那些和 so 库有关的问题
旧文新发,看了自己的笔记应用,这是 18 年写的了,感觉应该还挺有用,分享一下吧
ABI
不同 Android 手机使用不同的 CPU,因此支持不同的指令集。CPU 与指令集的每种组合都有其自己的应用二进制界面(或 ABI)。 ABI 可以非常精确地定义应用的机器代码在运行时如何与系统交互。 您必须为应用要使用的每个 CPU 架构指定 ABI。
Android 上支持的 ABI
存放位置
在 Android Studio
中,应该将 so
文件按照 ABI
分类并放置在 jniLibs
文件夹下
1 | ├── jniLibs |
查看 Android 设备支持的 ABI 类型
一般来说,设备 ABI 都是固定的,这是系统在编译时决定的,在 /system/build.prop
指定了设备的 ABI 类型
primary ABI(主ABI):对应当前系统中使用的机器码类型
secondary ABI(副ABI):表示当前系统支持的其他ABI类型
比如 Nexus 5 的 build.prop
文件中是这样的
1 | ro.product.cpu.abi=armeabi-v7a |
可以使用 adb 命令查看
1 | adb shell |
可以查看当前设备支持的 ABI 类型。
例如 Nexus 5 所支持的 ABI 类型
1 | [ro.product.cpu.abilist]: [armeabi-v7a,armeabi] |
或者在 Java
代码中,使用下面的代码获取
1 | Build.CPU_ABI//String 类型 primary ABI |
可以看到该设备(Nexus 5)的主 ABI 是 armeabi-v7a,副 ABI 是 armeabi
apk 安装过程
apk 在安装的时候,Package Manager 会扫描 apk 文件,寻找符合条件的 so 库。
现根据当前设备的 primary-abi 值,寻找对应的 so 文件,当不存在 primary 的 so 库时,会寻找 secondary 的 so 库。
即 lib/{primary-abi}/libName.so
或者 lib/{secondary-abi}/libName.so
即当安装应用时,系统会根据当前设备的 CPU 架构寻找最优的 ABI 适配,如果找到合适的 so 文件,则会将整个 abi 文件夹下的 so 文件复制到 /data/data/{package.name}/lib
目录下。
注意:apk安装过程对so选择是基于整个ABI文件夹的,而非以单个so文件为粒度,也就是说把lib/armeabi 、lib/armeabi-v7a、lib/x86等等文件夹的其中一个文件夹内所有.so复制到应用的data目录下。
经验
在我的一个 app 中,由于使用了某个第三方的 SDK ,这个第三方 SDK 只提供了 armeabi-v7a 的 so 库,并且我在这个项目中还引用了 React Native ,React Native 中包含了 x86 和 armeabi-v7a 的 so 库。
所以当我在 Pad 上安装完后,打开应用后就奔溃了,奔溃日志如下:
1 | com.facebook.soloader.SoLoader$WrongAbiError: APK was built for a different platform |
使用 Native Libs Monitor
这个软件查看该 app 安装的 so 库时发现,该 app 使用的全是 armeabi-v7a
的 so 文件,所以导致了Crash。
解决方案
- 方案一:
1 | 补齐 x86 下的 so 文件 |
- 方案二:
1 | 将第三方 SDK 提供的 so 文件复制一份到 x86 文件夹下,并在使用到这个 SDK 的功能时进行判断当前设备的 ABI ,如果是 x86 则提示用户该功能不可用。 |
配置
ndkFilter
在 build.gradle
中设置 ndkFilter
1 | defaultConfig{ |
这样的配置会使得打包后的 apk 文件中只保留 armeabi-v7a
和 x86
的文件夹。
splits
可以通过 splits 生成指定的apk文件
1 | splits { |