安卓项目中so库选择

接上篇Android中常见SDK类型区别-优快云博客

一些重要的加密算法或者核心协议一般都在C中编写,然后给java调用。这样可以避免反编译后查看到应用的源码。此时就需要了解一下NDK中的ABI(Application Binary Interface的缩写,也就是应用二进制接口)。

ABI现状及原理分析

Android 目前共支持7种CPU架构:
一类:mips, mips64, X86, X86–64, armeabi, 二类:armeabi-v7a,arm64-v8a,

基于平台:

平台        

32位库文件夹64位库文件夹
ARMlib/armeabi-v7alib/arm64-v8a
X86lib/x86lib/x86-64

市场占有率上,一类架构基本可以不不考虑了,它们的占有量应很少很少了,arm64-v8a作为最新一代架构,应该是目前的主流,armeabi-v7a只存在少部分老旧手机。
根据参考资料:微信适配的是arm64-v8a(部分渠道下载的apk可能适配的是armeabi-v7a,不做过多纠结,有可能采用的是动态下发的方案,具体不详,以前是armeabi),支付宝和手Q适配的是armeabi,淘宝适配的是armeabi-v7a。各个APP适配的平台不太一样,但是他们有一个共同点,那就是它们只指定了一个平台。

一个Android设备可以支持多种ABI(设备主ABI和辅助ABI)

  • 以arm64-v8a为主ABI的设备,辅助ABI为armeabi-v7a和armeabi;
  • 以armeabi-v7a为主ABI的设备,辅助ABI为armeabi。

另外,x86 架构的手机都会包含由 Intel 提供的称为 Houdini 的指令集动态转码工具,实现对 arm .so 的兼容,也就是说有适配armeabi平台的APP是可以跑在x86手机上的。

ABI工作原理

不同Android设备,使用的CPU架构可能不同,因此支持不同的指令集。 CPU 与指令集的每种组合都有其自己的应用二进制界面(或 ABI),ABI非常精确地定义了应用程序的机器代码应如何在运行时与系统交互。您必须为要与您的应用程序一起使用的每种CPU架构指定一个ABI(Application Binary Interface),一个APK可以同时包含32位(例如armeabi-v7a、x86)和64位例如arm64-v8a、x86_64)的二进制版本,以便在各种设备上提供最佳性能

ABI 包含以下信息:

  • 可使用的 CPU 指令集(和扩展指令集)。
  • 运行时内存存储和加载的字节顺序。Android 始终是 little-endian。
  • 在应用和系统之间传递数据的规范(包括对齐限制),以及系统调用函数时如何使用堆栈和寄存器。
  • 可执行二进制文件(例如程序和共享库)的格式,以及它们支持的内容类型。Android 始终使用 ELF。
  • 如何重整 C++ 名称。
如何判断APK的架构
  • 使用APK分析工具:Android Studio 提供了一个内置工具叫做APK Analyzer,它可以帮助你查看APK的内容,包括其支持的架构。打开Android Studio,选择“Build” > “Analyze APK…”,然后选择你的APK文件进行分析。
  • 手动检查APK文件:更改APK文件扩展名为.zip,然后解压缩它。在解压缩的文件夹中,导航到lib目录。查看lib目录下的子目录名称,这些名称代表了APK支持的架构。例如,arm64-v8a表示64位ARM架构,而armeabi-v7a表示32位ARM架构。
  • 使用命令行工具:通过aapt工具来查看APK文件的信息,包括其支持的架构。
    aapt dump badging your_app.apk | grep native-code

这条命令会输出APK支持的架构信息。aapt工具包含在Android SDK的Build-tools中。

  • 查看zygote和zygote64的进程号
//查看zygote和zygote64的进程号
adb shell ps -A|grep zygote
//查看app的进程号,new表示app packagename中的内容
adb shell ps -A|grep new

new进程24351是进程号772的进程创建的,772的进程是64位的(773进程时32位)。所以new是运行在64位系统中

简单做一个so加载流程时序图以arm64-v8a架构的手机为例:

在这里插入图片描述

 特别需要注意的情况是在命中了文件夹,而未命中so文件这种情况:

  • 比如命中了arm64-v8a文件夹,没有找到需要的so文件,就不会再往下(armeabi-v7a文件夹)找了,而是直接抛出异常。
  • 如果你的项目用到了第三方依赖,如果只保留一个ABI的时候,建议在Build中加入ndk.abiFilters
    例如:第三方aar文件,如果这个sdk对abi的支持比较全,可能会包含armeabi、armeabi-v7a、x86、arm64-v8a、x86_64五种abi,而你应用的其它so只支持armeabi、armeabi-v7a、x86三种,直接引用sdk的aar,会自动编译出支持5种abi的包。但是应用的其它so缺少对其它两种abi的支持,那么如果应用运行于arm64-v8a、x86_64为首选abi的设备上时,就会crash了哦。
我们该如何适配?

明确一个基本原则,abi是向下兼容的,即:

  • 只适配armeabi的APP可以跑在armeabi,x86,x86_64,armeabi-v7a,arm64-v8上
  • 只适配armeabi-v7a可以运行在armeabi-v7a和arm64-v8a
  • 只适配arm64-v8a 可以运行在arm64-v8a上

因此我们有如下适配方案:

  • 只适配armeabi:
    优点:基本可以适配所有手机机型,除了淘汰的mips和mips_64
    缺点:在大多数手机上都需要利用辅助ABI或者动态转码来兼容,性能较差

  • 只适配 armeabi-v7a
    只是又筛掉了一部分老旧设备,在性能和兼容二者中比较平衡

  • 只适配 arm64-v8
    优点:性能最佳(微信大哥采用的)
    缺点:只能运行在arm64-v8上,要放弃部分老旧设备用户

上述方案只是我们给出的建议,具体还要看实际的需求和考量:以性能换兼容就arm64-v8,以兼容换性能armeabi,二者稍微平衡一点的就armeabi-v7a。

能否做到性能+兼容都要

上述方案多多少少有一些取舍的,有没有完美的方案,既不放弃性能,也能完全兼容。答案是肯定的,Google已经安排上了,通过abi split,分包,为每一个CUP架构打一个apk,该apk 中就只包含一个平台。 google play支持上传多个apk,但是,据我所知,目前国内的应用商店是不支持的。

android {
...
splits {

// Configures multiple APKs based on ABI.
abi {

// Enables building multiple APKs per ABI.
enable true

// By default all ABIs are included, so use reset() and include to specify that we only
// want APKs for x86 and x86_64.
// Resets the list of ABIs that Gradle should create APKs for to none.
reset()

// Specifies a list of ABIs that Gradle should create APKs for.
include "x86", "x86_64", "arm64-v8a", "armeabi", "armeabi-v7a"

// Specifies that we do not want to also generate a universal APK that includes all ABIs.
universalApk false
}
}
打包配置
split分包

这个命令可以按照各种规则去分包,比如按照abi,屏幕密度(即ldpi,hdpi等)分包

splits { 
        abi { 
            enable true
            reset()
            include 'x86','armabi'//包含
            exclude 'armeabi', 'armeabi-v7a', "arm64-v8a"//不包含
            universalApk true
        }
    }
dk{abiFilters:}过滤

这个指令可以配置只打包你配置的so库,没有配置的就不打包,很灵活。 第三方aar文件,如果这个sdk对abi的支持比较全,可能会包含armeabi、armeabi-v7a、x86、arm64-v8a、x86_64五种abi,而你应用的其它so只支持armeabi、armeabi-v7a、x86三种,直接引用sdk的aar,会自动编译出支持5种abi的包。但是应用的其它so缺少对其它两种abi的支持,那么如果应用运行于arm64-v8a、x86_64为首选abi的设备上时,就会crash了,所以我们需要在我们的app中配置 abiFilter 配置,来避免一些未知的错误

//过滤x86的so库
ndk { 
    abiFilters 'armeabi-v7a', 'arm64-v8a'//指定ndk需要兼容的ABI(这样其他依赖包里x86,armeabi之类的so会被过滤掉)
}

这样配置会将armeabi-v7a(32位),arm64-v8a(64位)这2个包下的so库都打包到一个apk,而不像splits会每一个包打一个apk.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值