build(release): build the release APK for ARM only (arm64-v8a + armeabi-v7a) #230

Merged
JMR-dev merged 2 commits from build-release-arm-only into main 2026-07-03 16:27:36 +00:00
JMR-dev commented 2026-07-03 15:58:07 +00:00 (Migrated from github.com)

Summary

  • Adds ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") } to the release build type only in app/build.gradle.kts. The release build previously produced a universal APK with all four ABIs; it now ships ARM only — arm64-v8a (64-bit) + armeabi-v7a (32-bit). x86 and x86_64 are intentionally dropped (maintainer decision).
  • defaultConfig and the debug build type are untouched on purpose: CI's E2E matrix (.github/workflows/ci.yml) runs connectedDebugAndroidTest / Gradle Managed Devices on x86_64 emulators, which need the x86_64 native libs (incl. libsqlcipher.so). An ARM-only filter on debug/defaultConfig would crash those emulator tests with UnsatisfiedLinkError.

Scope / blast radius — please read

.github/workflows/release.yml:237-238 builds ./gradlew :app:bundleRelease :app:assembleRelease — both use the release build type, so this filter affects both the Play AAB and the standalone APK. After this change, the AAB uploaded to Google Play and the GitHub-release APK both ship arm64-v8a + armeabi-v7a only: 32-bit and 64-bit ARM devices are covered; x86 and x86_64 are intentionally dropped.

