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
- BaseDexLassLoader加载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
- getSplitRources
- 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%
- 开源计划
- 多进程支持