Android按需打包多种ABI(cpu)架构的so文件库

来源:互联网 发布:蚁群算法公式解析 编辑:程序博客网 时间:2024/06/06 10:51

ABI 管理


大家先来看看Google官方对Android ABI管理的介绍:


不同 Android 手机使用不同的 CPU,因此支持不同的指令集。CPU 与指令集的每种组合都有其自己的应用二进制界面(或 ABI)。 ABI 可以非常精确地定义应用的机器代码在运行时如何与系统交互。 您必须为应用要使用的每个 CPU 架构指定 ABI。

典型的 ABI 包含以下信息:

  • 机器代码应使用的 CPU 指令集。
  • 运行时内存存储和加载的字节顺序。
  • 可执行二进制文件(例如程序和共享库)的格式,以及它们支持的内容类型。
  • 用于解析内容与系统之间数据的各种约定。这些约定包括对齐限制,以及系统如何使用堆栈和在调用函数时注册。
  • 运行时可用于机器代码的函数符号列表 - 通常来自非常具体的库集。

本页枚举了 NDK 支持的 ABI,并且提供每个 ABI 如何运行的信息。

支持的 ABI


每个 ABI 支持一个或多个指令集。表 1 提供每个 ABI 支持的指令集概览。

表 1. ABI 和支持的指令集。

ABI支持的指令集说明armeabi
  • ARMV5TE 和更高版本
  • Thumb-1
  • 无硬浮点。armeabi-v7a
  • armeabi
  • Thumb-2
  • VFPv3-D16
  • 其他(可选)
  • 与 ARMv5、v6 设备不兼容。arm64-v8a
  • AArch-64
  • x86
  • x86 (IA-32)
  • MMX
  • SSE/2/3
  • SSSE3
  • 不支持 MOVBE 或 SSE4。x86_64
  • x86-64
  • MMX
  • SSE/2/3
  • SSSE3
  • SSE4.1、4.2
  • POPCNT
  • mips
  • MIPS32r1 及更高版本
  • 使用硬浮点,并且假设 CPU:FPU 时钟比率为 2:1 以获取最大兼容性。 不提供 micromips 或 MIPS16。mips64
  • MIPS64r6
  •  

    Android 平台 ABI 支持

    Android 系统在运行时知道它支持哪些 ABI,因为版本特定的系统属性会指示:

    • 设备的主要 ABI,与系统映像本身使用的机器代码对应。
    • 可选的辅助 ABI,与系统映像也支持的另一个 ABI 对应。

    此机制确保系统在安装时从软件包提取最佳机器代码。

    为实现最佳性能,应直接针对主要 ABI 进行编译。例如,基于 ARMv5TE 的典型设备只会定义主要 ABI:armeabi。 相反,基于 ARMv7 的典型设备将主要 ABI 定义为 armeabi-v7a,而将辅助 ABI 定义为 armeabi,因为它可以运行为每个 ABI 生成的应用原生二进制文件。

    许多基于 x86 的设备也可运行 armeabi-v7a 和 armeabi NDK 二进制文件。对于这些设备,主要 ABI 将是 x86,辅助 ABI 是 armeabi-v7a

    基于 MIPS 的典型设备只定义主要 ABI:mips

    安装时自动解压缩原生代码

    安装应用时,软件包管理器服务将扫描 APK,查找以下形式的任何共享库:

    lib/<primary-abi>/lib<name>.so

    如果未找到,并且您已定义辅助 ABI,该服务将扫描以下形式的共享库:

    lib/<secondary-abi>/lib<name>.so

    找到所需的库时,软件包管理器会将它们复制到应用的 data 目录 (data/data/<package_name>/lib/) 下的 /lib/lib<name>.so

    如果根本没有共享对象文件,应用也会构建并安装,但在运行时会崩溃。


    问题所在

    Google官方已经说的很清楚了,安装apk时,会扫描对应abi版本的库,没有的话就扫描兼容的库,如果根本没有共享对象文件,应用也会构建并安装,但在运行时会崩溃。

    而我们在平时开发中经常会用到很多第三方库,但是他们提供的so文件支持版本,都会有很多不同,所以在构建的时候只能选择其中一种平台或者几种平台库打包。
    现在通常的做法就是只打包armeabi-v7a一种平台的库,这种方式很好解决,直接使用Google官方提供的方案打包即可,方法如下:

    1.在项目application model的build.gradle添加如下节点

    1. android {
    2. splits {
    3. abi {
    4. enable true
    5. reset()
    6. include 'armeabi-v7a'
    7. universalApk true
    8. }
    9. }
    10. }

    参数解析

    参数释义splits拆分apkabi根据ABI拆分enable是否启用拆分include包含哪些ABI类型universalApk是否生成通用的APK具体可以参照官网:https://developer.android.com/studio/build/configure-apk-splits.html#configure-abi-split
    这种方案有一个缺点:如果我想同事打包armeabi-v7a和x86的 so包到同一个apk,这种方式是无法做到的,因为它只能打包一种平台的so包到同一个apk中,你如果include后边跟了几个平台,他会单独打包成对应平台的apk。

    我们要解决的问题就是:如何打包多个平台的so包到同一个apk中,我提供两种解决方案解决这个问题

    第一种:

    1.在项目application model的build.gradle添加如下节点

    1. android {
    2. defaultConfig {
    3. ndk {
    4. abiFilters 'armeabi' ,'armeabi-v7a'
    5. }
    6. }
    7. }

    然后在project的根目录(和local.properties同级)找到gradle.properties文本文件, 
    文件里面加入下面这行

    1. android.useDeprecatedNdk=true


    第二种:

    1.在项目application model的build.gradle添加如下节点

    1. android {
    2. packagingOptions {
    3.   exclude 'lib/armeabi/**'        //exclude 'lib/armeabi-v7a/**'        exclude 'lib/arm64-v8a/**'        exclude 'lib/mips/**'        exclude 'lib/mips64/**'        //exclude 'lib/x86/**'        exclude 'lib/x86_64/**'
    4. }
    5. }

    参数解析

    参数释义packagingOptions打包配置exclude排除掉哪些文件您想打包哪个平台的,就注释掉对应的行

    注:目前我只找到这两种方式,如果您有更好的方式,请留言。