Android插件化(二、开源插件化框架Qigsaw)

Android app bundle(aab)

aab是谷歌提出的动态发布方案,是一种改进的应用程序打包方案,可以大幅度减少应用程序体积。

优点

size更小
安装更快
支持动态发布

限制

仅限于通过Google Play发布的应用
最低支持Android 5.0
低于Android5.0的Google会优化大小,但是不支持动态交付
Android插件化(二、开源插件化框架Qigsaw)_第1张图片

Android app bundle(aab 原理)

Android插件化(二、开源插件化框架Qigsaw)_第2张图片
Android插件化(二、开源插件化框架Qigsaw)_第3张图片
Android插件化(二、开源插件化框架Qigsaw)_第4张图片

已知问题:

  • 不支持动态修改 resource tables
  • 在 dynamic feature 模块的清单文件里,不能引用不在 base 模块里的资源
  • 在 AS 中,更改 base 模块的 build variant,并不会自动更改依赖 base 的其他模块,所以构建时可能会报错
  • 不同模块 build configuration 不同,可能会有冲突,导致构建或运行时出错,比如 buildTypes.release.debuggable = true
  • 由于 AAB 可能包含多个 apk 文件,所以在把 apk 发送到设备时可能会因找不到资源,导致运行时异常,比如 adb刷机( sideloading )
  • 动态下载模块需要安装最新的 Play Store app,所以有很小概率下载 app 时会回滚为下载一个 multi-APK(为 Android 4.4以下设备提供)

spilt apks

Android App Bundle之所以能够支持应用运行期间安装dynamic feature,得益于Android 5.0推出的Split APKs功能。
具体可以参照官方文档:spilt apks
Split APKs加载
应用进程所使用到的ClassLoader和Resources均在LoadedAPK中创建。
通过Android 9.0 LoadedAPK源码片段,一起了解下Split APKs加载过程。
Android插件化(二、开源插件化框架Qigsaw)_第5张图片
Android插件化(二、开源插件化框架Qigsaw)_第6张图片

Qisaw 原理

由于国内无法使用Google Play商店,开发者即使将app打包成AAB格式也无法将其拆解下发到客户端。所以Qigsaw利用AAB开发套件,“山寨”Play Core Library公开接口实现,
支持AAB所有功能特性,给开发者带来原生般的极速开发体验。Qigsaw的核心优势如下:

(1)使用AAB原生的开发套件,带来极速的开发体验。
(2)支持AAB所有功能特性,"山寨"Play Core Library公开接口实现,开发者可直接阅读Google官方文档进行开发。
(3)任何进程均可动态加载插件,支持Android四大组件动态加载。
(4)如果您的应用有出海需求,可无缝切换至Android App Bundle方案,无需进行二次开发。
(5)仅一处Hook(Android9.0+无需Hook),少量私有API访问,保证框架稳定性。

Qigsaw借助Android App Bundle开发套件完成dynamic feature的打包,大大降低Qigsaw开发维护成本。因此Qigsaw关心的重点落在如何安装加载dynamic feature生成apk上。
Android插件化(二、开源插件化框架Qigsaw)_第7张图片
依据上图,如果需要动态加载split APKs,需要解决代码、资源以及四大组件的加载。

Split APKs代码加载

针对splits代码加载,Qigsaw 提供两种加载方式加载插件 apk,MULTIPLE_CLASSLOADER 加载方式指
每个插件由独立 ClassLoader 加载,SINGLE_CLASSLOADER 指所有插件由同一 ClassLoader 加载(涉及私有 Api 访问)。
,即base APK和split APKs采用同一ClassLoader加载。
在DexPathList中,为每个split创建对应的Element和NativeLibrary在DexPathList实例即可
Android插件化(二、开源插件化框架Qigsaw)_第8张图片

Split APKs资源加载

Splits资源加载相较于代码加载会复杂,因为不同系统版本或不同手机厂商都会存在一些兼容性问题。
Android插件化(二、开源插件化框架Qigsaw)_第9张图片
Android Gradle Plugin在资源打包时,会对res目录下资源文件分配一个唯一Id。
所有第三方应用base APK资源Package Id均为7F,Android App Bundle对splits资源打包时会基于7F依次递减分配Package Id。
因此,即使我们将split APKs资源添加到当前应用Resources实例中,也不会出现资源冲突问题,splits访问base资源也更加方便。
Android插件化(二、开源插件化框架Qigsaw)_第10张图片
通过Android App Bundle解决splits资源打包问题,那么splits资源如何加载呢?
通过Qigsaw 打包插件中的SplitResourcesLoaderTransform任务,该任务作用是
将插件 AndroidManifest.xml 文件记录的 Activity、Service、Receiver 等所有
class 文件插入对应的 SplitInstallHelper#loadResources(…) 方法,到达访问插件资源目的。

Split APK so加载

通过Qigsaw 打包插件中的SplitLibraryLoaderTransform任务加载。PlayCoreLibrary 提供 SplitInstallHelper#loadLibrary(…) 用于访问插件 so 文件。
Android插件化(二、开源插件化框架Qigsaw)_第11张图片

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特性保持一致。
ContentProvider 为每个 ContentProvider 创建名为 providerName + “Decorated” + splitName 的代理类,其中 providerName 为原始 provider 类名,splitName
为插件 apk 对应的名称,并且该类继承 SplitContentProvider.可以看到,Activity, Service, BroadcastReceiver 的处理都是为了解决资源访问问题,而ContentProvider 的处理​​,
是替换成代理类,这么做的原因是在 app 启动时 ContentProvider 的执行时机是比较靠前的:ContentProvider 的初始化位于 Application 的attachBaseContext和 onCreate之间,
在这个过程中插件 apk 并没有加载进来,一定会报 ClassNotFound。所以将插件 apk 的 provider 生成一个代理类,然后替换掉,如果插件没有加载进来,代理类什么也不执行即可。

Split APKs安装过程

Android插件化(二、开源插件化框架Qigsaw)_第12张图片

你可能感兴趣的:(插件化,android,java,apache)