# android-builder Native `linux/arm64` Android build toolchain for CI, published to the Gitea container registry at `git.helu.ca/r/android`. App repos consume this image to build signed release artifacts. Instrumented tests are **not** part of this toolchain — by design, CI builds are promotions of code already tested in Dev (on Apple silicon, where the emulator runs natively). The OCI Ampere (aarch64) runner has no `/dev/kvm` (the guest VM boots at EL1, so KVM can't access HYP/EL2), so there's no accelerated emulator here — and we don't need one. ## What's in the image - Eclipse Temurin JDK 21 (native arm64) - Android cmdline-tools, platform, and build-tools — **baked in**, so prod builds don't depend on Google's download endpoint at job time - `git`, `curl`, `unzip` Pinned versions live as `ARG`s at the top of the `Dockerfile`: | ARG | Default | Where to check | | ----------------------- | ----------- | -------------- | | `CMDLINE_TOOLS_VERSION` | `13114758` | https://developer.android.com/studio#command-line-tools-only | | `BUILD_TOOLS_VERSION` | `35.0.0` | SDK Manager / release notes | | `PLATFORM_VERSION` | `android-35`| your app's `compileSdk` | `aapt2` and the build-tools binaries ship native arm64 for 35.x, so packaging runs without emulation. ## Tagging model The whole point of owning this image is that **app repos pin a tag and a new toolchain never lands in a prod build by accident.** - **Immutable** — a git tag like `2026.06` produces `git.helu.ca/r/android:2026.06`. This is what app repos pin to. - **Moving** — pushes to `main` (and any tag build) refresh `git.helu.ca/r/android:latest` for convenience. Don't pin prod builds to this. ## Cutting a new toolchain 1. Update the `ARG` defaults in the `Dockerfile` if you're moving SDK/tool versions. Verify `CMDLINE_TOOLS_VERSION` against the link above — a stale number 404s the image build. 2. Commit to `main`. The workflow builds and pushes `:latest`; confirm it's green. 3. Tag the release with the year-month you want app repos to reference: ``` git tag 2026.06 git push origin 2026.06 ``` This publishes the immutable `git.helu.ca/r/android:2026.06`. 4. Roll app repos forward deliberately by bumping their pinned tag (see below) — one at a time if you want to validate, all at once if you trust the bump. ## Using it in an app repo Drop `.gitea/workflows/build.yml` (the template alongside this repo) into the app and pin the toolchain: ```yaml jobs: build: runs-on: [self-hosted, arm64] container: image: git.helu.ca/r/android:2026.06 credentials: username: ${{ gitea.actor }} password: ${{ secrets.GITEA_TOKEN }} ``` The build task is selectable: `assembleRelease` (APK, the default) or `bundleRelease` (AAB — only needed for Google Play distribution). ### Required secrets in each app repo (or org-level) Signing happens at job time; nothing sensitive lives in the repo or the image. | Secret | What it is | | ------------------- | ---------- | | `KEYSTORE_BASE64` | release keystore, base64-encoded: `base64 -w0 release.keystore` | | `KEYSTORE_PASSWORD` | keystore password | | `KEY_ALIAS` | signing key alias | | `KEY_PASSWORD` | key password | `GITEA_TOKEN` needs `write:package` here (to push) and `read:package` in app repos (to pull). The built-in token usually covers this; if your instance scopes it tightly, use a PAT. ## First-run sequencing The image must exist in the registry before any app workflow can pull it. So: cut and push `2026.06` from this repo first, confirm it's in the registry, *then* the app workflows that pin it will resolve.