为何 Twitter 区别于微信、淘宝,只使用了 armeabi-v7a?

最近在研究APP瘦身,碰巧又遇到armeabi、armeabi-v7a、arm64-v8a等ABI相关的知识点,决心记录下来以作分享。

目前现状

首先我们分析下国内的淘宝、微信,以及国外的Facebook、Twitter都使用了哪些ABI。

我们对这4家APK进行Analyze,可以发现Facebook和Twitter只使用了armeabi-v7a,而微信和淘宝只使用了armeabi,分析结果如下图所示:

大厂并没有按照我们的理解使用不同的ABI针对不同的CPU?其实笔者发现携程、饿了么、百度糯米都是只使用了armeabi,阿里系的淘票票使用了armeabi、x86(如果你有兴趣,可以通过爬取分析一下应用市场的前100名都使用了哪些ABI)。

知识点回顾

首先,我们来看下Google老大哥是怎么介绍的ABI的,翻译官方文档:

不同 Android 手机使用不同的 CPU,因此支持不同的指令集

 

CPU 与指令集的每种组合都有其自己的应用二进制界面(或 ABI) 

ABI 可以非常精确地定义应用的机器代码在运行时如何与系统交互

 

您必须为应用要使用的每个 CPU 架构指定 ABI

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


各版本分析如下: 
- mips / mips64: 极少用于手机可以忽
- x86 / x86_64: x86 架构的手机都会包含由 Intel 提供的称为 Houdini 的指令集动态转码工具,实现对 arm .so 的兼容,再考虑 x86 1% 以下的市场占有率,x86 相关的两个 .so 也是可以忽略的
- armeabi: ARM v5 这是相当老旧的一个版本,缺少对浮点数计算的硬件支持,在需要大量计算时有性能瓶颈
- armeabi-v7a: ARM v7 目前主流版本
- arm64-v8a: 64位支持

具体含义

如果你基础比较好的话,看完Google老大哥的介绍的话,就明白了:不同的 CPU 支持不同的指令集。当我们需要我们APP支持尽可能多的不同CPU的时候,只需要将不同版本的so文件放置在不同的目录下,APK安装运行的时候会根据自己需要而自己选取。

但是这样却带来一个问题,APK文件较大,影响用户下载。

那我们是否可以只放置一些呢?

必然可以!

我们继续看Google老大哥是怎么说的:

  • 为实现最佳性能,应直接针对主要 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//lib.so
  • 如果未找到,并且您已定义辅助 ABI,该服务将扫描以下形式的共享库
    lib//lib.so
  • 找到所需的库时,软件包管理器会将它们复制到应用的 data 目录 (data/data//lib/) 下的/lib/lib.so

分析

上面说,如果根本没有共享对象文件,应用也会构建并安装,但在运行时会崩溃。所以有时候我们遇到

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

此时我们首先要想到的,是不是so文件没有放置,或者是在armeabi放置a.so,b.so,但是在armeabi-v7a只放置了b.so,没有放置a.so。

这里强调一下:虽然arm64-v8a是可以向下兼容的,但是也是兼容的有限制的:

其下有armeabi-v7a,armeabi ;armeabi-v7a向下兼容armeabi。对于一个cpu是arm64-v8a架构的手机,它运行app时,进入jnilibs去读取库文件时,先看有没有arm64-v8a文件夹,如果没有该文件夹,去找armeabi-v7a文件夹,如果没有,再去找armeabi文件夹,如果连这个文件夹也没有,就抛出异常; 如果有arm64-v8a文件夹,那么就去找特定名称的.so文件。
如果有arm64-v8a文件夹,那么就去找特定名称的.so文件,注意:如果没有找到,不会再往下(armeabi-v7a文件夹)找了,而是直接抛出异常。

注意:

  1. 如果没有找到,不会再往下(armeabi-v7a文件夹)找了,而是直接抛出异常。
  2. 如果你的项目用到了第三方依赖,如果只保留一个ABI的时候,建议在Build中加入ndk.abiFilters
  3. 例如:第三方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==了哦。
defaultConfig {  
    ndk {  
        abiFilters "armeabi"// 指定ndk需要兼容的ABI(这样其他依赖包里x86,armeabi,arm-v8之类的so会被过滤掉) 
    }  
}  

总结

  1. 如果你希望APK针对不同CPU有不同的版本,你可以使用胖二进制的方式,在不同的目录下面放置不同的so文件。这样兼容性更广、性能好些,但是APK大些;

  2. 如果你希望APK小一些,你可以像淘宝、微信、FaceBook、Twitter一样,一个api闯天下,至于选择armeabi、armeabi-v7a看你市场用户了。目前主流手机cpu多属于armeabi-v7a;

  3. 当然,你也可以动态检查系统环境,如果是x86就去下载相关库,然后加载......这样可以减少apk体积。


你可能感兴趣的:(Android)