阅读 68

Android 64位架构适配

前言

随着手机硬件的不断发展,近两年的新式手机已经全部采用了 64 位 CPU,64 位真的比 32 位快吗?实际上 32 位和 64 位的差异主要体现在内存寻址上,32 位最高只支撑 4GB 内存,而 64 位则能够最高支撑 128GB 内存。

目前各个应用市场也对 64 位适配提出了要求。

Google Play:

自 2019 年 8 月 1 日起,在 Google Play 上发布的应用必须支持 64 位架构。

国内:

小米应用商店与 OPPO 应用商店、vivo 应用商店等已经发出通知:

  • 2021 年 12 月底:现有和新发布的应用/游戏,需上传包含 64 位包体的 APK 包(支持双包在架,和 64 位兼容 32 位的两个形式,不再接收仅支持 32 位的 APK 包)。

  • 2022 年 8 月底:硬件支持 64 位的系统,将仅接收含 64 位版本的 APK 包。

  • 2023 年底:硬件将仅支持 64 位 APK,32 位应用无法在终端上运行。

华为应用商店:

  • 2022 年 2 月 1 日起,在华为应用市场新上架/升级的游戏及应用,必须包含 64 位版本,华为应用市场不再接收仅包含 32 位版本的应用。

  • 2022 年 9 月 1 日起,华为应用市场将不再接收包含 32 位版本的应用。

Android ABI

不同的 Android 设备使用不同的 CPU,而不同的 CPU 支持不同的指令集。CPU 与指令集的每种组合都有专属的应用二进制接口 (ABI)。

Android 设备支持的 ABI 类型如下:

ABI支持的指令集备注
armeabi-v7aarmeabi
Thumb-2
VFPv3-D16
与 ARMv5/v6 设备不兼容。
适用于基于 32 位 ARM 的 CPU,逐渐被弃用。
arm64-v8aAArch64适用于基于 ARMv8-A 的 CPU,支持 64 位 AArch64 架构,当前主流。
x86x86 (IA-32)
MMX
SSE/2/3
SSSE3
不支持 MOVBE 或 SSE4。
一般是模拟器。
x86_64x86-64
MMX
SSE/2/3
SSSE3
SSE4.1、4.2
POPCNT
一般是模拟器。

这里主要看 arm 架构的,新的架构能够兼容旧的 abi 对应的 so,例如 arm64-v8a 架构的 CPU 能够运行 armeabi-v7a 架构的 so,反过来不行,这就是为什么现在很多 APP 只包含 armeabi-v7a 的包却能够在最新的 CPU 上运行。如果以后的 CPU 不再兼容旧的架构了的话,现在只包含 armeabi 或者 armeabi-v7a 架构的 APP 就不能再运行了。

如果应用同时包含了两种架构,应用运行时会有两个 Zygote (一个 32 位,一个 64 位)进程同时运行。APP 安装的时候根据 lib 目录里面支持的架构和机器自己的 CPU 类型来决定 primaryCpuAbi,在启动的时候会根据安装时候确定的 primaryCpuAbi 的值来决定是从 64 位还是 32 位的 Zygote 进程 fork 出子进程,如果从 64 的 fork,则是以 64 位模式运行。

由于一些软件功能越来越多,安装包的体积、运行时需要消耗的运行内存越来越大,32 位应用的局限性越来越突出。而 64 位系统,可以在单个线程里使用超过4GB 的运行内存,当处理一些大型软件、或者进行高像素图像、视频处理的时候,就更能够发挥手机硬件的优势。比如一些大型游戏、网络视频直播、高画质影音播放等等。而且 64 位系统相比 32 位系统,会带来至少 20% 效率的提升。

查看自己的应用是否支持 64 位架构

关于如何检索 APK 中不支持 64 位 的 so 文件,官方提供了两种方法,具体可参考

其中比较简单的方法就是通过 Android Studio 提供的 APK 分析工具,查看 lib 文件夹,如果里面只有 armeabi 或者 armeabi-v7a 文件夹,就是只支持 32 位,不支持 64 位。 如果同时还有 arm64-v8a 文件夹,则说明有 64 位原生库,是否与 32 位有相同的功能和质量,还需要进行测试。

只支持32位的Apk

可以看到这里没有任何 arm64-v8ax86_64 库,则需要更新构建流程以开始构建并打包 APK 中的这些工件。

应用内的原生库的来源一般有三处:

  • 第三方库

  • 工程内的 so 文件

  • C/C++ 源码模块

目前很多第三方库已经同时支持 32 和 64 位了,但是有些还不支持,如何找出这部分不支持的库或者文件呢?如果项目中的 .so 文件数量很多,就很难通过肉眼的方式来查找。

我们可以通过 gradle 脚本或者一些现有三方框架,对项目打包过程中 mergeReleaseNativeLibs (mergeDebugNativeLibs 也可以,根据自己情况选择)  这个 Task 来进行 .so 文件的检索,通过判断每个 .so 文件的路径中是否包含 "aremeabi-v7a"、"arm64-v8a"、"x86"、"x86_64" 等名称来判断 .so 的类型。

核心代码

void apply(Project project) {     project.afterEvaluate {         // 1. Find the task merge[BuildVariants]NativeLibs         Task mergeNativeTask = null         for (Task task : project.getTasks()) {             if (task.name.startsWith("merge") && task.name.endsWith("NativeLibs")) {                 mergeNativeTask = task             }         }         if (null == mergeNativeTask) {             return         }         // 2. Create detect task.         project.getTasks().create("support 64-bit abi") {             group "privacy"             dependsOn mergeNativeTask             doFirst {                 println "EasyPrivacy => Support 64-bit abi start."                 SoFileList soList = new SoFileList()                 // 2.1 Find so file recursively.                 mergeNativeTask.inputs.files.each { file ->                     findSoFile(file, soList)                 }                 // 2.2 Print 64-bit abi supported status.                 soList.printlnResult()             }         }     } } /**  * Find so file recursively.  */ void findSoFile(File file, SoFileList soList) {     if (null == file) {         return     }     if (file.isDirectory()) {         // recursively         file.listFiles().each {             findSoFile(it, soList)         }     } else if (file.absolutePath.endsWith(".so")) {         println "EasyPrivacy => so: ${file.absolutePath}"         SoFile so = generateSoInfo(file)         if (so.soPath.contains("armeabi-v7a")) {             soList.armeabiv_v7a.add(so)         } else if (so.soPath.contains("armeabi")) {             soList.armeabi.add(so)         } else if (so.soPath.contains("arm64-v8a")) {             soList.arm64_v8a.add(so)         } else if (so.soPath.contains("x86_64")) {             soList.x86_64.add(so)         } else if (so.soPath.contains("x86")) {             soList.x86.add(so)         } else if (so.soPath.contains("mips64")) {             soList.mips_64.add(so)         } else if (so.soPath.contains("mips")) {             soList.mips.add(so)         }     } } 复制代码

这里我们使用一个已经封装好的 gradle 插件 ,EasyPrivacy 通过集成和使用后,检测出项目中,尚未进行 arm64-v8a 适配的 .so 文件。

EasyPrivacy检测结果

根据项目情况,我们需要对 in armeabiv-v7a, but not in arm64-v8a 的 .so 文件进行适配

通过分析我们可以看到   jetified-gsyVideoPlayer-armv7a-8.0.0:libijkffmpeg.so 、jetified-gsyVideoPlayer-armv7a-8.0.0:libijkplayer.so 、jetified-gsyVideoPlayer-armv7a-8.0.0:libijksdl.so 、 一共3个 .so 需要我们去适配。

64 位适配修改

首先我们要将打包配置进行修改:

ndk { // 选择要添加的对应 cpu 类型的 .so 库,多个abi以“,”分隔。     abiFilters "armeabi-v7a"     // 可指定的值为 'armeabi-v7a', 'arm64-v8a', 'armeabi', 'x86', 'x86_64', } 复制代码

改为:

ndk {     abiFilters "armeabi-v7a", "arm64-v8a" } 复制代码

这时再进行打包就可以看到 arm64-v8a 的 .so 文件夹了

支持32/64的Apk

现在已经支持 64 库,但是是否与 32 位有相同的功能和质量,还需要进行进一步的检查和测试。

然后通过 gsyVideoPlayer 的引用说明,我们可以选择 com.shuyu:gsyVideoPlayer-arm64 的版本进行接入,接入修改后,重新进行检测:

引入arm64后的检测

我们发现下方的提示并没有消失:

so in armeabiv-v7a, but not in arm64-v8a: [jetified-gsyVideoPlayer-armv7a-8.0.0:libijkffmpeg.so] [jetified-gsyVideoPlayer-armv7a-8.0.0:libijkplayer.so] [jetified-gsyVideoPlayer-armv7a-8.0.0:libijksdl.so] 复制代码

不用紧张,这里是因为三方库命名的问题,通过上图中的  arm64-v8a size  观察到 size 的值已经由原来的 52 变为了 55,接着我们去对应的apk里检查一下,在 arm64-v8a 文件夹下是否有 libijkffmpeg.so 、libijkplayer.so 、libijksdl.so 这三个文件。

Apk 分析

可以看到,64 位支持的三方 .so 文件已经成功引入了。

虽然把所有支持的 abi 的 so 都打在一个包里,可以用来适配所有设备,但缺点就是包体积会增大,特别是原生库比较多的情况。 如果是 Google 市场的应用包,可以使用 Android App Bundle 来减小体积。但是国内的应用市场暂不支持,不过国内的部分应用市场提供了分别上传 32 位兼容包和 64 位包的能力,所以可以利用构建多个 APK 的能力来打出支持不同 abi 的包,应用市场根据用户手机 CPU 类型分发对应的包,可以减少用户下载包的大小。

splits {     abi {         enable true //是否在这个范围分裂         reset() //重新设置 split 配置。         include 'armeabi-v7a', 'arm64-v8a'//包含哪些架构类型。         universalApk false  //是否创建所有可用的 ABIs 一个 APK。     } } 复制代码

然后执行 assembleRelease 这个 task 进行打包,可以在指定目录下看到产出了不同 abi 的包。

不同abi的包

接下来要在 64 位手机、32 位手机上进行分别进行功能测试,如何查看自己的手机 CPU 类型呢,可以通过 adb 命令来查看:

adb shell getprop ro.product.cpu.abi arm64-v8a 复制代码

命令行中执行 adb shell getprop ro.product.cpu.abi  如果输出 arm64-v8a 则代表该手机 CPU 类型为 64 位。

如果功能测试无误后,即可根据应用市场上传要求进行 Apk 包上传 上传应用市场

小结

64 位适配是目前安卓手机应用的主流趋势,做好适配不仅可以迎合政策,还可以提升应用在新机型上的运行效率,虽然国内市场刚刚开始要求,但避免某天因政策影响,导致自己的应用无法上架,还是早做打算的好~


作者:百瓶技术
链接:https://juejin.cn/post/7054094260236189710


文章分类
ANDROID
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