Android ABI Filters: How to Choose Architectures Without Breaking Devices
A practical guide to Android ABI filters, native library packaging, 32-bit and 64-bit support, and testing architecture choices across real devices.
Table of Contents10 sections
If an Android app contains only Kotlin or Java bytecode, ABI selection is usually invisible. The moment a dependency ships native .so files, architecture becomes part of your compatibility contract.
The practical rule is: do not add ABI filters just because they make an APK smaller. Add them only when you understand which native libraries your app ships, which devices you must support, and how your distribution channel packages those libraries.
What an Android ABI Actually Controls
An ABI describes the CPU architecture and binary interface expected by native code. Common Android ABIs include arm64-v8a, armeabi-v7a, x86_64, and the older x86.
Android’s 64-bit architecture guidance explains that native libraries are packaged under ABI-specific directories such as lib/arm64-v8a/ and lib/armeabi-v7a/.
If your app has no native libraries, filtering ABIs does not magically optimize Kotlin code. ABI decisions matter when your own NDK code or a third-party SDK introduces native binaries.
Start by Inspecting the Artifact
Before editing Gradle, inspect the APK or bundle you already produce. Android Studio’s APK Analyzer can show whether the package contains .so files and which ABI directories they occupy. From the command line, an APK can also be inspected as a ZIP archive:
zipinfo -1 app-release.apk | grep '\.so$'
Check whether every native dependency you rely on is available for the architectures you intend to ship. A payment SDK, image processor, database engine, device-vendor library, or another dependency may introduce native code even when your application code is Kotlin.
When abiFilters Makes Sense
A Gradle configuration can restrict the ABIs built or packaged:
android {
defaultConfig {
ndk {
abiFilters += listOf("arm64-v8a", "armeabi-v7a")
}
}
}
This is useful when the supported hardware fleet is known, native build time matters, or a distribution artifact intentionally targets a constrained device family. It is dangerous when the filter is copied from another project without checking transitive native dependencies or the actual device matrix.
Think of abiFilters as a compatibility policy, not a cleanup flag.
App Bundle Changes the Size Calculation
For Google Play distribution, an Android App Bundle changes the trade-off. Google’s app-size guidance explains that Play generates optimized APKs for device configurations, so users do not necessarily download every architecture contained in the bundle.
That means removing ABIs solely to reduce the universal artifact size can be the wrong optimization. You may save little for Play users while silently excluding hardware you still intended to support.
For direct APK distribution, enterprise deployment, alternative stores, or sideloading, packaging strategy deserves separate verification because the delivery system may not perform the same device-specific splitting. If you own that delivery path, the secure in-app APK update architecture should treat the chosen artifact, package identity, signing continuity, and installation state as one release contract.
32-bit and 64-bit Must Be a Deliberate Decision
For ARM, armeabi-v7a is 32-bit and arm64-v8a is 64-bit. If a product still supports 32-bit hardware, dropping armeabi-v7a is a product decision with a measurable device impact.
Conversely, keeping only a 32-bit native library is increasingly fragile. Android’s official guidance recommends checking third-party SDKs for appropriate 64-bit libraries rather than assuming the build system can transform a 32-bit binary into a 64-bit one.
Gradle can choose which binary to package, but it cannot manufacture a missing architecture for a closed-source .so.
Device Fleets Need a Compatibility Matrix
For apps deployed to dedicated Android hardware, build the ABI policy from the fleet rather than from phone-market assumptions.
| Device family | CPU ABI | Android version | Required native SDK | Verified artifact |
|---|---|---|---|---|
| Fleet A | arm64-v8a | supported | vendor SDK | yes/no |
| Fleet B | armeabi-v7a | supported | vendor SDK | yes/no |
| Emulator | x86_64 | test only | optional | yes/no |
Then decide which rows are production requirements and which exist only for development. This avoids a common failure mode: a release works on modern phones and CI emulators but cannot install or load a native library on older dedicated hardware.
Do Not Forget Native Library Compatibility Beyond ABI
ABI is only one dimension of native compatibility. Newer Android hardware can also expose assumptions about memory-page alignment.
Android’s 16 KB page-size guidance recommends current Android Gradle Plugin and NDK versions and explains how to verify bundle alignment. An app can therefore have the correct arm64-v8a library and still require native-toolchain work for newer devices.
The broader lesson is useful: the architecture matching does not mean the native binary is compatible.
A Safer Release Checklist
Before changing ABI support:
- Inspect release artifacts for every
.so. - Identify which dependency owns each native library.
- Map production devices to their required ABI.
- Confirm every mandatory native dependency exists for those ABIs.
- Decide separately for App Bundle and direct-APK distribution.
- Test installation and the native-code path on representative hardware.
- Recheck native compatibility when upgrading SDKs, AGP, or the NDK.
If APK size is the motivation, measure the delivered artifact rather than optimizing the repository configuration by intuition.
The Takeaway
Android ABI filters are not primarily a performance feature. They are a declaration of which native architectures your application is prepared to support.
Start with the binaries you actually ship and the devices you actually support. Use filters only after that evidence is clear. For App Bundles, account for device-specific delivery before removing architectures for size. For managed hardware fleets, maintain an explicit compatibility matrix and test the native path, not just app startup.
That approach turns abiFilters from a mysterious Gradle snippet into a deliberate release-engineering decision.
Continue Exploring
You Might Also Like
Why Android Push Notifications Duplicate and How to Fix Them
A practical debugging workflow for duplicate Android notifications, covering FCM payload ownership, stable notification IDs, PendingIntent identity, and idempotent handling.
How to Handle Partial Success in Android ViewModels
A practical pattern for Android mutations that succeed before a follow-up refresh fails, without lying to the user or turning Compose callbacks into orchestration code.
Android WebView vs Custom Tabs: How to Choose
Choose between Android WebView and Custom Tabs by comparing ownership, security, browser state, UI control, authentication, lifecycle cost, and testing.