早期的Android系统差点儿仅仅支持ARMv5的CPU架构,你知道如今它支持多少种吗?7种。

Android系统眼下支持以下七种不同的CPU架构:ARMv5。ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起),每一种都关联着一个相应的ABI。

应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)怎样执行在相应的系统平台上。从使用的指令集,内存对齐到可用的系统函数库。

在Android系统上。每一个CPU架构相应一个ABI:armeabi,armeabi-v7a,x86。mips,arm64-v8a,mips64,x86_64。

1.为什么你须要重点关注.so文件

假设项目中使用到了NDK,它将会生成.so文件,因此显然你已经在关注它了。假设仅仅是使用Java语言进行编码,你可能在想不须要关注.so文件了吧,由于Java是跨平台的。

但其实,即使你在项目中仅仅是使用Java语言,非常多情况下,你可能并没有意识到项目中依赖的函数库或者引擎库里面已经嵌入了.so文件,并依赖于不同的ABI。

比如,项目中使用RenderScript支持库,OpenCV。Unity,android-gif-drawable,SQLCipher等,你都已经在生成的APK文件里包括.so文件了。而你须要关注.so文件。

Android应用支持的ABI取决于APK中位于lib/ABI文件夹中的.so文件。当中ABI可能是上面说过的七种ABI中的一种。

Native Libs Monitor 这个应用能够帮助我们理解手机上安装的APK用到了哪些.so文件,以及.so文件来源于哪些函数库或者框架。

当然。我们也能够自己对app反编译来获取这些信息,只是相对麻烦一些。

非常多设备都支持多于一种的ABI。比如ARM64和x86设备也能够同一时候执行armeabi-v7a和armeabi的二进制包。

但最好是针对特定平台提供相应平台的二进制包。这样的情况下执行时就少了一个模拟层(比如x86设备上模拟arm的虚拟层),从而得到更好的性能(归功于近期的架构更新,比如硬件fpu。很多其它的寄存器,更好的向量化等)。

我们能够通过Build.SUPPORTED_ABIS得到依据偏好排序的设备支持的ABI列表。但你不应该从你的应用程序中读取它,由于Android包管理器安装APK时,会自己主动选择APK包中为相应系统ABI预编译好的.so文件,假设在相应的lib/ABI文件夹中存在.so文件的话。

2.App中可能出错的地方

处理.so文件时有一条简单却并不知名的重要法则。

你应该尽可能的提供专为每一个ABI优化过的.so文件,但要么全部支持。要么都不支持:你不应该混合着使用。你应该为每一个ABI文件夹提供相应的.so文件。

当一个应用安装在设备上。仅仅有该设备支持的CPU架构相应的.so文件会被安装。

在x86设备上,libs/x86文件夹中假设存在.so文件的话。会被安装,假设不存在,则会选择armeabi-v7a中的.so文件。假设也不存在,则选择armeabi文件夹中的.so文件(由于x86设备也支持armeabi-v7a和armeabi)。

3.其它地方也可能出错

当你引入一个.so文件时,不止影响到CPU架构。我从其它开发人员那里能够看到一系列常见的错误,当中最多的是"UnsatisfiedLinkError","dlopen: failed"以及其它类型的crash或者低下的性能:

使用android-21平台版本号编译的.so文件执行在android-15的设备上

使用NDK时。你可能会倾向于使用最新的编译平台,但其实这是错误的,由于NDK平台不是后向兼容的,而是前向兼容的。推荐使用app的minSdkVersion相应的编译平台。

这也意味着当你引入一个预编译好的.so文件时,你须要检查它被编译所用的平台版本号。

4.混合使用不同C++执行时编译的.so文件

.so文件能够依赖于不同的C++执行时,静态编译或者动态载入。混合使用不同版本号的C++执行时可能导致非常多奇怪的crash,是应该避免的。

作为一个经验法则。当仅仅有一个.so文件时,静态编译C++执行时是没问题的,否则当存在多个.so文件时。应该让全部的.so文件都动态链接同样的C++执行时。

这意味着当引入一个新的预编译.so文件,并且项目中还存在其它的.so文件时。我们须要首先确认新引入的.so文件使用的C++执行时是否和已经存在的.so文件一致。

5.没有为每一个支持的CPU架构提供相应的.so文件

这一点在前文已经说到了,但你应该真的特别注意它,由于它可能发生在根本没有意识到的情况下。

比如:你的app支持armeabi-v7a和x86架构。然后使用Android Studio新增了一个函数库依赖,这个函数库包括.so文件并支持很多其它的CPU架构,比如新增android-gif-drawable函数库:

compile ‘pl.droidsonroids.gif:android-gif-drawable:1.1.+’

公布我们的app后,会发现它在某些设备上会发生Crash,比如Galaxy S6,终于能够发现仅仅有64位文件夹下的.so文件被安装进手机。

解决方式:又一次编译我们的.so文件使其支持缺失的ABIs,或者设置

ndk.abiFilters

显示指定支持的ABIs。

最后一点: 假设你是一个SDK提供者,但提供的函数库不支持全部的ABIs。那你将会搞砸你的用户,由于他们能支持的ABIs必将仅仅能少于你提供的。

将.so文件放在错误的地方

