Skip to content

fix(build): only package requested --arch ABIs in Android APK/AAB#6578

Open
ndonkoHenri wants to merge 14 commits into
flet-0.86from
fix-android-arch-filtering
Open

fix(build): only package requested --arch ABIs in Android APK/AAB#6578
ndonkoHenri wants to merge 14 commits into
flet-0.86from
fix-android-arch-filtering

Conversation

@ndonkoHenri

@ndonkoHenri ndonkoHenri commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

flet build apk --arch arm64-v8a produced an APK that still contained lib/armeabi-v7a and lib/x86_64 — including a full Python distribution per ABI (~20 MB each).

Fixes #6567

Root cause

The build template has mapped --archdefaultConfig.ndk.abiFilters since 0.85.0 (#6331), but that filter is silently defeated:

  1. The Flutter Gradle plugin programmatically sets buildType.ndk.abiFilters to all default ABIs (armeabi-v7a, arm64-v8a, x86_64) whenever split-per-abi is off (FlutterPlugin.kt, using DEFAULT_PLATFORMS — not the requested --target-platform).
  2. AGP merges defaultConfig-level and buildType-level abiFilters as a set union (MergedNdkConfig.appendabiFilters.addAll), so {arm64-v8a} ∪ {all 3} = all 3.

Changes

  • Gradle packaging excludes (the actual fix): the generated app/build.gradle.kts now adds packaging.jniLibs.excludes for unrequested ABI directories. Exclusion happens in AGP's MergeNativeLibsTask — upstream of both APK and AAB packaging — and filters native libs from all sources, including library-module/AAR dependencies like serious_python_android.
  • Forward --arch to Flutter as --target-platform: engine/AOT artifacts are only built for the requested ABIs, and --split-per-abi now produces only the requested split APK(s). --split-per-abi is not auto-enabled — output shape is unchanged unless explicitly requested.
  • Validate --arch values for Android (arm64-v8a, armeabi-v7a, x86_64) with a clear CLI error. Previously x86 (accepted by serious_python, dropped by Flutter) or macOS-style values (arm64) produced opaque Gradle failures or APKs with no site-packages that crashed at runtime.
  • Fix multi-value --arch: values were passed to serious_python space-separated, but Dart's args parser only accepts multi-options comma-separated/repeated — every value after the first was silently dropped, so multi-arch builds shipped libpythonsitepackages.so only for the first ABI.
  • Clear stale build outputs before flutter build (all platforms): Flutter never removes previous artifacts from e.g. flutter-apk/, and copy_build_output harvests these directories wholesale — switching --arch/--split-per-abi (or renaming the product) between runs landed artifacts of the previous build in the user's output directory.
  • New flet_cli/utils/android.py helpers + unit tests.

Test code

flet build apk --arch arm64-v8a
unzip -l build/apk/*.apk 'lib/*'

Full validation matrix (clean state, verified with unzip -l, sizes from a minimal counter app):

Command Result
apk --arch arm64-v8a one APK (24 MB), only lib/arm64-v8a
apk --arch arm64-v8a x86_64 one APK, exactly those two ABIs, incl. site-packages for both
apk --arch arm64-v8a --split-per-abi only *-arm64-v8a.apk, arm64 libs only
aab --arch arm64-v8a base/lib/arm64-v8a only
apk (no --arch) all 3 ABIs (66 MB) — unchanged
apk --split-per-abi (no --arch) 3 split APKs — unchanged
apk --arch x86 clean CLI error listing valid values
[tool.flet.android] target_arch = ["arm64-v8a"] same as --arch arm64-v8a

The single-ABI APK was also installed and launched on an arm64 emulator (Python boots, site-packages import, UI renders).

Additional details

  • Keeping the template's existing ndk.abiFilters block: harmless today and useful again if Flutter's plugin behavior changes. Flutter's disable-abi-filtering Gradle property was considered as an alternative but rejected to avoid coupling to a Flutter-internal property name.

Summary by Sourcery

Fix Android builds so APKs/AABs respect requested architectures and cleanly regenerate artifacts per build.

Bug Fixes:

  • Ensure flet build apk and flet build aab only package native libraries for the Android ABIs requested via --arch, instead of all default ABIs.
  • Forward Android --arch values to Flutter as --target-platform so engine artifacts and --split-per-abi outputs are generated only for the requested ABIs.
  • Validate Android --arch values at the CLI level and surface a clear error when unsupported architectures are specified.
  • Fix handling of repeated/multi-value --arch, --source-packages, and --permissions flags so all provided values are preserved.
  • Prevent stale build artifacts from previous Flutter builds being copied into the output directory when build options change.

Enhancements:

  • Add Android-specific helpers to map --arch values to Flutter target platforms and to compute excluded ABIs for Gradle packaging.
  • Centralize resolution of platform output paths used when copying Flutter build artifacts.
  • Extend CLI help text for --arch to clearly list supported Android and macOS architectures.

Documentation:

  • Document the Android --arch handling fixes and related build behavior changes in the changelog.

…6567)

The build template has mapped `--arch` to defaultConfig.ndk.abiFilters
since 0.85.0, but that filter is silently defeated: the Flutter Gradle
plugin programmatically adds all default ABIs as buildType-level
abiFilters when split-per-abi is off, and AGP merges the two levels as a
set union. Artifacts therefore always shipped serious_python's Python
dists for all three ABIs.

- Generate packaging.jniLibs.excludes for unrequested ABI directories in
  the app build.gradle.kts. Exclusion happens in AGP's MergeNativeLibsTask,
  upstream of both APK and AAB packaging, and filters libs from all
  sources including AAR/library-module dependencies.
- Forward --arch to flutter build as --target-platform, so engine/AOT
  artifacts are only built for the requested ABIs and --split-per-abi
  produces only the requested split APKs.
- Validate --arch values for Android builds (arm64-v8a, armeabi-v7a,
  x86_64) with a clear CLI error: serious_python also accepts x86, which
  Flutter no longer supports, and macOS-style values (arm64, x64)
  previously produced APKs with no site-packages that crashed at runtime.
…a-separated list

Dart's args parser accepts multi-option values only comma-separated or
via repeated flags; with the previous space-separated form, every value
after the first was silently consumed as a positional argument, so
multi-arch builds shipped libpythonsitepackages.so only for the first
ABI and crashed at import time on the others.
…build

flutter-apk/ and bundle/ accumulate artifacts across builds, and
copy_build_output copies them wholesale — switching --arch or
--split-per-abi between runs landed artifacts of the previous build in
the user's output directory.
Generalizes the Android-only cleanup: every platform's output directories
are final assembly areas that the native toolchain fully regenerates, so
wiping them before 'flutter build' guarantees copy_build_output only
harvests artifacts of the current build. Beyond the Android flag-toggle
case, this also covers stale old-named binaries left behind in
Release/, bundle/ or build/ios/ipa/ after a product rename.

Extracts the outputs-glob placeholder resolution from copy_build_output
into resolve_output_path() — the linux outputs glob has {arch} in its
directory part, so cleaning its dirname requires the substitution.
… and --permissions flags

These options were declared with nargs="+" but argparse's default store
action, so repeating the flag silently replaced earlier values
(--arch arm64-v8a --arch x86_64 kept only x86_64). action="extend"
makes repetition accumulate, matching --exclude, --info-plist and the
other multi-value options in this file. Space-separated single-flag
usage is unchanged.

--flutter-build-args is intentionally left on action="append": repeats
already accumulate as nested lists, which its consumers flatten.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've reviewed this pull request using the Sourcery rules engine

@ndonkoHenri ndonkoHenri changed the base branch from main to flet-0.86 June 11, 2026 21:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Fixes Android --arch builds inadvertently packaging all default ABIs by ensuring only requested ABIs’ native libs and Flutter artifacts are produced and included.

Changes:

  • Add Gradle packaging.jniLibs.excludes for unrequested Android ABI directories in the generated app template.
  • Introduce Android ABI helpers (ABI ↔ Flutter --target-platform, excluded ABIs) and validate Android --arch values.
  • Improve CLI handling of multi-value flags and clear stale Flutter build outputs before copying artifacts.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/build.gradle.kts Excludes unrequested ABI lib/<abi>/ directories during native libs merge/packaging.
sdk/python/packages/flet-cli/src/flet_cli/utils/android.py Adds Android ABI mapping/validation helpers used by the build pipeline.
sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py Fixes multi-value parsing for flags and validates Android --arch; passes excluded ABIs into templates.
sdk/python/packages/flet-cli/src/flet_cli/commands/build.py Forwards --arch to Flutter via --target-platform and deletes stale output dirs before building.
CHANGELOG.md Documents the Android --arch packaging fix and multi-flag behavior fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread sdk/python/packages/flet-cli/src/flet_cli/utils/android.py
Comment thread sdk/python/packages/flet-cli/src/flet_cli/commands/build.py
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 11, 2026

Copy link
Copy Markdown

Deploying flet-website-v2 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2d8f4a1
Status: ✅  Deploy successful!
Preview URL: https://46716290.flet-website-v2.pages.dev
Branch Preview URL: https://fix-android-arch-filtering.flet-website-v2.pages.dev

View logs

…-filtering

# Conflicts:
#	CHANGELOG.md
#	sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py
…pports

python-build dropped 32-bit Android in 3.13 (PEP 738), so with the new
3.14 default a no---arch build packaged armeabi-v7a engine libs without
a Python runtime — 32-bit devices could install the app but it crashed
at startup. Each PythonRelease row now declares its android_abis, the
default target_arch materializes from it, and an explicit
--arch armeabi-v7a with Python >= 3.13 fails fast suggesting
--python-version 3.12.

Adds registry-consistency tests for android_abis.
…pports

python-build dropped 32-bit Android in 3.13 (PEP 738), so with the new
3.14 default a no---arch build packaged armeabi-v7a engine libs without
a Python runtime — 32-bit devices could install the app but it crashed
at startup. Each PythonRelease row now declares its android_abis, the
default target_arch materializes from it, and an explicit
--arch armeabi-v7a with Python >= 3.13 fails fast suggesting
--python-version 3.12.

Adds registry-consistency tests for android_abis.
… fix-android-arch-filtering

# Conflicts:
#	CHANGELOG.md
#	sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py
The multi-version Python PR (#6577) removed flet.version.pyodide_version
but the 'Get Pyodide version' step still read it, failing every
'Build Flet Client for Web' run. Resolve the version from the
flet_cli.utils.python_versions registry instead (default release's
Pyodide), and replace the hand-rolled tarball + wheel downloads with
flet_cli.utils.pyodide.ensure_pyodide — the hardcoded
micropip-0.8.0/packaging-24.2 filenames would have silently broken on
the new Pyodide line (3.14's lock resolves micropip 0.11.1), since
curl without -f writes 404 pages into the .whl files.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants