乐趣区

关于android: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-v7a armeabi
Thumb-2
VFPv3-D16
与 ARMv5/v6 设施不兼容。
实用于基于 32 位 ARM 的 CPU,逐步被弃用。
arm64-v8a AArch64 实用于基于 ARMv8-A 的 CPU,反对 64 位 AArch64 架构,以后支流。
x86 x86 (IA-32)
MMX
SSE/2/3
SSSE3
不反对 MOVBE 或 SSE4。
个别是模拟器。
x86_64 x86-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 位有雷同的性能和品质,还须要进行测试。

能够看到这里没有任何 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 文件。

依据我的项目状况,咱们须要对 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 文件夹了

当初曾经反对 64 库,然而是否与 32 位有雷同的性能和品质,还须要进行进一步的检查和测试。

而后通过 gsyVideoPlayer 的援用阐明,咱们能够抉择 com.shuyu:gsyVideoPlayer-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 这三个文件。

能够看到,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 的包。

接下来要在 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 位适配是目前安卓手机利用的支流趋势,做好适配不仅能够投合政策,还能够晋升利用在新机型上的运行效率,尽管国内市场刚刚开始要求,但防止某天因政策影响,导致本人的利用无奈上架,还是早做打算的好~

更多精彩请关注咱们的公众号「百瓶技术」,有不定期福利呦!

退出移动版