我们往往非常easy对.so文件应该放在或者生成到哪里感到困惑,以下是一个总结:

  • Android Studio工程放在jniLibs/ABI文件夹中(当然也能够通过在build.gradle文件里的设置jniLibs.srcDir属性自己指定)
  • Eclipse工程放在libs/ABI文件夹中(这也是ndk-build命令默认生成.so文件的文件夹)
  • AAR压缩包中位于jni/ABI文件夹中(.so文件会自己主动包括到引用AAR压缩包的APK中)
  • 终于APK文件里的lib/ABI文件夹中
  • 通过PackageManager安装后,在小于Android 5.0的系统中,.so文件位于app的nativeLibraryPath文件夹中;在大于等于Android 5.0的系统中,.so文件位于app的nativeLibraryRootDir/CPU_ARCH文件夹中。

仅仅提供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等等)。

以降低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
}
}
}

关于Android的.so文件所须要知道的的更多相关文章

  1. Linux内核:关于中断你须要知道的

    1.中断处理程序与其它内核函数真正的差别在于,中断处理程序是被内核调用来对应中断的,而它们执行于中断上下文(原子上下文)中,在该上下文中执行的代码不可堵塞. 中断就是由硬件打断操作系统. 2.异常与中 ...

  2. 在Linux终端管理文件你要知道的11个命令

    LS - 列表文件 ls命令列出目录中的文件. 默认情况下,使用ls列出当前目录下的文件. 2 你也可以列出文件递归-也就是说,列出所有文件在当前目录中的目录-使用ls -R.LS还可以列出在其他目录 ...

  3. 每一个JavaScript开发者都应该知道的10道面试题

    JavaScript十分特别.而且差点儿在每一个大型应用中起着至关关键的数据.那么,究竟是什么使JavaScript显得与众不同,意义非凡? 这里有一些问题将帮助你了解其真正的奥妙所在:   1.你能 ...

  4. Android AndroidManifest 清单文件以及权限具体解释

    每一个Android应用都须要一个名为AndroidManifest.xml的程序清单文件,这个清单文件名称是固定的而且放在每一个Android应用的根文件夹下.它定义了该应用对于Android系统来 ...

  5. android 上传文件

    android对于上传文件,还是非常easy的,和java里面的上传都是一样的,基本上都是熟悉操作输出流和输入流!另一个特别重要的就是须要一些content-type这些參数的配置!  假设这些都弄好 ...

  6. Android 程序员必须知道的 53 个知识点

    1. android 单实例运行方法 我们都知道 Android 平台没有任务管理器,而内部 App 维护者一个 Activity history stack 来实现窗口显示和销毁,对于常规从快捷方式 ...

  7. 为什么 Android Studio 工程文件夹占用空间这么大?我们来给它减减肥

    偶然中发现Android Studio的工程文件夹比ADT Bundle的大很多.用Android Studio新建一个空工程,工程文件夹大小为30M,运行一次后大小为40M.同样用ADT Bundl ...

  8. android 打开各种文件(setDataAndType)转:

    android 打开各种文件(setDataAndType) 博客分类: android-->非界面 android 打开各种文件 setDataAndType action动作  转自:htt ...

  9. 如何查看Android的Keystore文件的SHA1值

    像使用百度地图api时候,一般需要获取keystore的SHA1值,这里就手把手教大家如何查看Android的keystore文件中的SHA1值. 第一步: 打开cmd,切换到keystore所在的文 ...

随机推荐

  1. Android——隐藏输入法的小技巧

    今天偶然在百度地图提供的DEMO里看到这样一段代码.认为确实是个小技巧,就写下来分享一下. 针对的问题: 我们在开发android界面的时候,常常使用EditText控件.然后每次进入这个页面的时候, ...

  2. Android应用之——微信微博第三方sdk登录分享使用过程中的一些常见问题

    前言 近期在使用第三方登录和分享的过程中遇到了非常多问题,一方面能够归结为自己经验的不足,还有一方面事实上也说明了官方文档的含糊不清.这篇博文不会写关于怎样使用第三方登录分享,由于官方文档已经写明了步 ...

  3. MyEclipse2015安装SVN插件

    一.下载SVN插件subclipse 下载地址:http://subclipse.tigris.org/servlets/ProjectDocumentList?folderID=2240 在打开的网 ...

  4. 风暴英雄 http 302重定向 正在等待游戏模式下载完成

    抓包 在抓到的数据包里面,看到一个http get请求,右键选中,然后follow stream wireshark自动进行数据包过滤tcp.stream eq 1340,并且可以看到完整的数据通讯 ...

  5. 读取excel模板填充数据 并合并相同文本单元格

    try             { string OutFileName = "北京市国控企业污染源废气在线比对监测数据审核表" + DateTime.Now.ToString(& ...

  6. 英语发音规则---X字母

    英语发音规则---X字母 一.总结 一句话总结: 1.x位于词尾或音节尾部,读/ks/? box /bɒks/ n.盒; 箱状物 fix /fɪks/ vt.固定 fox /fɒks/ n.狐; 狐狸 ...

  7. UIimageView和UIimage的小区别

    UIimageView 用来显示一张图片或者显示一组动画图片 UIimage        不是一个控件,只是一个普通的类,用来生成一张图片,只单纯的生成一张图片,图片只会被加载到内存,如果想要让用户 ...

  8. android夜间模式切换

    1.记录个最简单的夜间模式的实现 2.styles.xml <style name="DayTheme" parent="AppTheme"> &l ...

  9. js禁止

    很多时候需要用到js禁止相关的代码: function prohibit() { // 禁止右键 $(document).ready(function() { $(document).bind(&qu ...

  10. 陆、jq基础语法

    一.概述:更加方便的处理html文档.events事件.动画效果和ajax交互等. 1.jq主要功能: (1)访问页面框架的局部. (2)修改页面表现 (3)更改页面的内容 (4)响应事件 (5)为页 ...