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 ARGs 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 36.0.0 SDK Manager / release notes
PLATFORM_VERSION android-36 your app's compileSdk

aapt2 and the build-tools binaries ship native arm64 for 36.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:

jobs:
  build:
    runs-on: ubuntu-24.04-arm64
    container:
      image: git.helu.ca/r/android:2026.06
      credentials:
        username: ${{ gitea.actor }}
        password: ${{ secrets.PACKAGE_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

PACKAGE_TOKEN (a PAT, the same secret the other repos here use) needs write:package in this repo (to push the image) and read:package in app repos (to pull it). Set it as a repo or org-level Actions secret. The built-in gitea.token is not used because it isn't scoped for the registry.

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.

Description
Android build
Readme MIT 46 KiB
Languages
Dockerfile 100%