How it works
Signal is distributed as an Android App Bundle. The Play Store uses the bundle to generate a set of device-specific APKs that include only the resources needed for a given device. Reproducing the build and comparing those APKs to what is installed on a device is the core of the verification process. The build environment is captured as a Docker image. Because the image pins all build tool versions, Java version, NDK, and SDK components, anyone who builds the image from the sameDockerfile gets a bit-for-bit identical compiler toolchain. Combined with Signal’s deterministic build configuration, the compiled output is reproducible.
The Dockerfile
TheDockerfile in reproducible-builds/ is the authoritative description of the build environment:
- Base image: Ubuntu Jammy, pinned by digest
- JDK: OpenJDK 17
- Android SDK: API level 36, build-tools 35.0.0
- NDK: 28.0.13004108
- CMake: 3.22.1
Prerequisites
Before you start, install the following tools:gitdockerpython(3.x)uv(Python package manager)adb— Android Debug Bridgebundletool— bundletool releases
Step-by-step verification
1
Set up directories
Create a working directory to hold the APKs you will compare:
2
Check your Signal version
In the Signal app go to Settings → Help and note the version number, for example
7.7.0. All subsequent commands use this version.3
Clone the exact version
Tags follow the pattern
v<version>:4
Build the Docker image
5
Build the app bundle
Run the Gradle build inside the container. The container mounts the repository root and runs as your local user to avoid permission issues:The output bundle is at
app/build/outputs/bundle/playProdRelease/Signal-Android-play-prod-release.aab.6
Generate device-specific APKs from the bundle
With your device connected, use Move the split APKs up one level and discard the bundle:
bundletool to generate the APKs that match your device:7
Pull the APKs from your device
apks-from-device/ directory containing base.apk and one or more split_config.*.apk files.8
Compare the APKs
Install the Then compare each pair (adjust ABI and density names to match your device):Each successful comparison ends with
apkdiff dependencies and run the comparison:APKs match!.Verifying the website APK
For users without Play Store access, Signal provides a universal APK at signal.org/android/apk. The website build is a single larger APK rather than an app bundle, which simplifies comparison to one pair of APKs. Build withassembleWebsiteProdRelease instead:
app/build/outputs/apk/websiteProdRelease/. Compare that APK directly to the one downloaded from the website (or pulled from the device).
The reproducible-builds/ directory
apkdiff.py knows how to compare APK internals correctly: APKs are zip archives, so a naive byte-for-byte diff would fail due to zip metadata differences. The script unpacks both APKs, skips files that are intentionally different between Play Store and self-built versions (signing information, stamp-cert-sha256), and compares the remaining entries.
Troubleshooting
APKs don't match
APKs don't match
- Verify you checked out the exact git tag matching the version on your device.
- Confirm you are comparing the right pairs: base-to-base, ABI-to-ABI, density-to-density.
- Rebuild the Docker image from scratch (
docker build --no-cache) — the Dockerfile may have changed between versions. - Check open issues in case a known mismatch is being tracked.
Build fails inside Docker
Build fails inside Docker
- Ensure Docker has sufficient memory (at least 4 GB recommended).
- Make sure the repo was cloned cleanly at the exact tag — a dirty working tree can affect build outputs.
- Check that the
--userflag matches your local UID/GID to avoid permission issues with Gradle caches.
bundletool reports unsupported signature scheme
bundletool reports unsupported signature scheme
Google’s public
bundletool release does not yet support v3.1 APK signature schemes. You may need to build bundletool from source. Track progress on bundletool issue #369.Code Transparency (extra credit)
In addition to the full reproducible build check, you can run a faster Code Transparency verification. This checks that the APK on your device was signed with Signal’s transparency key after being submitted to the Play Store:Code Transparency is a weaker check than the full reproducible build process. It verifies the APK was not modified after Signal submitted it, but it does not verify that the submitted code matches the public git repository. The full reproducible build process covers both.
