片多多64位升级之路
1.为什么要做?
为了满足厂商的要求和市场趋势,64位的安装包升级无可避免。为了解决片多多在64位机型上的性能和稳定性问题,需要在工程中支持64位安装包,并能准确输出64位包,最后进行精准分发。
2.收益是什么?
- 应用在64位的机器上运行,有专门的64位包,可以让内存分配得更大,应用更好运行,给了应用更广阔的创新空间,经过兼容更多的更新的硬件来提高软件的全体性能
- 基于第一点,应用在64位上运行的crash率会降低
- 合理满足了各商店对于应用上架的要求
3.需要做什么?
- 工程升级至64位
- 流水线改造--增加支持64位打包
- 升级策略精准分发:其中包含商店渠道、应用内升级渠道、分发渠道。
1⃣️商店渠道自带支持:根据用户机型情况判断给用户推送32位或者64位包
2⃣️应用内升级准备支持:根据用户机型情况判断让用户下载32位或者64位包来安装
3⃣️分发渠道:渠道分发目前优先32位包,64位包由升级行为带动
4.不良影响及解决
4.1 有不良影响?
- 64位的包体积会比32位大,且可能大很多
4.2 不良影响的解决方案
- 对应用中使用的各种库采取动态加载方式(需要对不同的第三方库进行梳理,看这些库是否支持)
- 其他的就常规体积优化策略
- 差异化分发,64位与32位包分开提供,为两份安装包
5.64位app运行原理
5.1 什么是64位适配?
64位适配,是指在64位的设备上运行64位的进程。
5.2 如何做到让我们的app运行在64位进程上?
64位的设备所承载的系统有两个Zygote进程(Zygote是在init进程启动时创建的,它又称为孵化器,它可以通过fork(复制进程)的形式来创建应用程序进程和SystemServer进程),一个32位的Zygote,一个64位的Zygote,两者同时运行在系统上。
app在安装进手机的时候,其实是一个解包的过程(apk其实就是一个安装包),解包之后,在本地的文件中会有一个文件夹,名为“lib”。系统的PMS服务(PackageManagerService)就会通过它的scanPackageDirtyLI方法进行遍历lib文件夹下的目录,目录内存放着so库,如下图所示:
库中可能包含了“arm64-v8a”、"armabi"、“armabi-v7a”等文件夹,每个文件夹内都会有对应的so库。PMS根据文件夹列表再结合手机硬件所支持的abilist列表,选择最适合的文件夹下的so加载。这个选择方式最终的结果是输出了一个叫primaryCpuAbi的值。注意:如果PMS决定了一个文件夹之后,其他文件夹它是忽略的。
当app真正启动的时候,ActivityManagerService(ActivityManagerService,以下简称AMS,服务端对象,负责系统中所有Activity、Service的生命周期以及BroadcastReceiver和ContentProvider的管理)根据前边得到的primaryCpuAbi值,调用了进程的start()方法来确定这个app是需要使用64位还是32位的zygote进程来fork出应用进程。若该应用进程是由32位创建,那么则运行在32位进程上,64位同理。
那么,划重点就是,64位的适配其实就是apk中lib文件夹下的so库的适配,java的代码是同一份,无论在64位还是32位上均可运行,而so库则不同,专门适配的版本,无论是性能和效率都会得到更高的发挥。这里要注意一点,一旦运行了64位的进程,那么此时去加载32位的so库,是无法实现的,32位亦然。
6.片多多适配
6.1 包的构建
方案一、构建一个支持所有abi类型的apk。
优点:满足任意机型的安装
缺点:包体积变得特别大,因为是支持的abi数*原本的包体积大小。按照现在片多多的包体积大小为47MB,想要以此方式支持64位的话,包体积将会>94MB。
实现方案:在build.gradle里的ndk中加上相应的abi类型即可
方案二、为每个abi单独构建apk
优点:包体积几乎保持不变
缺点:需要根据不同的情况,下发合适的apk到对应的用户设备上进行安装
方案:在gradle里单独配置不同的buildTypes,然后利用修改脚本,打出不同的包
gradle中的脚本设置如下:
android {
buildTypes {
debug {
// 其他配置
matchingFallbacks = ['debug']
ndk {
abiFilters "armabi"
}
}
debug64 {
// 其他配置
matchingFallbacks = ['debug']
ndk {
abiFilters "arm64-v8a"
}
}
release {
// 其他配置
matchingFallbacks = ['debug']
ndk {
abiFilters "armabi"
}
}
release64 {
// 其他配置
matchingFallbacks = ['debug']
ndk {
abiFilters "arm64-v8a"
}
}
}
}
打包脚本sh文件中的设置如下:
gradle $command"Debug" --stacktrace
gradle $command"Debug64" --stacktrace
gradle $command"Release" --stacktrace
gradle $command"Release64" --stacktrace
最终选择:根据片多多的市场情况,目标用户群体对包体积大小的敏感度很高,所以方案一的包体积大小是无法接受的,那么只能选择方案二。
6.2 升级方案
6.3 流水线的改造
由于目前的请求只支持下发一个安装包的链接,就需要进行改造。根据6.2所示,请求的参数中带上了是否架构的标记,便于后台针对不同的参数进行下发不同的安装包链接。
就这样完成了一键式的集成分发流程
后续要接入:
1、动态化so库下发能力
注意点:
任何接入的库都需要查看是否分别用32位与64的so存在。需要查找64位与32位的so库的区别的,快速方式可以使用以下工具:EasyPrivacy:https://github.com/pengxurui/EasyPrivacy。
使用日志分析即可: