核心在于目标差异:ndk.abiFilters仅过滤单个APK内.so库的ABI集合,生成一个通用包;splits.abi则按指定ABI分别生成多个独立APK(如app-arm64-v8a-release.apk),适配应用市场分发需求,并自动处理versionCode偏移与AndroidManifest注入。

Gradle 按 ABI 分别生成 Android 安装包,核心是启用 splits.abi 配置,而不是靠 ndk.abiFilters —— 后者只控制哪些 so 库打进单个 APK,不生成多个 APK。
为什么用 splits.abi 而不是 ndk.abiFilters
ndk.abiFilters 是过滤最终 APK 里包含哪些 ABI 的 so 库,结果仍是「一个 APK」;splits.abi 才是让 Gradle 输出多个 APK(如 app-arm64-v8a-release.apk、app-armeabi-v7a-release.apk)。
- 如果你的目标是上传不同 ABI 包到华为/小米等应用市场,必须用
splits - 如果你只是想减小单个 APK 体积,用
abiFilters就够了,不用分包 -
splits生成的每个 APK 里只含对应 ABI 的 so,且AndroidManifest.xml会自动注入android:versionCode偏移(避免安装冲突)
在 build.gradle 中正确配置 splits.abi
必须写在模块级(通常是 app/build.gradle)的 android { } 块内,不是 defaultConfig 或 buildTypes 里。
-
enable true是开关,不设就等于没开 - 用
reset()+include是最安全的方式,避免因 Gradle 版本差异带入意外 ABI(比如新版默认含x86_64,但你根本不需要) -
exclude看似方便,但容易漏掉新增 ABI(如未来 Gradle 加了riscv64),推荐显式include
示例(Kotlin DSL):
android {
splits {
abi {
enable = true
reset()
include("arm64-v8a", "armeabi-v7a")
universalApk = false
}
}
}
build 命令和输出结果要注意什么
执行 ./gradlew assembleRelease 后,APK 不再只出一个 app-release.apk,而是按 ABI 分散在 build/outputs/apk/release/ 下:
app-arm64-v8a-release.apkapp-armeabi-v7a-release.apk- 如果设了
universalApk = true,还会多一个app-universal-release.apk(含全部 ABI,体积最大)
注意:versionCode 会被自动调整。比如你在 defaultConfig 里设的是 versionCode 100,Gradle 会给 arm64-v8a 包加 2、armeabi-v7a 加 1,变成 102 和 101 —— 这是为了防止用户从低 ABI 升级到高 ABI 时被系统拒绝安装。
容易踩的坑:ABI 兼容性与设备实际匹配
生成了 arm64-v8a 和 armeabi-v7a 两个包,并不意味着所有设备都能装对。关键看设备运行时报告的 ABI:
- 64 位设备(如骁龙 8 Gen3)通常同时上报
arm64-v8a和armeabi-v7a,但 Google Play 优先匹配第一个,所以它会装arm64-v8a包 - 纯 32 位设备(如旧款联发科 MT6582)只上报
armeabi-v7a,只能装对应包 - 如果误把
x86包上传到手机市场,用户下载后会提示 “This app is incompatible with your device”
真正需要验证的不是 Gradle 配置是否生效,而是最终 APK 的 lib/ 目录下是否只含目标 ABI 子目录,且里面 so 文件数量/名称与源码一致 —— 否则运行时 UnsatisfiedLinkError 会直接 crash。











