热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

为何大厂APP如微信、支付宝、淘宝、手Q等只适配了armeabiv7a/armeabi?

为何大厂APP如微信、支付宝、淘宝、手Q等只适配了armeabi-v7aarmeabi?-文章首发于公众号「技术最TOP」,每天都有干货文章持续更新,可以微信搜索「技术最TOP」第

文章首发于公众号「 技术最TOP 」,每天都有干货文章持续更新,可以微信搜索「 技术最TOP 」第一时间阅读!

0. 前言

前几天啊,在公众号发了一篇文章《优化ApK大小之ABI Filters 和 APK split》,评论区收到了一些留言说,文章讲得不够深入,关于系统是如何选择不同abi下的so库的?当前APP该如何适配?该去掉哪些该保留哪些?都存在一些疑问。

因此,决定亲自更文一篇,系统地讲一下关于Android CPU架构方面的一些东西,以及结合大厂APP如微信、支付宝、淘宝等APP的适配情况,分析我们开发APP中该如何适配。本文涉及以下几个问题:

  • 什么是ABI?
  • ABI有何作用?
  • 目前大厂APP是如何适配不同的CPU架构的?
  • ABI 是如何工作的?
  • 我们自己的APP中该如何适配?
  • ABI split-性能+兼容全都要

本篇文章中,就一一为你解答这些疑问。

1. 什么是ABI?

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有何作用?

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

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

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

android {
        defaultConfig {
            ndk {
                abiFilters 'arm64-v8a', 'x86_64'
            }
        }
    
}

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

2.1 举例说明ABI的作用

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

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

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

如上图所示,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'
        }
    }
}

效果如下:

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

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

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

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

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

可以看到,微信适配的是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架构的手机为例:

对于一个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

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上,要放弃部分老旧设备用户

这三种方案都是可以的,现在的大厂APP适配中,这三种都有,大部分是前2种方案。具体选哪一种就看自己的考量了,以性能换兼容就arm64-v8,以兼容换性能armeabi,二者稍微平衡一点的就armwabi-v7a

目前来说,大多数的大厂APP用的都是armeabiarmwabi-v7a,只有像微信这种牛逼的APP,为了追求性能和用户体验,放弃了少部分设备,这也说得通吧,毕竟微信也不在乎苍蝇那点肉。

5.番外篇-性能+兼容能否兼得?

其实到上一小节,本文就该结束了,但总感觉优点意犹未尽,除了适配所有全部CPU架构外,就特么不能性能和兼容同时兼得吗?其实Google早有考虑。也是可以实现的那就是 abi split,分包,实现也很简单,在gradle 中添加如下配置:

 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
        }
      }
    }

然后,就能为每个CPU架构单独打一个APK,该apk 中就只包含一个平台,如下:

这样,又能保证性能,又能不额外增加APK的大小,同时又又很完美的兼容,因为可以为所有架构都单独打一个包,一举多得。

同时,Google Play 支持上传多个APK:

这样,就能根据不同的CPU架构,下载不同的包啦!

但是,但是,但是,很遗憾,国内的应用商店目前还不支持!

参考文章

  • https://www.diycode.cc/topics...
  • https://developer.android.com...
  • https://android.jlelse.eu/con...

以上就是本文的全部内容,如有错误,欢迎评论区指出。原创不易,如果你喜欢本文,欢迎点赞、转发、收藏三连一下。


推荐阅读
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
author-avatar
aaa
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有