美文网首页Android-NDK/JNI
Android:如何正确放置so库文件

Android:如何正确放置so库文件

作者: rechen | 来源:发表于2018-09-27 10:47 被阅读69次

问题描述

当需要引用 so 库的时候,正常情况下我们只需要将不同版本的 so 文件分别放置。但是这样就会遇到两个问题:

  1. 如果每个架构的 so 库都放进去,会大大增加 apk 包的大小
  2. 如果偏偏没有 arm-v7a 的版本呢?是删除 armeabi-v7a 目录只保留 armeabi ?还是说两个目录下 so 文件数不同也没有关系?

首先了解一下 so 文件的类型

so 文件的类型

在 Android 系统中 ndk 默认会生成如下 7 种 .so。

  • armeabi ARM:v5 第5代、第6代的ARM处理器,早期的手机用的比较多。缺少对浮点数计算的硬件支持,在需要大量计算时有性能瓶颈
  • armeabi-v7a:v7 目前主流版本,2011年15月以后的生产的大部分Android设备都使用它
  • arm64-v8a:第8代、64位ARM处理器,很少设备,三星 Galaxy S6是其中之一
  • x86:平板、模拟器用得比较多
  • x86_64:x86架构的64位。
  • mips:极少用于手机
  • mips64:mips架构的64位

首先mips和mips64极少用于手机,因此可以忽略;x86和x86_64的架构都会包含由 Intel 提供的称为 Houdini 的指令集动态转码工具,实现 对 arm 的兼容,再考虑 x86 1% 以下的市场占有率,x86 相关的两个 so 也是可以忽略的;arm64-v8a 是可以向下兼容的,因此也是可以忽略的。

也就是说,项目中只需要保存两种架构即可:armeabi 和 armeabi-v7a。

android加载 so 库的模式

比如当前用户的手机是 armeabi-v7a 的,apk的armeabi包下有 a.so 和 b.so 两个库,而 armeabi-v7a 包下只有 a.so 一个库。

  1. android4.4 的so文件拷贝逻辑

android在扫描apk文件的时候,并没有保证 zip entry 的扫描顺序。加载 libs/<abi>/libxxx.so 时,首先判断这个 so 库是否是当前CPU的架构,如果是的话,则将一个类似名为 hasPrimary 的 boolean 值置为 true ,然后将 so 库拷贝到手机上;如果不是的话,则判断是否已经加载过当前CPU架构的 so 库了,即判断 hasPrimary 的值,只有 hasPrimary 的值为 false 时,即还没有加载过当前CPU架构的 so 库,则将这个 so 库拷贝到手机上。

  • 如果首先扫描到 armeabi 包下的 a.so 库,此时因为 hasPrimary 默认为false,因此会将 a.so 库拷贝到手机上,随后 armeabi 下的 b.so 库也会被拷贝到手机上
  • 如果首先扫描到 armeabi-v7a 包下的 a.so 库,此时会将 hasPrimary 置为true,并将 a.so 库拷贝到手机上,因为 hasPrimary 的值为 true ,后面也就不会拷贝 armeabi 包下的 b.so 库了

因此有可能只会拷贝 armeabi-v7a 下的 a.so 库到手机上,当执行 b.so 中的逻辑时,就会产生 crash

  1. android5.0+ 的 so 文件拷贝逻辑

不再以文件为粒度匹配,直接拷贝整个文件夹。因此只会将整个 armeabi-v7a 包下的 so 库拷贝,因此当执行 b.so 中的逻辑时,也会产生crash

正确的放置方法

  • 为了减小 apk 体积,只保留 armeabi 和 armeabi-v7a 两个文件夹,并保证这两个文件夹中 so 数量一致
  • 对只提供 armeabi 版本的第三方 so,原样复制一份到 armeabi-v7a 文件夹

相关文章

网友评论

    本文标题:Android:如何正确放置so库文件

    本文链接:https://www.haomeiwen.com/subject/bsteoftx.html