build: support unsigned release builds for F-Droid - #371
Open
garfiec wants to merge 3 commits into
Open
Conversation
Without credentials, `assembleRelease` fell through to the committed debug key and emitted an `app-release.apk` that looks signed. Packagers that apply their own signature need no signature at all, and the failure was silent. `-PunsignedRelease` drops the signing config so AGP emits `app-release-unsigned.apk`. It outranks credentials on purpose, so the path is testable without moving `keystore.properties` aside, and the differing filename means the two builds cannot be confused. The release workflow now asserts the shipped APK carries the published certificate — a swapped keystore secret was otherwise undetectable, and a key change strands every existing install — and re-verifies the unsigned path, which nothing else exercises.
BuildConfig.GIT_SHA is stamped from `git rev-parse HEAD` at build time, but the workflow built the APK before committing the version bump and tagging. The published v2026.08.4 APK therefore carries fcbaf61 in its dex — the parent of tag v2026.08.4 (c09ec96). Anyone rebuilding from the tag gets a different string and can never match the release byte-for-byte, which rules out F-Droid publishing our developer-signed APK instead of re-signing it. Commit and tag locally before the build, and push only once every check has passed. A failed build still leaves nothing behind: the commit and tag are local to the runner.
F-Droid's update detection is regex-only and cannot evaluate our packing, so a versionCode derived inside the Gradle plugin is invisible to it — every release would need a hand-filed metadata merge request. Spell the code out in version.properties, write it from bump-version.sh, and have the plugin keep re-deriving it and fail the build when the two disagree, so the literal is a cross-check rather than a second source of truth. Add fastlane/metadata/android/en-US/, the listing layout F-Droid and IzzyOnDroid both read: descriptions, a changelog keyed by versionCode, and phone/tablet screenshots.
Contributor
Android debug APKArtifact:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
F-Droid builds from source on its own infrastructure and needs an APK with no signature, which this repo could not produce — a credential-less
assembleReleasefell through to the committed debug key and emitted anapp-release.apkthat looked signed. This adds that build mode, removes a defect that made a published release impossible to rebuild from its own tag, and adds the store-listing metadata F-Droid and IzzyOnDroid read.Changes
Build
-PunsignedReleasedrops the release signing config, so AGP emitsapp-release-unsigned.apk. It is read throughproviders.gradlePropertyto stay a tracked configuration-cache input, and outranks credentials on purpose so the path is testable without movingkeystore.propertiesaside.gradleprops.Release workflow
BuildConfig.GIT_SHAis stamped fromgit rev-parse HEAD, so building first shipped an APK carrying the SHA of the commit preceding its own tag. A failed run pushes no commit, tag or release.-PunsignedReleaseand asserts the result is genuinely unsigned. This runs at release cuts rather than in ordinary CI: it is the only time the unsigned build matters, and that job already pays for one R8 run.Versioning
version.propertiesspells outversionCodealongsideversionName.bump-version.shwrites it and refuses a bump if the line is missing; the plugin still derives the code and fails the build if the literal disagrees. F-Droid's update detection is regex-only and cannot evaluate the packing.Store metadata
fastlane/metadata/android/en-US/— descriptions, a changelog keyed by versionCode, and phone/tablet screenshots, with afastlane/README.mdcovering the naming rules.Release process
docs/RELEASING.mddocuments the unsigned build, the tag-before-build ordering and the certificate assertion, and gains one new manual step: a changelog file must be committed before dispatching a release, because F-Droid reads it from the tagged commit and the release commit touches onlyversion.properties.Verification
detekt,detektMetadataCommonMain,test,:app:assembleDebugandvendor-web-assets.py --checkpass.assembleReleasewas run with and without the flag, confirming the output filename andapksigner verifyresult in each case, and Gradle was confirmed to invalidate the configuration cache citingunsignedRelease. Both new workflow guards were executed against real APKs, and the expected certificate was checked against the fingerprint inREADME.md. Every feature and privacy claim in the store listing was checked against the source.Not device-tested. The workflow changes are unexercised until the next release cut.
Notes
fdroidserveris the remaining gate before an RFP, since the developer-signed model has no fallback.