ABI是英文Application Binary Interface的缩写,及应用二进制接口。

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

ABI 包含以下信息:

  • 可使用的 CPU 指令集(和扩展指令集)。
  • 运行时内存存储和加载的字节顺序。Android 始终是 little-endian。
  • 在应用和系统之间传递数据的规范(包括对齐限制),以及系统调用函数时如何使用堆栈和寄存器。
  • 可执行二进制文件(例如程序和共享库)的格式,以及它们支持的内容类型。Android 始终使用 ELF。
  • 如何重整 C++ 名称。

Android目前支持以下7种ABIs:

mips, mips64, X86, X86–64, arm64-v8a, armeabi, armeabi-v7a

2. ABI有何作用

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

当我们想要在项目中使用 native(C/C++) 类库,我们必须对要支持的处理器架构提供对应编译包。每个处理器架构需要我们提供一个或多个包含native代码的.so文件。

默认情况下,为了使APP有更好的兼容性,我们使用Android Studio 或者命令打包时,会默认支持所有的架构,但相应的APK size 会疯狂的增大。对于用户来说,目标设备只需要其中一个版本,但当用户下载APK时,会全部下载(对用户来说相当的不友好)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jUFGqBXJ-1637899327939)(//upload-images.jianshu.io/upload_images/3513995-160b8a24eb990449?imageMogr2/auto-orient/strip|imageView2/2/w/248/format/webp)]

怎么办呢?abifilters 为我们提供了解决方案,abifilters为我们提供了选择适配指定CPU架构的能力,只需要在app下的build.gradle添加如下配置:

android {
defaultConfig {
ndk {
abiFilters ‘arm64-v8a’, ‘x86_64’
}
}

}

你可能看了上面的这些文字,还不能理解abi的作用,那么我们就用一个简单的例子来说明一下。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TjsOGPAt-1637899327985)(//upload-images.jianshu.io/upload_images/3513995-f515ba248696d67b?imageMogr2/auto-orient/strip|imageView2/2/w/225/format/webp)]

2.1 举例说明ABI的作用

首先,我们创建一个最简单的Hello world应用,只有一个Activity和一个启动图标。我们看以下打出来的apk:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AwSwr7oK-1637899327986)(//upload-images.jianshu.io/upload_images/3513995-49257d6c6a926f12?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)]

没有任何的原生库使用,大小为2.1MB,现在我们为它添加多ABI原生库支持,我们在项目中集成Realm,然后打包。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQdQA0OB-1637899327987)(//upload-images.jianshu.io/upload_images/3513995-d1ceda3e282d5e03?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)]

看到没,apk大小从2.1MB猛增加到11.2MB,多了一个原生so库的文件夹,大小为8.8MB,我们来看一下它的详细信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kiDAamZ2-1637899327988)(//upload-images.jianshu.io/upload_images/3513995-c2fd754e44e650e2?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)]

如上图所示,Realm为5种CPU架构生成了.so库,分别是mipsx86x86_64arm64-v8aarmeabi-v7a。增加了8.8MB包的大小。但是这不是我们想要的,我们只想要适配我们指定的的CPU架构,因此,我们需要在gralde.build中添加abifilters配置来完成我们想要的效果:

android {
compileSdkVersion 28 // 编译sdk版本
defaultConfig {
applicationId “com.example.zhouwei.helloworld”
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName “1.0”
testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”
// 适配指定CPU架构
ndk {
abiFilters ‘arm64-v8a’, ‘x86_64’
}
}
}

效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bXehoAKK-1637899327989)(//upload-images.jianshu.io/upload_images/3513995-375b25a779c21322?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)]

可以看到,只生成了我们指定CPU架构的so文件,包的大小也减少了5.3MB

这时候,你可能会有一个疑问,Android 共支持7种CPU架构,那么,我们在实际项目中该适配哪些CPU架构能保证最好的兼容,同时又最大限度的减少APK的大小?

在回答这个问题之前,我们不妨看一下这些顶级巨头公司,他们是是如何适配的。

3. 目前大厂APP是如何适配不同的CPU架构的?

首先,我们下载一些大厂的APK,看一下他们的适配情况,这里我分析了微信、手机QQ、支付宝和淘宝这4个APP的适配情况:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kVgvPCgf-1637899327989)(//upload-images.jianshu.io/upload_images/3513995-f1586a34b19fb4bc?imageMogr2/auto-orient/strip|imageView2/2/w/482/format/webp)]

可以看到,微信适配的是arm64-v8a(微信应该是最近才适配到arm64-v8a,以前是armeabi),支付宝和手Q适配的是armwabi,淘宝适配的是armwabi-v7a。各个APP适配的平台不太一样,但是他们有一个共同点,那就是它们只指定了一个平台。

等等,上面这些APP只适配了一中CPU架构,比如只适配了armwabi-v7a,那如果APP装在其他架构的手机上,如arm64-v8a上,会蹦吗?

要弄清楚这个问题,我们得先搞清楚,ABI是如何工作的。

ABI是如何工作的呢?

官方文档解释如下:

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

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

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

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

64 位设备也支持其 32 位变体。以 arm64-v8a 设备为例,该设备也可以运行 armeabi 和 armeabi-v7a 代码。但请注意,如果应用以 arm64-v8a 为目标,而非依赖于运行 armeabi-v7a 版应用的设备,则应用在 64 位设备上的性能要好得多。

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

上面这一段是不是有点看蒙了,这里我来简单解释以下。总的来说,就是一个Android设备可以支持多种ABI,设备主ABI和辅助ABI,以arm64-v8a为主ABI的设备,辅助ABI为armeabi-v7aarmeabi,以armeabi-v7a为主ABI的设备,辅助ABI为armeabi

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

3.1 主辅助ABI具体适配流程

前面说了ABI的工作原理,一个Android设备支持主辅ABI,那么他们具体是如何工作的呢?我们以arm64-v8a架构的手机为例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yReG6lzs-1637899327990)(//upload-images.jianshu.io/upload_images/3513995-acffe78107db6552?imageMogr2/auto-orient/strip|imageView2/2/w/901/format/webp)]

对于一个cpu是arm64-v8a架构的手机,它运行app时,进入jnilibs去读取库文件时,先看有没有arm64-v8a文件夹,如果没有该文件夹,去找armeabi-v7a文件夹,如果没有,再去找armeabi文件夹,如果连这个文件夹也没有,就抛出异常;

如果有arm64-v8a文件夹,那么就去找特定名称的.so文件,注意:如果没有找到想要的.so文件,不会再往下(armeabi-v7a文件夹)找了,而是直接抛出异常。

Exception:Java.lang.UnsatisfiedLinkError: dlopen failed: library “/***.so” not found

特别需要注意的情况是在命中了文件夹,而未命中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了哦。

因此,我们需要在我们的app中配置 abiFilter 配置,来避免一些未知的错误。

defaultConfig {
ndk {
abiFilters “armeabi”// 指定ndk需要兼容的ABI(这样其他依赖包里x86,armeabi,arm-v8之类的so会被过滤掉)
}
}

3.2 Android 7种CPU架构在当前市场的占有率
  • arm64-v8a: 目前主流版本

  • armeabi-v7a: 一些老旧的手机

  • x86 / x86_64: x86 架构的手机都会包含由 Intel 提供的称为 Houdini 的指令集动态转码工具,实现对 arm .so 的兼容,再考虑 x86 1% 以下的市场占有率,x86 相关的两个 .so 也是可以忽略的

  • armeabi/mips / mips64: NDK 以前支持 ARMv5 (armeabi) 以及 32 位和 64 位 MIPS,但 NDK r17 已不再支持,极少用于手机可以忽。

目前手机市场上,x86 / x86_64/armeabi/mips / mips6 的架构,基本可以不不考虑了,它们的占有量应很少很少了,arm64-v8a作为最新一代架构,应该是目前的主流armeabi-v7a只存在少部分老旧手机。

我试着在Google上查找,具体的市场占有数据,但没找到,但是从国民级应用微信只适配arm64-v8a就可以看出,arm64-v8a是目前的主流,并且还有一点,Google Play 从2019年8月开始,就强制APP适配arm64-v8a,以慢慢淘汰32位的armeabi-v7a

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PyTQyIDt-1637899327991)(//upload-images.jianshu.io/upload_images/3513995-e1eceaf02c93e71c?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)]

4. 我们项目中该如何适配呢?

这里就可以回答前面的两个问题了。

Q1: 只适配了armwabi-v7a,那如果APP装在其他架构的手机上,如arm64-v8a上,会蹦吗?

A: 不会,但是反过来会。

因为armwabi-v7aarm64-v8a会向下兼容:

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

那我们该如何适配呢?给出如下几个方案:

方案一:只适配armeabi

  • 优点:基本上适配了全部CPU架构(除了淘汰的mips和mips_64)

  • 缺点:性能低,相当于在绝大多数手机上都是需要辅助ABI或动态转码来兼容

方案二:只适配 armwabi-v7a

同理方案一,只是又筛掉了一部分老旧设备,在性能和兼容二者中比较平衡

方案三: 只适配 arm64-v8

  • 优点: 性能最佳

  • 缺点: 只能运行在arm64-v8上,要放弃部分老旧设备用户

和mips_64)

  • 缺点:性能低,相当于在绝大多数手机上都是需要辅助ABI或动态转码来兼容

方案二:只适配 armwabi-v7a

同理方案一,只是又筛掉了一部分老旧设备,在性能和兼容二者中比较平衡

方案三: 只适配 arm64-v8

  • 优点: 性能最佳

  • 缺点: 只能运行在arm64-v8上,要放弃部分老旧设备用户

Android强行进阶:为何大厂APP如微信,焦虑的移动互联网开发者如何破局相关推荐

  1. 膜拜大佬!焦虑的移动互联网开发者如何破局?成功拿下大厂offer

    开头 很多人说Android开发前景越来越差了 我觉得这个回答是片面的 首先Android应用开发前景差是在最近两年出现的,也就是从2018开始,从那时起移动端的程序员已经慢慢出现供大于求的局面,本人 ...

  2. Android强行进阶:为何大厂APP如微信、支付宝、淘宝、手Q等只适配了armeabi-v7a/armeabi?

    0. 前言 前几天啊,在公众号发了一篇文章<优化ApK大小之ABI Filters 和 APK split>,评论区收到了一些留言说,文章讲得不够深入,关于系统是如何选择不同abi下的so ...

  3. 企业微信发布,看Saas产品的破局与增长逻辑

    昨日上午 10 点,倍受关注的企业微信 1.0 低调上线.企业微信的切入,将给企业服务市场带来怎样的变动?我将从企业服务市场行业的角度出发,给大家带来一些我个人的看法,希望和大家多多交流.本文由人人都 ...

  4. Android强行进阶—按键事件焦点事件攻略

    前言 对于Android手机APP普通开发者来说,KeyEvent接触相对较少,相反接触较多的应该是TouchEvent.而Android TV开发者对KeyEvent的接触就非常频繁.这也是手机应用 ...

  5. Android强行进阶,自定义控件—LayoutManager,android开发视频

    } } if (dx > 0) { if (mHorizontalOffset >= getMaxOffset()) { // 根据最大偏移量来计算滑动到最右侧边缘 mHorizontal ...

  6. Android开发想进大厂?先看看这份国内互联网大厂的薪资、职级、绩效考核一览表

    下表涵盖了国内主要互联网大厂新入职员工各职级薪资: 大厂职级薪资对应关系,图来源:曾加@知乎 上述表格不排除有很极端的收入情况,但至少能囊括一部分同职级的收入.这个表是"技术线"新 ...

  7. 企业微信社群变成“死群”,怎么破局?

    在商家们决定用企业微信后,往往会选择尽快从微信里转移老客.尽量从各个渠道多拉新客.一番操作下来,群多了.人也多了,可麻烦的是他们好像并不活跃,甚至不少都成了「死群」. 那么,在面对「死群」的局面时,商 ...

  8. python人脸检测与微信小程序_python+requests对app和微信小程序进行接口测试

    对于web端和app端的接口测试来说,他们都是通过请求方法,url和传递的body参数进行接口请求,区别web和app的区别就是header请求的不同.不同的地方在于header中的User-Agen ...

  9. python+requests对app和微信小程序进行接口测试

    对于web端和app端的接口测试来说,他们都是通过请求方法,url和传递的body参数进行接口请求,区别web和app的区别就是header请求的不同.不同的地方在于header中的User-Agen ...

最新文章

  1. java spring 配置文件_[Java教程]Spring配置文件
  2. 【3006】统计数字
  3. 【机器学习基础】GBDT--梯度提升树实例分析完全解读
  4. Linux下和Windows下创建Oracle数据库,表空间,Oracle用户
  5. windows当代理服务器-CCProx的使用
  6. 一年中最后一个月的最后一天说说_一年的最后一天说说
  7. 上海音乐学院计算机考研难吗,上海音乐学院考研难吗?一般要什么水平才可以进入?...
  8. saiku+kettle整合(六)olap操作
  9. 操作系统之进程管理:17、死锁
  10. 如何在用户区显示一张位图
  11. BackBone及其实例探究
  12. tensorflow之 feature_column + pre-made estimator组合实战
  13. CADD课程学习(2)-- 靶点晶体结构信息
  14. python之OCR文字识别
  15. Windows 调色板
  16. no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature
  17. 计算机代表的数字,计算机中数的表示
  18. 内存数据库-H2简介与实践
  19. CSAPP Architecture Lab PartC满分
  20. 如何在互联网公司求职成功

热门文章

  1. 架构——自包含系统(SCS)
  2. html5中如何放图片,css怎么放图片?
  3. 黄金跳水如黄鼠狼探亲不怀好意,晚间黄金走势预测分析。
  4. 国内能否炒伦敦金,2023国际十大正规伦敦金交易平台排名
  5. 如何估算网站日承受最大访问PV ,你想建设一个能承受500万PV/每天的网站吗?如果计算呢?
  6. CSS element+element
  7. linux sec是什么类型,SEC 文件扩展名: 它是什么以及如何打开它?
  8. 万维网服务及策略服务 insdicli APPSrv DC1
  9. Mac 版 word文档突然消失之破解之谜
  10. 常见蛋白质种类_关于健身常用的4种蛋白粉