Qigsaw是爱奇艺开源的对Android App Bundle(aab)方案的实现,利用aab,应用可以在运行时下载和加载所需要的能力,很多App都需要这种动态化能力。
Google近年来一直在收紧私有API,厂商也会对私有API做自己的定制,国内的不少动态化方案由于使用了私有API导致各种兼容性问题(不同厂商ROM API实现不同兼容问题、不同系统版本API变更兼容问题),维护成本高,前景不明朗。而aab方案是Google官方给出的动态化方案,必然会得到长期稳定的支持,是Android动态化未来的方向。
国内由于没有Google Play,而且play service相关代码不开源,无法直接使用Google提供的aab解决方案。Qigsaw提供了“山寨”方案,参考play service(怎么参考的?应该是反编译后梳理吧。。。)实现方案自己实现了一套支持aab的框架并开源,让国内开发者可以下发aab进行动态更新,也让大家不用啃反编译过来的play service代码,就能探索aab实现原理。
源码结构
https://github.com/iqiyi/Qigsaw
Qigsaw下载下来,是一个标准gradle工程,先看看settings.gradle,确定下参与编译的有哪些module:
include ':app','downloader'
include ':java', ':assets', ':native'
include ':splitcore', ':playcorelibrary', ':splitcommon'
include ':splitinstaller', ':splitdownloader', ':splitloader'
include ':splitrequester', ':splitreporter', ':splitextension'
project(':assets').projectDir = new File("./features/assets")
project(':java').projectDir = new File("./features/java")
project(':native').projectDir = new File("./features/native")
project(':splitcore').projectDir = new File("./qigsaw-android/splitcore")
project(':playcorelibrary').projectDir = new File("./qigsaw-android/playcorelibrary")
project(':playcorelibrary').projectDir = new File("./qigsaw-android/playcorelibrary")
project(':splitinstaller').projectDir = new File("./qigsaw-android/splitinstaller")
project(':splitdownloader').projectDir = new File("./qigsaw-android/splitdownloader")
project(':splitloader').projectDir = new File("./qigsaw-android/splitloader")
project(':splitrequester').projectDir = new File("./qigsaw-android/splitrequester")
project(':splitreporter').projectDir = new File("./qigsaw-android/splitreporter")
project(':splitcommon').projectDir = new File("./qigsaw-android/splitcommon")
project(':splitextension').projectDir = new File("./qigsaw-android/splitextension")
这是个全部依赖Qigsaw源码构建的示例工程。
- 其中Qigsaw库源码位于 qigsaw-android 目录下,被分成了多个模块(其中 playcorelibrary 被定义了两次,应该是个小bug,但不影响);
- 业务模块包括app, java, assets, native,其中app是宿主模块,其他的都是可动态下发的feature模块。
- 此外还包括了Qigsaw的gradle plugin,位于buildSrc目录下
- 源码通过 buildSrc/src/main/resources/META-INF/gradle-plugins/ 导出了两个Plugin
- com.iqiyi.qigsaw.application
- com.iqiyi.qigsaw.dynamicfeature
- 在app模块的build.gradle中,可以看到 apply plugin: ‘com.iqiyi.qigsaw.application’
- 在feature模块的build.gradle中,可以看到 apply plugin: ‘com.iqiyi.qigsaw.dynamicfeature’
- 源码通过 buildSrc/src/main/resources/META-INF/gradle-plugins/ 导出了两个Plugin
此外,工程里还有个没参与编译的独立的工程:qigsaw-android-sample,这是个让用户直接参考使用的工程,可以单独用Android studio打开这个目录,这里面没有配置qigsaw的源码依赖,而是直接依赖了编译好的gradle库。分析gradle源码时,不需要关注它。
Qigsaw gradle plugin分析
QigsawAppBasePlugin
tasks
按照执行顺序,梳理一下各个gradle task做的事情:
- QigsawProcessManifestTask
- 替换Manifest中的Provider名称
- com.iqiyi.qigsaw.sample.java.JavaContentProvider_Decorated_java
- 问题:_java算是怎么回事?需要check下
- com.iqiyi.qigsaw.sample.java.JavaContentProvider_Decorated_java
- 替换Manifest中的Provider名称
- ExtractTargetFilesFromOldApk
- 将上次生成的apk中的 assets/qigsaw/** 拷贝到qigsaw/out-apk/
- GenerateQigsawConfig
- 生成Qigsaw的QigsawConfig.java配置文件
- ProcessSplitApkTask
- 生成Qigsaw的split apk相关信息,qigsaw/split-outputs/
- CreateSplitDetailsFileTask
- 生成Qigsaw的split汇总信息,qigsaw/split-details/
- SplitBaseApkForABIsTask
- 支持多ABI,为每个ABI生成一个产物,当只有一个ABI时(国内基本都只有一个ABI),什么都不做