AAB 的开发套件太爽了,不想就这样暴殄天物。
爱奇艺资深工程师 陈家威 如是说。
《基于 Android App Bundle 动态化方案探索》的学习笔记。
爱奇艺的Qigsaw方案脱胎于 AAB,紧跟 Google 的脚步又适应国内环境,高大上又接地气。
Google 减少 APK 体积的发展历程
- 以前的发布过程,周期长,占用更多空间
- 包含所有 so 库
- 包含所有资源
- 包体积和安装成功率呈反比
- Multiple APK
- Google Play 支持
- 通过不同配置,下发不同 APK
- 通过 Gradle 的 split 配置打包
- 像素配置
- 架构配置
- 推广使用并不好
- Android App Bundle
- APK 转换为 AAB
- 上传 AAB 到 Google Play
- Google Play 将 AAB 拆分成多个 APK
- Base APK
- Configuration APK
- 下载时根据配置下载:Base APK + Configuration APK + xxhdpi APK + arm64 APK
- Dynamic Feature 根据设备配置继续拆分
国内插件化发展回顾及原理分析
-
国内插件化
- AndroidDynamicLoad
- DynamicLoadAPK
- Neptune
- OpenAtlas
- DroidPlugin
-
原理
- BaseDexClassLoader 加载 class
- Resources
- AssetManager
- BaseDexClassLoader 加载 lib 中的 so
- AndroidManifest 记录四大组件
-
单类加载器
- Element 对应 DexFile,加载 Dex
- NativeLibraryElement 对应 File 记录 so 目录
-
多类加载器
- 替换系统 ClassLoader
- 每个插件,独立的 ClassLoader 加载
-
资源加载
- 资源文件 ID PP(系统应用还是第三方 7F)TT(资源类型)EEEE(顺序)
- AAPT|AAPT2生成资源 ID
- 调用 AssetManager#addAssetPath(String) 加载 Asset 资源
- 系统资源 PP01 PP02 PP03
- App 资源 PP7F 插件 PP7E
- 资源隔离
- 资源分区
-
启动未在宿主 AndroidManifest 文件注册的 Activity
- 插桩预埋方式
- startActivity 后,execStartActivity 时替换 Class 信息,newActivity 时还原 Class 信息
- 插桩预埋方式
Android App Bundle 原理介绍
- Split APK
- Android 5.0提供
- 减少包体积
- 签名相同
- 同一个应用
- 如何安装?
- adb 安装:adb install-multiple [base-apk,split1-apk]
- PackageInstaller 安装
- 在运行期间,安装 Split APKs
- 安装后,宿主应用进程会被杀死
- 系统应用可以静默安装 Split APKs
- 如何加载的 - LoadedAPK 用于保存当前已加载 APK 的本地状态
- mClassLoader
- 创建 PathClassLoader :createOrUpdateClassLoaderLocked(List addedPaths)
- 增加 Split APKs 路径
- mResources
- getSplitResDirs
- mApplication
- mClassLoader
- AAB 如何加载插件
- Play Core Library,Google Play 支持
- SplitCompat 为了让插件及时生效,与国内插件化很类似
- 国内无法使用 Google Play
Qigsaw 简介及原理分析
-
利用 AAB 开发套件,爱奇艺自研的动态组件化方案
-
设计原因
- 开发者希望插件和基线能在同一工程协作开发
- 体验好
- 共同学习
- Android P 对私有 API 访问限制
- 利用 AAB 强大的开发套件
- 便于国际化
- 开发者希望插件和基线能在同一工程协作开发
-
开发初体验
- 全新的打包插件 dynamic-feature
- 插件和 Base 可以统一开发调试
- 部分插件可以和主 APK 打包在一起,部分插件 APK 上传到 cdn
-
核心优势
- “山寨”Play Core Library 公开接口实现,开发者阅读官方文档即可开发
- Hook,少量私有 API 访问(Grey list)
- 利用 AAB 开发工具
- 支持 Android4.0及以上
- 任何进程均可加载插件
- 国际化和 AAB 无缝切换
-
对比其它插件化框架
- 接入方便
- 无需关心插件上传,分发
-
插件安装加载过程
- 与 AAB 过程类似
-
如何工作的
-
单类加载器
-
资源加载使用 Qigsaw 独有方式,插件提供代码插入
public Resources getResources(){ SplitInstallHelper.loadResources(this,super.getResources()); return super.getResources(); }
-
-
扩展功能
- 多进程支持
- 解决“哪个进程发起插件请求,插件就加载到哪个进程里”问题
- 捕获 ClassNotFoundException 异常然后在 game 进程中加载已安装但未加载的插件
- Hook PathClassLoader
- 解决“哪个进程发起插件请求,插件就加载到哪个进程里”问题
- 支持插件的 Application,在插件启动时创建 Application 实例,并调用生命周期方法
- 支持插件的 Provider
- 进程启动时移除插件 Provider
- 插件启动时再进行 Provider 安装
- 与 Tinker 融合
- 通过 Tinker Patch 下发插件更新
- assets 文件中的文件记录版本号
- 通过 Tinker Patch 下发插件更新
- 在爱奇艺的应用场景
- 爱奇艺小游戏和小程序框架,是通过 Qigsaw 加载的
- 19年初上线,经受数亿用户考验
- 崩溃率接近于0%
- 开源计划
- 多进程支持