F-Droid's official build scanner rejects the foojay-resolver-convention plugin because it can fetch a JDK over the network during the offline, reproducible build. The plugin was inert here (no toolchain block ever invoked it), so removing it leaves the app functionally identical to 2.7.3 and still reproducible byte-for-byte from source. Bumps versionName to 2.7.4 (the release trigger) and retargets the official fdroiddata recipe draft at v2.7.4, plus two recipe corrections the fdroiddata CI caught on the v2.7.3 submission (MR !40967): - Categories: 'Time' (retired in the current taxonomy) -> 'Calendar & Agenda' - AutoUpdateMode: 'Version v%v' (invalid per schema) -> 'Version' Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Official F-Droid submission (draft)
Goal: publish Calendula to the official F-Droid repo alongside the self-hosted repo, as one app — same signed binary in both channels, so existing self-hosted users migrate with no reinstall and no data loss.
This folder holds the draft fdroiddata recipe. Nothing here is submitted
yet. The self-hosted pipeline (../../fdroid-metadata/, .gitea/workflows/release.yaml)
is unaffected by these files.
Publishing model: reproducible build + developer-signed binary
F-Droid builds Calendula from source on its buildserver, then verifies the
output is byte-for-byte identical to our signed APK (fetched via the
Binaries URL). On a match it publishes our binary, signed with our
key — identified by AllowedAPKSigningKeys. Result: official and self-hosted
both carry the same signature. If a build ever fails to match, F-Droid simply
skips that version (fails safe — no bad publish).
Verification status (2026-06-21)
- ✅ Run-to-run reproducible —
v2.7.0built twice from a clean worktree (R8 minify + resource-shrink, build cache off) → byte-for-byte identical (sha256 568c944a…). - ✅ Cross-JDK reproducible — rebuilt with JDK 17 and JDK 21 → identical APK. JDK version is not a sensitivity, so it need not be pinned.
- ✅ Tag self-consistent — committed
versionCode/versionNamealready equal the tag-derived values, so F-Droid building the tag as-is matches the CI-published binary (CI'ssedsubstitution is a no-op). - ✅ App signing cert SHA-256 extracted from published APKs (identical
across v1.0.0 / v2.0.0 / v2.4.0):
5cdaee8e…. No keystore needed. - ✅ Eligibility — MIT, 100% FOSS deps (no Play Services / Firebase /
analytics / billing), no
INTERNETpermission, no native code. - ✅ End-to-end reproducible vs the DISTRIBUTED binary — built tag
v2.7.1from source and compared against the publishedcalendula_v2.7.1.apk: every app entry (dex / resources / assets / manifest) byte-identical. The only difference wasMETA-INF/version-control-info.textproto(AGP's git metadata, env-dependent). Fixed withvcsInfo { include = false }on the release build; re-validated → 0 non-signature differences. Takes effect from the first release built after that change — submit the recipe starting at that version (v2.7.1 and earlier still embed the textproto and won't verify). - ⚠️ Not yet proven: cross-host / fixed-build-path reproducibility on F-Droid's buildserver (low risk for a no-NDK pure-JVM app; with vcsInfo disabled, the env-dependent field is gone; F-Droid confirms at review).
- ✅ Buildserver toolchain supported (checked 2026-06-21):
- Gradle 9.5.1 is in F-Droid's gradle-transparency-log (
checksums.json) with a verified sha256, sogradlew.pywill download + verify + run it. - AGP 9.2 is in
gradlew.py'sMIN_GRADLE_VERSIONmap (9.2 -> 9.4.1). - JDK 17 is standard on the buildserver (AGP 9.2 requires exactly 17).
- build-tools 36.0.0 / android-37: not statically preinstalled (baseline
stops at 33), but
provision-android-sdkmakes$ANDROID_HOME/build-toolsand/platformsgroup-writable so AGP/Gradle install newer ones on demand.
- Gradle 9.5.1 is in F-Droid's gradle-transparency-log (
Before submitting — checklist
- Confirm the
BinariesURL is publicly reachable and stable long-term, e.g.https://apps.dev.jeanlucmakiola.de/dev/fdroid/repo/calendula_v2.7.0.apkresolves to the dev-signed APK. F-Droid re-fetches it on every build. - Confirm F-Droid's buildserver supports the toolchain (see timing risk).
- (Recommended) Reproduce one published release end-to-end: build the tag from
source, strip signatures, and diff against the downloaded
calendula_v<ver>.apkto confirm the from-source build matches the distributed binary — not just another local build.
Submission steps (fdroiddata, GitLab)
- Fork
https://gitlab.com/fdroid/fdroiddata. - Copy
de.jeanlucmakiola.calendula.ymltometadata/in the fork. - Test locally with
fdroid build -v de.jeanlucmakiola.calendulaandfdroid lint de.jeanlucmakiola.calendula(andfdroid readmeta). - Open a Merge Request. Initial review can take weeks to months; the self-hosted repo keeps serving in the meantime, so there's no rush.
Listing metadata (descriptions, screenshots, icon)
These are not in the recipe .yml. F-Droid's fdroid update harvests them
automatically from the fastlane tree in the app's source repo:
fastlane/metadata/android/<locale>/
short_description.txt full_description.txt title.txt
images/icon.png images/phoneScreenshots/*.png
changelogs/<versionCode>.txt (optional, per release)
This is the single source of truth: en-US + de-DE already exist there, and the
self-hosted repo is generated from the same tree at release time via
scripts/fastlane_to_fdroid_localized.sh. Nothing extra to add to fdroiddata —
F-Droid picks the listing up from source. (Screenshots may not be committed to
the fdroiddata repo anyway, so the source-tree fastlane layout is required.)
Per-version changelogs: the self-hosted release workflow generates
changelogs/<versionCode>.txt at release time. For the official repo to show a
changelog, that file must be committed into fastlane/metadata/android/<locale>/changelogs/
at the tagged commit — wire this into the release/version-bump step, or accept
no in-client changelog for the official listing initially.