Qigsaw原理
Qigsaw借助Android App Bundle开发套件完成dynamic feature的打包,大大降低Qigsaw开发维护成本。因此Qigsaw关心的重点落在如果安装加载dynamic feature生成apk上。
第三方应用利用PackageInstaller安装split APKs体验极其不友好,且某些国产手机对split APKs功能支持不完善,所以我们最终还是按照一般插件化方式安装加载split APKs。
依据上图,如果需要动态加载split APKs,需要解决代码、资源以及四大组件的加载。
Split APKs代码加载
针对splits代码加载,Qigsaw采用单类加载器方式,即base APK和split APKs采用同一ClassLoader加载。
在DexPathList中,为每个split创建对应的Element
和NativeLibraryElement
实例即可。关于单类加载器更多细节,本文不再赘述,相关原理已非常成熟。
Split APKs资源加载。
Splits资源加载相较于代码加载会复杂,因为不同系统版本或不同手机厂商都会存在一些兼容性问题。
Android Gradle Plugin在资源打包时,会对res
目录下资源文件分配一个唯一Id。
Id前两位PP
为Package Id,代表应用类型。是系统应用、第三方应用、Instant App或Dynamic Feature等。
Id中间两位TT
为Type,代表资源类型。是drawable、layout或string等。
Id后四位EE
为Entry,代表该资源顺序。
所有第三方应用base APK资源Package Id均为7F,Android App Bundle对splits资源打包时会基于7F依次递减分配Package Id。因此,即使我们将split APKs资源添加到当前应用Resources实例中,也不会出现资源冲突问题,splits访问base资源也更加方便。
Instant Apps资源打包是基于7F依次递增。
通过Android App Bundle解决splits资源打包问题,那么splits资源如何加载呢?我们来看一段代码。
Qigsaw提供loadResources
方法加载split APKs资源。为避免开发者写大量模板代码,Qigsaw打包插件采用字节码操作方式自动写入该方法。
Split APKs四大组件加载
Android App Bundle在Manifest文件合并过程中,会将split APKs manifest文件内容合并至base APK中。因此,所有split APKs四大组件信息都是已经声明在base APK中。
Android App Bundle这种处理方式不支持Manifest更新,例如新增四大组件,所以Qigsaw也不支持新增四大组件。在正常开发迭代过程中,动态新增splits四大组件需求极少,所以Qigsaw与Android App Bundle特性保持一致。
Split APKs安装过程
前文我们介绍了Play Core Library是如何安装、加载split APKs,Qigsaw安装、加载split APKs与Play Core Library类似。首先,通过一张图来了解。
在爱奇艺App运行过程中,当X
进程发起安装游戏APK请求时,会经历以下步骤。
X
进程通过Qigsaw Core Library发起游戏APK安装请求。当主进程收到请求后,开始下载并安装游戏APK。
在下载、安装整个过程中,Qigsaw Core Library会将整个过程所有状态返回给爱奇艺App,包括下载进度、安装结果等。
当安装完成以后,爱奇艺App就可以使用游戏APK。
Qigsaw下载、安装split APKs均在主进程处理,split APKs的加载则发生在X
进程。Qigsaw安装、加载split APKs原则是,哪个进程发起split APKs安装请求,就在哪个进程加载split APKs。