赞
踩
转载自:http://www.jianshu.com/p/b758e36ae9b5
国际管理上图说明
一图诠释Android的.so文件
上周末参加AndroidBus开发者论坛[上海站],《小红书Android演进之路》(主讲:桑明明)提到.so文件,保留jniLibs下armeabi-v7a就可以了,这样就大大降低app的大小。这话是对的,因为我开发中也出现过这样的情况,jniLibs下所有的文件丢失了,app就小了两三兆(就一个友盟社会化分享)。but有bug(有的手机会崩溃)。保留一个试了,没有崩溃,然后再网上各种恶补.so文件的知识,cpu架构。
-
- 指令集 厂商 位数
- x86(x86) Intel 32
- x86_64(Intel 64) Intel 64
- arm64-v8a(ARMV8-A) AMR 64
- armeabi(ARM v5) ARM 32
- armeabi-v7a(ARM v7) ARM 32
- mips MIPS 32
- mips64 MIPS 64
如上图【一图诠释Android的.so文件】
Android系统目前支持以下七种不同的CPU架构,每一种都关联着一个相应的ABI。应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。
如果项目中使用到了NDK(类似于JDK,因为版权问题谷歌自行开发了NDK),它将会生成.so文件,因此显然你已经在关注它了。如果只是使用Java语言进行编码,你可能在想不需要关注.so文件了吧,因为Java是跨平台的。但事实上,即使你在项目中只是使用Java语言,很多情况下,你可能并没有意识到项目中依赖的函数库或者引擎库里面已经嵌入了.so文件,并依赖于不同的ABI。例如,项目中使用RenderScript支持库,OpenCV,Unity,android-gif-drawable,SQLCipher等,你都已经在生成的APK文件中包含.so文件了,而你需要关注.so文件。
adb device 查看连接的设备,
adb -s 192.168.56.101:5555 shell 进入手机的shell设置模式,
cat /proc/cpuinfo 查看手机CPU信息
查看手机CPU信息的命令
或者搜:本地库监视器Native Libs Monitor(其包名:com.xh.nativelibsmonitor.app)
Android应用支持的ABI取决于APK中位于lib/ABI目录中的.so文件,其中ABI可能是上面说过的七种ABI中的一种。
很多设备都支持多于一种的ABI。例如ARM64和x86设备也可以同时运行armeabi-v7a和armeabi的二进制包。但最好是针对特定平台提供相应平台的二进制包,这种情况下运行时就少了一个模拟层(例如x86设备上模拟arm的虚拟层),从而得到更好的性能(归功于最近的架构更新,例如硬件fpu,更多的寄存器,更好的向量化等)。
我们可以通过Build.SUPPORTED_ABIS得到根据偏好排序的设备支持的ABI列表。但你不应该从你的应用程序中读取它,因为Android包管理器安装APK时,会自动选择APK包中为对应系统ABI预编译好的.so文件,如果在对应的lib/ABI目录中存在.so文件的话。
7.1、处理.so法则和系统的选择
处理.so文件时有一条简单却并不知名的重要法则:你应该尽可能的提供专为每个ABI优化过的.so文件,但要么全部支持,要么都不支持:你不应该混合着使用。你应该为每个ABI目录提供对应的.so文件。
当一个应用安装在设备上,只有该设备支持的CPU架构对应的.so文件会被安装。在x86设备上,libs/x86目录中如果存在.so文件的话,会被安装,如果不存在,则会选择armeabi-v7a中的.so文件,如果也不存在,则选择armeabi目录中的.so文件(因为x86设备也支持armeabi-v7a和armeabi)。
7.2、常见crash(崩溃)系列
当你引入一个.so文件时,不止影响到CPU架构。我从其他开发者那里可以看到一系列常见的错误,其中最多的是"UnsatisfiedLinkError","dlopen: failed"以及其他类型的crash或者低下的性能:使用android-21平台版本编译的.so文件运行在android-15的设备上,使用NDK时,你可能会倾向于使用最新的编译平台,但事实上这是错误的,因为NDK平台不是后向兼容的,而是前向兼容的。推荐使用app的minSdkVersion对应的编译平台。这也意味着当你引入一个预编译好的.so文件时,你需要检查它被编译所用的平台版本。
7.3、混合使用不同C++运行时编译的.so文件
.so文件可以依赖于不同的C++运行时,静态编译或者动态加载。混合使用不同版本的C++运行时可能导致很多奇怪的crash,是应该避免的。作为一个经验法则,当只有一个.so文件时,静态编译C++运行时是没问题的,否则当存在多个.so文件时,应该让所有的.so文件都动态链接相同的C++运行时。这意味着当引入一个新的预编译.so文件,而且项目中还存在其他的.so文件时,我们需要首先确认新引入的.so文件使用的C++运行时是否和已经存在的.so文件一致。
7.4、如果没有为每个支持的CPU架构提供对应的.so文件
这一点在前文已经说到了,但你应该真的特别注意它,因为它可能发生在根本没有意识到的情况下。例如:你的app支持armeabi-v7a和x86架构,然后使用Android Studio新增了一个函数库依赖,这个函数库包含.so文件并支持更多的CPU架构。如友盟社会化分享jar包带有各种.so文件,放在jniLibs下的对应文件夹中。
7.5、在我们发布app后
会发现它在某些设备上会发生Crash,最终可以发现只有64位目录下的.so文件被安装进手机。
解决方案:重新编译我们的.so文件使其支持缺失的ABIs,或者设置:ndk.abiFilters 显示指定支持的ABIs。(最后一点:如果你是一个SDK提供者,但提供的函数库不支持所有的ABIs,那你将会搞砸你的用户,因为他们能支持的ABIs必将只能少于你提供的。)
7.6、将.so文件放在错误的地方
我们往往很容易对.so文件应该放在或者生成到哪里感到困惑,下面是一个总结:
7.7、只提供armeabi架构的.so文件而忽略其他ABIs的
所有的x86/x86_64/armeabi-v7a/arm64-v8a设备都支持armeabi架构的.so文件,因此似乎移除其他ABIs的.so文件是一个减少APK大小的好技巧。但事实上并不是:这不只影响到函数库的性能和兼容性。x86设备能够很好的运行ARM类型函数库,但并不保证100%不发生crash,特别是对旧设备。64位设备(arm64-v8a, x86_64, mips64)能够运行32位的函数库,但是以32位模式运行,在64位平台上运行32位版本的ART和Android组件,将丢失专为64位优化过的性能(ART,webview,media等等)。
7.8、以减少APK包大小为由是一个错误的借口
因为你也可以选择在应用市场上传指定ABI版本的APK,生成不同ABI版本的APK可以在build.gradle中如下配置:
-
- android {
-
- ...
-
- splits {
- abi {
- enable true
- reset()
- include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
- universalApk true //generate an additional APK that contains all the ABIs
- }
- }
-
- // map for the version code
- project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
-
- android.applicationVariants.all { variant ->
- // assign different version code for each output
- variant.outputs.each { output ->
- output.versionCodeOverride =
- project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0)* 1000000 + android.defaultConfig.versionCode
-
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。