If ARM-only is only intended for the standalone release APK and the Play AAB should keep serving x86/x86_64 too (e.g. for Chromebooks / x86 tablets via Play's per-device delivery), this filter should instead be scoped to the assembleRelease task specifically rather than the whole release build type. As implemented here, per the maintainer's request, both artifacts are ARM-only.

Docs to revisit — flagging, not resolving

  • docs/play-compliance.md §2 (16 KB page-size support) was verified against an AAB containing all four ABIs (its table lists arm64-v8a, x86_64, armeabi-v7a, and x86 alignment results). After this change the AAB only contains the two ARM ABIs, so that section's 4-ABI premise is stale, and x86/x86_64 Play devices (Chromebooks, x86 tablets/emulators) would get no installable APK from Play. The two ARM ABIs the AAB still ships are both confirmed 16 KB-aligned in that same table, so the page-size compliance conclusion itself still holds for what ships. Worth a doc update if ARM-only is intended for Play.
  • docs/fdroid-compliance.md doesn't mandate a specific ABI set, and docs/fdroid/org.libremail.app.yml builds via plain gradle: - yes, which invokes this same release build type — so F-Droid's published build also becomes ARM-only. F-Droid's user base skews toward ARM hardware (incl. older 32-bit armeabi-v7a, which this change keeps), so dropping x86/x86_64 there is low-impact and not an anti-feature/policy blocker (F-Droid has no ABI-universality requirement).

Net coverage after this change: ARM 32-bit (armeabi-v7a) + ARM 64-bit (arm64-v8a) covered; x86 + x86_64 intentionally dropped.

Verification

Built with JDK 21 (C:\Program Files\Eclipse Adoptium\jdk-21.0.11.10-hotspot; AGP 9.2 does not support JDK 25+).

1. Release is ARM-only (arm64-v8a + armeabi-v7a) — ./gradlew :app:assembleRelease, then listed .so entries in app-release.apk:

    10096  1981-01-01 01:01   lib/arm64-v8a/libandroidx.graphics.path.so
    10360  1981-01-01 01:01   lib/arm64-v8a/libdatastore_shared_counter.so
  2084360  1981-01-01 01:01   lib/arm64-v8a/libsqlcipher.so
     7252  1981-01-01 01:01   lib/armeabi-v7a/libandroidx.graphics.path.so
     8432  1981-01-01 01:01   lib/armeabi-v7a/libdatastore_shared_counter.so
  1039684  1981-01-01 01:01   lib/armeabi-v7a/libsqlcipher.so

Exactly lib/arm64-v8a/ + lib/armeabi-v7a/ — confirmed no x86/x86_64.

2. Debug still has all four ABIs — ./gradlew :app:assembleDebug, then listed .so entries in app-debug.apk:

    10096  1981-01-01 01:01   lib/arm64-v8a/libandroidx.graphics.path.so
    10360  1981-01-01 01:01   lib/arm64-v8a/libdatastore_shared_counter.so
  2084360  1981-01-01 01:01   lib/arm64-v8a/libsqlcipher.so
     7252  1981-01-01 01:01   lib/armeabi-v7a/libandroidx.graphics.path.so
     8432  1981-01-01 01:01   lib/armeabi-v7a/libdatastore_shared_counter.so
  1039684  1981-01-01 01:01   lib/armeabi-v7a/libsqlcipher.so
     9284  1981-01-01 01:01   lib/x86/libandroidx.graphics.path.so
     7976  1981-01-01 01:01   lib/x86/libdatastore_shared_counter.so
  2227284  1981-01-01 01:01   lib/x86/libsqlcipher.so
    10760  1981-01-01 01:01   lib/x86_64/libandroidx.graphics.path.so
     9424  1981-01-01 01:01   lib/x86_64/libdatastore_shared_counter.so
  2217240  1981-01-01 01:01   lib/x86_64/libsqlcipher.so

x86_64 is present — the CI emulator ABI is unaffected.

3. Fast gate: :app:testDebugUnitTest :app:compileDebugAndroidTestKotlin :app:lintDebug :app:ktlintCheck :app:detekt — all BUILD SUCCESSFUL.

Test plan

  • ./gradlew :app:assembleRelease — release APK contains only lib/{arm64-v8a,armeabi-v7a}/*.so
  • ./gradlew :app:assembleDebug — debug APK still contains lib/{arm64-v8a,armeabi-v7a,x86,x86_64}/*.so
  • ./gradlew :app:testDebugUnitTest :app:compileDebugAndroidTestKotlin :app:lintDebug :app:ktlintCheck :app:detekt
  • CI emulator E2E matrix (left to CI; debug ABI coverage confirmed unaffected above)
  • Maintainer decision: is ARM-only intended for the Play AAB too, or should the AAB keep x86/x86_64 for Chromebooks / x86 devices (see Scope section above)?

Supersedes #228 (that PR filtered to arm64-v8a only; this one keeps 32-bit ARM as well).

🤖 Generated with Claude Code

## Summary - Adds `ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") }` to the **release** build type only in `app/build.gradle.kts`. The release build previously produced a universal APK with all four ABIs; it now ships **ARM only — arm64-v8a (64-bit) + armeabi-v7a (32-bit)**. x86 and x86_64 are intentionally dropped (maintainer decision). - `defaultConfig` and the **debug** build type are untouched on purpose: CI's E2E matrix (`.github/workflows/ci.yml`) runs `connectedDebugAndroidTest` / Gradle Managed Devices on **x86_64 emulators**, which need the x86_64 native libs (incl. `libsqlcipher.so`). An ARM-only filter on debug/defaultConfig would crash those emulator tests with `UnsatisfiedLinkError`. ## Scope / blast radius — please read `.github/workflows/release.yml:237-238` builds `./gradlew :app:bundleRelease :app:assembleRelease` — both use the `release` build type, so **this filter affects both the Play AAB and the standalone APK**. After this change, the AAB uploaded to Google Play and the GitHub-release APK both ship **arm64-v8a + armeabi-v7a only**: 32-bit and 64-bit ARM devices are covered; **x86 and x86_64 are intentionally dropped**. If ARM-only is only intended for the standalone release APK and the Play AAB should keep serving x86/x86_64 too (e.g. for Chromebooks / x86 tablets via Play's per-device delivery), this filter should instead be scoped to the `assembleRelease` task specifically rather than the whole `release` build type. As implemented here, per the maintainer's request, **both artifacts are ARM-only.** ### Docs to revisit — flagging, not resolving - **`docs/play-compliance.md` §2 (16 KB page-size support)** was verified against an AAB containing all four ABIs (its table lists arm64-v8a, x86_64, armeabi-v7a, and x86 alignment results). After this change the AAB only contains the two ARM ABIs, so that section's 4-ABI premise is stale, and **x86/x86_64 Play devices (Chromebooks, x86 tablets/emulators) would get no installable APK** from Play. The two ARM ABIs the AAB still ships are both confirmed 16 KB-aligned in that same table, so the page-size compliance conclusion itself still holds for what ships. Worth a doc update if ARM-only is intended for Play. - **`docs/fdroid-compliance.md`** doesn't mandate a specific ABI set, and `docs/fdroid/org.libremail.app.yml` builds via plain `gradle: - yes`, which invokes this same `release` build type — so F-Droid's published build also becomes ARM-only. F-Droid's user base skews toward ARM hardware (incl. older 32-bit armeabi-v7a, which this change **keeps**), so dropping x86/x86_64 there is low-impact and not an anti-feature/policy blocker (F-Droid has no ABI-universality requirement). **Net coverage after this change:** ARM 32-bit (armeabi-v7a) + ARM 64-bit (arm64-v8a) covered; x86 + x86_64 intentionally dropped. ## Verification Built with JDK 21 (`C:\Program Files\Eclipse Adoptium\jdk-21.0.11.10-hotspot`; AGP 9.2 does not support JDK 25+). **1. Release is ARM-only (arm64-v8a + armeabi-v7a)** — `./gradlew :app:assembleRelease`, then listed `.so` entries in `app-release.apk`: ``` 10096 1981-01-01 01:01 lib/arm64-v8a/libandroidx.graphics.path.so 10360 1981-01-01 01:01 lib/arm64-v8a/libdatastore_shared_counter.so 2084360 1981-01-01 01:01 lib/arm64-v8a/libsqlcipher.so 7252 1981-01-01 01:01 lib/armeabi-v7a/libandroidx.graphics.path.so 8432 1981-01-01 01:01 lib/armeabi-v7a/libdatastore_shared_counter.so 1039684 1981-01-01 01:01 lib/armeabi-v7a/libsqlcipher.so ``` Exactly `lib/arm64-v8a/` + `lib/armeabi-v7a/` — confirmed no x86/x86_64. **2. Debug still has all four ABIs** — `./gradlew :app:assembleDebug`, then listed `.so` entries in `app-debug.apk`: ``` 10096 1981-01-01 01:01 lib/arm64-v8a/libandroidx.graphics.path.so 10360 1981-01-01 01:01 lib/arm64-v8a/libdatastore_shared_counter.so 2084360 1981-01-01 01:01 lib/arm64-v8a/libsqlcipher.so 7252 1981-01-01 01:01 lib/armeabi-v7a/libandroidx.graphics.path.so 8432 1981-01-01 01:01 lib/armeabi-v7a/libdatastore_shared_counter.so 1039684 1981-01-01 01:01 lib/armeabi-v7a/libsqlcipher.so 9284 1981-01-01 01:01 lib/x86/libandroidx.graphics.path.so 7976 1981-01-01 01:01 lib/x86/libdatastore_shared_counter.so 2227284 1981-01-01 01:01 lib/x86/libsqlcipher.so 10760 1981-01-01 01:01 lib/x86_64/libandroidx.graphics.path.so 9424 1981-01-01 01:01 lib/x86_64/libdatastore_shared_counter.so 2217240 1981-01-01 01:01 lib/x86_64/libsqlcipher.so ``` `x86_64` is present — the CI emulator ABI is unaffected. **3. Fast gate:** `:app:testDebugUnitTest :app:compileDebugAndroidTestKotlin :app:lintDebug :app:ktlintCheck :app:detekt` — all `BUILD SUCCESSFUL`. ## Test plan - [x] `./gradlew :app:assembleRelease` — release APK contains only `lib/{arm64-v8a,armeabi-v7a}/*.so` - [x] `./gradlew :app:assembleDebug` — debug APK still contains `lib/{arm64-v8a,armeabi-v7a,x86,x86_64}/*.so` - [x] `./gradlew :app:testDebugUnitTest :app:compileDebugAndroidTestKotlin :app:lintDebug :app:ktlintCheck :app:detekt` - [ ] CI emulator E2E matrix (left to CI; debug ABI coverage confirmed unaffected above) - [ ] Maintainer decision: is ARM-only intended for the **Play AAB** too, or should the AAB keep x86/x86_64 for Chromebooks / x86 devices (see Scope section above)? Supersedes #228 (that PR filtered to arm64-v8a only; this one keeps 32-bit ARM as well). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.