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:

  1. include ':app','downloader'
  2. include ':java', ':assets', ':native'
  3. include ':splitcore', ':playcorelibrary', ':splitcommon'
  4. include ':splitinstaller', ':splitdownloader', ':splitloader'
  5. include ':splitrequester', ':splitreporter', ':splitextension'
  6. project(':assets').projectDir = new File("./features/assets")
  7. project(':java').projectDir = new File("./features/java")
  8. project(':native').projectDir = new File("./features/native")
  9. project(':splitcore').projectDir = new File("./qigsaw-android/splitcore")
  10. project(':playcorelibrary').projectDir = new File("./qigsaw-android/playcorelibrary")
  11. project(':playcorelibrary').projectDir = new File("./qigsaw-android/playcorelibrary")
  12. project(':splitinstaller').projectDir = new File("./qigsaw-android/splitinstaller")
  13. project(':splitdownloader').projectDir = new File("./qigsaw-android/splitdownloader")
  14. project(':splitloader').projectDir = new File("./qigsaw-android/splitloader")
  15. project(':splitrequester').projectDir = new File("./qigsaw-android/splitrequester")
  16. project(':splitreporter').projectDir = new File("./qigsaw-android/splitreporter")
  17. project(':splitcommon').projectDir = new File("./qigsaw-android/splitcommon")
  18. 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’

此外,工程里还有个没参与编译的独立的工程:qigsaw-android-sample,这是个让用户直接参考使用的工程,可以单独用Android studio打开这个目录,这里面没有配置qigsaw的源码依赖,而是直接依赖了编译好的gradle库。分析gradle源码时,不需要关注它。

Qigsaw gradle plugin分析

gradle plugin源码(buildSrc)调试方法

QigsawAppBasePlugin

tasks

按照执行顺序,梳理一下各个gradle task做的事情:

  • QigsawProcessManifestTask
    • 替换Manifest中的Provider名称
      • com.iqiyi.qigsaw.sample.java.JavaContentProvider_Decorated_java
        • 问题:_java算是怎么回事?需要check下
  • 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),什么都不做