This document explains how to build P.CASH Wallet for F-Droid with reproducible builds enabled.
F-Droid requires reproducible builds to verify that the published APK matches the source code. The main challenge is that baseline profiles (assets/dexopt/baseline.prof) are non-deterministic and differ between builds.
Solution: Pass -Pfdroid=true gradle property to disable baseline profile generation.
| Build Type | Baseline Profiles | Flag |
|---|---|---|
| Play Store | Enabled (better startup performance) | None |
| F-Droid | Disabled (reproducible) | -Pfdroid=true |
The F-Droid build metadata is maintained in the fdroiddata repository.
File: metadata/cash.p.terminal.yml
Builds:
- versionName: 0.51.4
versionCode: 207
commit: 0.51.4
subdir: app
submodules: true
gradle:
- yes
gradleProps:
- fdroid=trueBuilds:
- versionName: 0.51.4
versionCode: 207
commit: 0.51.4
subdir: app
submodules: true
build: ../gradlew assembleRelease -Pfdroid=trueThe docker scripts in this repository automatically pass -Pfdroid=true:
# Navigate to docker folder
cd docker
# Build APK
./build-apk.sh [VERSION_TAG] [KEYSTORE_PATH] [KEYSTORE_PASSWORD]
# Example
./build-apk.sh 0.51.4 ~/keys/release.keystore mypassword
# Verify reproducibility against downloaded APK
./test.sh /path/to/downloaded.apkReplicates F-Droid's exact build environment:
# Clone repository at specific version
git clone --branch 0.51.4 --depth 1 https://github.com/piratecash/pcash-wallet-android
cd pcash-wallet-android
# Build using F-Droid's buildserver image
docker run --rm \
-v "$PWD":/repo \
-w /repo \
registry.gitlab.com/fdroid/fdroidserver:buildserver \
bash -c './gradlew clean :app:assembleRelease -Pfdroid=true'
# APK output location
ls -la app/build/outputs/apk/release/# Clone and checkout version
git clone https://github.com/piratecash/pcash-wallet-android
cd pcash-wallet-android
git checkout 0.51.4
# Build with F-Droid flag
./gradlew clean :app:assembleRelease -Pfdroid=true
# APK output
ls -la app/build/outputs/apk/release/# Check APK contents
unzip -l app/build/outputs/apk/release/*.apk | grep baseline
# Expected results:
# With -Pfdroid=true → No output (disabled)
# Without flag → Shows assets/dexopt/baseline.profUsing the test script:
cd docker
./test.sh /path/to/fdroid-downloaded.apkManual comparison with apktool:
# Extract both APKs
apktool d -o /tmp/local-build local-build.apk
apktool d -o /tmp/fdroid-build fdroid-build.apk
# Compare
diff -r /tmp/local-build /tmp/fdroid-build
# Visual comparison (requires meld)
meld /tmp/local-build /tmp/fdroid-buildExpected: No differences, or only signature-related differences.
| Issue | Cause | Solution |
|---|---|---|
baseline.prof in diff |
Flag not passed | Add -Pfdroid=true to gradle command |
classes*.dex differs |
Baseline profile included | Verify -Pfdroid=true is set |
| Resource ordering differs | Non-deterministic processing | Use F-Droid's docker image |
| JDK version mismatch | Different Java versions | Match F-Droid's JDK (currently 21) |
| Gradle version mismatch | Wrapper not used | Always use ./gradlew |
The app/build.gradle contains:
// Disable baseline profile generation for F-Droid reproducible builds
// https://f-droid.org/docs/Reproducible_Builds/
// F-Droid builds should pass -Pfdroid=true to disable baseline profiles
if (project.hasProperty('fdroid')) {
tasks.whenTaskAdded { task ->
if (task.name.contains("ArtProfile")) {
task.enabled = false
}
}
}When -Pfdroid=true is passed, all tasks containing "ArtProfile" in their name are disabled, preventing baseline profile generation.
- F-Droid Reproducible Builds
- fdroiddata Repository
- F-Droid Build Metadata Reference
- WalletScrutiny - Wallet verification service