build(release): build the release APK for arm64-v8a only #228

Closed
JMR-dev wants to merge 1 commits from build-release-arm64-only into main
JMR-dev commented 2026-07-03 15:47:10 +00:00 (Migrated from github.com)

Summary

  • Adds ndk { abiFilters += "arm64-v8a" } to the release build type only in app/build.gradle.kts. The release build previously produced a universal APK with all four ABIs (arm64-v8a, armeabi-v7a, x86, x86_64); it now ships arm64-v8a only.
  • 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 arm64-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 only, dropping armeabi-v7a (32-bit ARM), x86, and x86_64 device coverage.

If arm64-only is only intended for the standalone release APK and the Play AAB should keep serving all four ABIs (so Play's per-device delivery can still reach 32-bit-ARM/x86 devices), this filter should instead be scoped to the assembleRelease task specifically (e.g. via a variantFilter/per-task splits config, or restricting ndk.abiFilters through a task-specific mechanism) rather than the whole release build type. As implemented here, per the task spec, both artifacts are arm64-v8a only.

Conflicts found in docs — flagging, not resolving

  • docs/play-compliance.md §2 (16 KB page-size support) was verified against an AAB containing all four ABIs (its table explicitly lists arm64-v8a, x86_64, armeabi-v7a, and x86 alignment results for all three bundled native libs). After this change the AAB only contains arm64-v8a, so that section's premise ("the release AAB packages exactly three native libraries" across 4 ABIs) is now stale and devices needing armeabi-v7a/x86/x86_64 builds from Play would get no installable APK at all (Play cannot serve a device an ABI that isn't in the bundle). This doc should be revisited if arm64-only is intentional for Play.
  • docs/fdroid-compliance.md doesn't mandate a specific ABI set, but docs/fdroid/org.libremail.app.yml builds via plain gradle: - yes, which invokes this same release build type — so F-Droid's published build would also become arm64-v8a only. F-Droid's user base skews toward older/budget hardware, some of which is still 32-bit-ARM (armeabi-v7a) only; this is worth a maintainer call, not an anti-feature/policy blocker (F-Droid has no ABI-universality requirement in its inclusion criteria).

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 arm64-only — ./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

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

2. Debug still has all 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/*.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 arm64-v8a-only intended for the Play AAB too, or should the AAB keep all four ABIs (see Scope section above)?

🤖 Generated with Claude Code

## Summary - Adds `ndk { abiFilters += "arm64-v8a" }` to the **release** build type only in `app/build.gradle.kts`. The release build previously produced a universal APK with all four ABIs (arm64-v8a, armeabi-v7a, x86, x86_64); it now ships arm64-v8a only. - `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 arm64-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 only**, dropping armeabi-v7a (32-bit ARM), x86, and x86_64 device coverage. If arm64-only is only intended for the standalone release APK and the Play AAB should keep serving all four ABIs (so Play's per-device delivery can still reach 32-bit-ARM/x86 devices), this filter should instead be scoped to the `assembleRelease` task specifically (e.g. via a `variantFilter`/per-task `splits` config, or restricting `ndk.abiFilters` through a task-specific mechanism) rather than the whole `release` build type. As implemented here, per the task spec, **both artifacts are arm64-v8a only.** ### Conflicts found in docs — flagging, not resolving - **`docs/play-compliance.md` §2 (16 KB page-size support)** was verified against an AAB containing all four ABIs (its table explicitly lists arm64-v8a, x86_64, armeabi-v7a, and x86 alignment results for all three bundled native libs). After this change the AAB only contains arm64-v8a, so that section's premise ("the release AAB packages exactly three native libraries" across 4 ABIs) is now stale and devices needing armeabi-v7a/x86/x86_64 builds from Play would get **no installable APK at all** (Play cannot serve a device an ABI that isn't in the bundle). This doc should be revisited if arm64-only is intentional for Play. - **`docs/fdroid-compliance.md`** doesn't mandate a specific ABI set, but `docs/fdroid/org.libremail.app.yml` builds via plain `gradle: - yes`, which invokes this same `release` build type — so F-Droid's published build would also become arm64-v8a only. F-Droid's user base skews toward older/budget hardware, some of which is still 32-bit-ARM (armeabi-v7a) only; this is worth a maintainer call, not an anti-feature/policy blocker (F-Droid has no ABI-universality requirement in its inclusion criteria). ## 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 arm64-only** — `./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 ``` Only `lib/arm64-v8a/` — confirmed no armeabi-v7a/x86/x86_64. **2. Debug still has all 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/*.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 arm64-v8a-only intended for the **Play AAB** too, or should the AAB keep all four ABIs (see Scope section above)? 🤖 Generated with [Claude Code](https://claude.com/claude-code)
JMR-dev commented 2026-07-03 15:58:56 +00:00 (Migrated from github.com)

Superseded by #230, which keeps 32-bit ARM (armeabi-v7a) alongside arm64-v8a per maintainer request (release is now ARM-only: arm64-v8a + armeabi-v7a, x86/x86_64 intentionally dropped). Closing this arm64-v8a-only PR in favor of #230.

Superseded by #230, which keeps 32-bit ARM (armeabi-v7a) alongside arm64-v8a per maintainer request (release is now ARM-only: arm64-v8a + armeabi-v7a, x86/x86_64 intentionally dropped). Closing this arm64-v8a-only PR in favor of #230.

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.