首先大家先了解下:
ABI和CPU
不同的 Android 手机使用不同的 CPU,而不同的 CPU 支持不同的指令集。CPU 与指令集的每种组合都有专属的应用二进制接口,即 ABI。
每个 ABI 支持一个或多个指令集,每个 ABI 支持的指令集如下图。
ABI | 支持的指令集 | 备注 |
armeabi | ARMV5TE 和更高版本Thumb-1 | 在 r16 中已弃用。在 r17 中已移除。无硬浮点数。 |
armeabi-v7a | armeabiThumb-2VFPv3-D16其他(可选) | 与 ARMv5、ARMv6 设备不兼容 |
arm64-v8a | AArch64 | 兼容armeabi-v7a |
x86 | x86 (IA-32)MMXSSE/2/3SSSE3 | 不支持 MOVBE 或 SSE4。 |
x86_64 | x86-64MMXSSE/2/3SSSE3SSE4.1、4.2POPCNT |
64 位设备也支持其 32 位变体。以 arm64-v8a 设备为例,该设备也可以运行 armeabi 和 armeabi-v7a 代码,但相对来说代码运行的效率也会略有降低。但请注意,如果应用以 arm64-v8a 为目标,而非依赖于运行 armeabi-v7a 版应用的设备,应用在 64 位设备上的性能要好得多。
报错原因
正常情况下,找到所需的库时,软件包管理器会将它们复制到应用的 data 目录 (data/data/<package_name>/lib/) 下的 /lib/lib.so。
如果根本没有共享对象文件,应用也会编译并安装,但在运行时会崩溃。
举个荔枝:如果你有两个文件夹armeabi和arm64-v8a。armeabi里面有a.so 和 b.so,arm64-v8a里面只有a.so,那么arm64-v8a的手机在用到b的时候发现有arm64-v8a的文件夹,但是里面没有b.so,就报错了,所以删掉arm64-v8a文件夹,这个时候手机发现没有适配arm64-v8a,就会直接去找armeabi的so库,所以要么你别加arm64-v8a,要么armeabi里面有的so库,arm64-v8a里面也必须有。
解决问题
既然已经知道了问题原因,那么咱们就单刀直入 直捣黄龙。
依旧以 arm64-v8a 设备为例,只留下armeabi-v7a文件夹(留下哪些文件夹应该根据提供的so库决定,如果有其他类型的so文件夹也可以不删除),其余的文件夹删除,并保持这两个文件夹里的文件是一样的。
然后在gradle.properties中添加:
android.useDeprecatedNdk=true
在build.gradle(app)中添加对应的cpu的.so库:
android {
...
defaultConfig {
.....
ndk {
//选择要添加的对应cpu类型的.so库。
// abiFilters 'armeabi','arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
abiFilters 'armeabi-v7a'
moduleName "app"
}
}
}
需要注意的是:可能有些时候为了打包方便,在打包时生成多个ABI的apk,但于此是大忌!因为通过此方法打包的apk lins下只会有一个对应ABI的文件夹。
举个荔枝,若include‘arm64-v8a’,那么打出的apk中lins里只会有一个名为arm64-v8a的空文件夹 ,因为我们的so文件只存在于’armeabi-v7a’中,那么在程序运行后就会报没有so文件的错误。所以在打包多个ABI类型的apk时,一定要于添加的cpu类型的so对应。
android {
...
defaultConfig {
.....
}
splits {
abi {
enable true
reset()
//include 'armeabi', 'armeabi-v7a','arm64-v8a','x86','x86_64'
include 'armeabi-v7a'
universalApk true
}
}
}
完整的配置为:
android {
...
defaultConfig {
.....
ndk {
//选择要添加的对应cpu类型的.so库。
//abiFilters 'armeabi','arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
abiFilters 'armeabi-v7a'
moduleName "app"
}
}
splits {
abi {
enable true
reset()
//同时打包出多个cpu类型的apk
//include 'armeabi', 'armeabi-v7a','arm64-v8a','x86','x86_64'
include 'armeabi-v7a'
universalApk true
}
}
}
总结
使用上述方法虽然可以解决java.lang.UnsatisfiedLinkError的问题,但是在程序的运行效率上会有所降低。若可以选择还是建议编译CPU直接支持的指令集而不是兼容的指令集。
参考:
https://developer.android.google.cn/ndk/guides/abis https://www.zhihu.com/question/36893314/answer/78467097