diff --git a/.gitea/workflows/builder-image.yml b/.gitea/workflows/builder-image.yml index d72a3d7..ef29570 100644 --- a/.gitea/workflows/builder-image.yml +++ b/.gitea/workflows/builder-image.yml @@ -15,7 +15,9 @@ env: jobs: build-image: - runs-on: ubuntu-24.04-arm64 + # amd64: Google ships the Linux build-tools (aapt2, d8) for x86_64 only, + # so the toolchain must be built for and run on amd64. + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4 @@ -43,12 +45,12 @@ jobs: - name: Set up Buildx uses: docker/setup-buildx-action@v3 - - name: Build and push (linux/arm64) + - name: Build and push (linux/amd64) uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile - platforms: linux/arm64 + platforms: linux/amd64 push: true tags: ${{ steps.tags.outputs.tags }} # Bump these here if you want to override the Dockerfile defaults diff --git a/Dockerfile b/Dockerfile index bfa0a69..4c81adf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,9 @@ -# Native linux/arm64 Android build toolchain for CI. +# Native linux/amd64 Android build toolchain for CI. # Builds release artifacts only — no emulator, no test/system images. -# eclipse-temurin publishes a native linux/arm64 manifest, so this runs -# without emulation on an OCI Ampere (aarch64) runner. +# Must be amd64: Google publishes the Linux build-tools (aapt2, d8, …) for +# x86_64 only — there is no arm64 Linux build-tools package — so packaging +# cannot run natively on an aarch64 runner. The APK output is architecture- +# neutral regardless of the build host. FROM eclipse-temurin:21-jdk-noble # --- Version pins (bump deliberately; this is what your app repos trust) --- @@ -40,9 +42,8 @@ RUN mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools && \ ENV PATH=${PATH}:${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin:${ANDROID_SDK_ROOT}/platform-tools # Accept licenses and bake the SDK packages into the image so prod builds -# don't depend on Google's endpoint at job time. -# aapt2 and the build-tools binaries ship native arm64 for 35.x, so APK/AAB -# packaging runs natively on aarch64. +# don't depend on Google's endpoint at job time. The build-tools binaries +# (aapt2, d8) are x86_64 ELF — this is why the image must be amd64. RUN yes | sdkmanager --licenses >/dev/null && \ sdkmanager --install \ "platform-tools" \ @@ -51,7 +52,10 @@ RUN yes | sdkmanager --licenses >/dev/null && \ rm -rf ${ANDROID_SDK_ROOT}/.android # Sanity: fail the image build if the toolchain isn't actually usable. +# Execute aapt2 (not just --version a tool) so an arch mismatch in the +# build-tools binaries fails the image build here, not in every app build. RUN java -version && sdkmanager --version && node --version && \ + "${ANDROID_SDK_ROOT}/build-tools/${BUILD_TOOLS_VERSION}/aapt2" version && \ test -d "${ANDROID_SDK_ROOT}/platforms/${PLATFORM_VERSION}" WORKDIR /workspace \ No newline at end of file diff --git a/README.md b/README.md index 29e1af2..316f3a8 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,23 @@ # android-builder -Native `linux/arm64` Android build toolchain for CI, published to the Gitea +Native `linux/amd64` 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. +natively). + +**Why amd64:** Google publishes the Linux Android build-tools (`aapt2`, `d8`, +…) for **x86_64 only** — there is no arm64 Linux build-tools package. Running +the toolchain on an aarch64 runner fails at resource packaging +(`aapt2: Syntax error: newline unexpected`, an x86_64 binary the kernel can't +exec). The produced APK/AAB is architecture-neutral regardless of build host, +so building on amd64 costs nothing on the output side. ## What's in the image -- Eclipse Temurin JDK 21 (native arm64) +- Eclipse Temurin JDK 21 (native amd64) - 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` @@ -27,8 +32,8 @@ Pinned versions live as `ARG`s at the top of the `Dockerfile`: | `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. +The build-tools binaries (`aapt2`, `d8`) are x86_64 ELF — this is why the +image is amd64 (see "Why amd64" above). ## Tagging model @@ -63,7 +68,7 @@ app and pin the toolchain: ```yaml jobs: build: - runs-on: ubuntu-24.04-arm64 + runs-on: ubuntu-24.04 container: image: git.helu.ca/r/android:2026.06 credentials: diff --git a/templates/build.yml b/templates/build.yml index 5d9a208..052c122 100644 --- a/templates/build.yml +++ b/templates/build.yml @@ -24,7 +24,9 @@ env: jobs: build: - runs-on: ubuntu-24.04-arm64 + # amd64: the toolchain image carries x86_64 Android build-tools (Google + # ships no arm64 Linux build-tools), so run it on an amd64 runner. + runs-on: ubuntu-24.04 container: image: git.helu.ca/r/android:2026.06 credentials: