陈家伟 基于Android App Bundle的动态化方案探索

前端狗

2019/07/09 发布于 编程 分类

GMTC2019 

文字内容
1. 基于Android App Bundle 动态化⽅方案探索 陈家伟 爱奇艺资深工程师
4. ⾃自我介绍 陈家伟 二零一四年,毕业于南昌大学。 工作轨迹:步步高 -> 平安 -> 至今爱奇 艺。 技术领域:Android 动态化,React Native 等,目前主要负责基于Android App Bundle动态化方案Qigsaw研发和推广。
5. ⽬目录 •Google减少APK体积的发展历 程 •国内插件化发展回顾及原理分析 •Android App Bundle原理介绍 •Qigsaw简介及原理分析
6. 回⾸首Android第⼀一个10年年,应⽤用发布⽅方式。
7. Android应⽤用⽤用发布流程 APK APK APK
8. 传统发布⽅方式弊端 all native library, all language, all density, all OS all…
9. 难以忽视的“⼤大”问题
10. 40 30 20 10 0 2012 2014 2016 爱奇艺安装包体积 2019
11. ⾃自2012年年以来, 应⽤用平均体积增⻓长5倍
12. 应⽤用体积越⼤大,安装成功率越低
13. Android 5.0 推出Multiple APK, 旨在减少安装包体积
14. Multiple APK Multiple APK是Google Play提供⼀一个功能, 它允许您的应⽤用针对不不同的设备配置发布不不同的APKs。 https://developer.android.com/google/play/publishing/multiple-apks
15. ARMv7 xx-hdpi ARMv8 xxx-hdpi
16. android { ... splits { // Configures multiple APKs based on screen density. density { ... // Specifies a list of screen densities Gradle should not create multiple APKs for. exclude "ldpi", "xxhdpi", "xxxhdpi" } // Configures multiple APKs based on ABI. abi { ... // Specifies a list of ABIs that Gradle should create APKs for. include "x86", “x86_64" // Specifies that we do not want to also generate a universal APK that includes all ABIs. universalApk false } } }
17. … Density app-hdpiX86-release.apk build output You App app-hdpiX86_64-release.apk app-mdpiX86-release.apk CPU Arch app-mdpiX86_64-release.apk
18. Multiple APK 弊端 您可能为每个版本构建 数百个APK,降低迭代 效率。
19. Multiple APK的“恶果” 开发者宁愿它“胖”,也 不不愿麻烦。 导致⽤用户设备存在⼤大量量 未使⽤用过的内容。
20. Android App Bundles
21. Android App Bundle发布流程 Pixel 2XL Bundle Bundle Android App Bundle Android SplitApp APKs Bundle
22. xxhdpi hdpi arm64 x86 Configuration APKs Base APK (shared code) base zh en
23. Pixel 2 XL en xxxhdpi arm64
24. Pixel 2 XL (pre L) en xxxhdpi arm64 Dynamic Delivery xxxhdpi hdpi arm64 x86 zh APK base base zh Split APKs en Optimized APK
25. Dynamic Feature • 安装时不不需要的⼤大型功能(付费 ⾼高级功能、AR功能等)。 • 针对特定受众群体的功能(商业 应⽤用中特定⽤用户下载专属功 能)。 • 很少使⽤用的功能(身份验证、信 ⽤用卡扫描)。
27. 国内插件化发展回顾
28. AndroidDynamicLoad DynamicLoadAPK Neptune 2012 2014 2018
29. DirectLoadApk 2012 DroidPlugin Small RePlugin 2014 2018 OpenAtlas DynamicApk VirtualAPK Atlas
30. 国内插件化原理理简介
31. META-INF BaseDexClassLoader class.dex class2.de class3.de classN.de x x x res resources.arsc assets BaseDexClassLoader Resources AssetManager lib AndroidManifest.xml 四⼤大组件信息
32. 单类加载器器 DexPathList DexFile Element0 Element1 Element2 Element3 PathClassLoader(DexPathList) NativeLibraryElement0 File(lib folder) NativeLibraryElement1 NativeLibraryElement2 Element4 插件 NativeLibraryElement3
33. 多类加载器器 LoadedAPK mRouteClassLoader mClassLoader mPlugin ClassLoader0 mPlugin ClassLoader1 mPlugin ClassLoader2
34. 资源加载 P P T T E E E E 7 F 0 2 0 0 0 1 AAPT AAPT2 资源加载调⽤用AssetManager#addAssetPath(String)即可 注:Android 5.0之前⽆无法动态增加资源路路径
35. AssetManager中已加载资源路路径: /system/framework/framework-res.apk (PP:01) 系统资源 /system/framework/framework-res-hwext.apk (PP:02) /product/overlay/frameworkResOverlay.apk (PP:03) App资源 /data/app/com.iqiyi.test-tX6rCsTDr08d9EOfzYy5ug==/base.apk (PP:7F) 插件资源 /data/user/0/com.iqiyi.test/app_split/plugin.apk (PP:7E) (PP:7F)
36. /system/framework/framework-res.apk (PP:01) /system/framework/framework-res-hwext.apk (PP:02) /product/overlay/frameworkResOverlay.apk (PP:03) /data/user/0/com.iqiyi.test/app_split/plugin.apk (PP:7F) 资源隔离:每个插件拥有独⽴立Resources对象,⽆无法直接访问宿主资源。 /system/framework/framework-res.apk (PP:01) /system/framework/framework-res-hwext.apk (PP:02) /product/overlay/frameworkResOverlay.apk (PP:03) /data/app/com.iqiyi.test-tX6rCsTDr08d9EOfzYy5ug==/base.apk (PP:7F) /data/user/0/com.iqiyi.test/app_split/plugin.apk (PP:7E) 资源分区:插件和宿主共⽤用Resources对象,可互相访问资源。
37. 替换class信息 Context startActivity Instrumentation execStartActivit …AMS… newActivity 还原class信息 采⽤用插桩预埋⽅方式启动未在宿主AndroidManifest⽂文件注册的Activity
38. Android App Bundles原理理
39. Split APKs
40. Android 5.0 Framework层功能
41. ⽬目的:减少APK体积
42. 特点1:签名相同
43. 特点2:同⼀一应⽤用
44. Split APKs安装
45. ADB安装
46. adb install [apk] adb install-multiple [base-apk, split1-apk]
47. PackageInstaller安装
48. 第三⽅方应⽤用利利⽤用PackageInstaller 可在应⽤用运⾏行行期间安装Split APKs
50. 系统应⽤用可以静默安装Split APKs 系统版本低于7.0,需重启才能⽣生效
51. Split APKs加载 LoadedAPK mClassLoader mResources mApplication … LoadedAPK:⽤用于保存当前已加载APK的本地状态
52. Split APKs路路径集合 private void createOrUpdateClassLoaderLocked(List<String> addedPaths) { ... if (mClassLoader == null) { 创建PathClassLoader ... mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, mBaseClassLoader, mApplicationInfo.classLoaderName); ... } 增加Split APKs路路径 ... if (addedPaths != null && addedPaths.size() > 0) { final String add = TextUtils.join(File.pathSeparator, addedPaths); ApplicationLoaders.getDefault().addPath(mClassLoader, add); // Setup the new code paths for profiling. needToSetupJitProfiles = true; } ... }
53. public Resources getResources() { Split APKs资源路路径数组 if (mResources == null) { final String[] splitPaths; try { splitPaths = getSplitPaths(null); } catch (NameNotFoundException e) { throw new AssertionError("null split not found"); 创建Resources } mResources = ResourcesManager.getInstance().getResources(null, mResDir, splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(), getClassLoader()); } return mResources; }
54. 使⽤用Play Core Library安装插件
55. Play Core Library PlayCoreLibrary提供SplitCompat模式让app可⽴立即使⽤用插件。
56. SplitCompat与国内插件化框架⼯工作原理理类似 • 单类加载器器⽅方式加载插件代码 • AssetManager#addAssetPath(String) 加载资源。
57. Qigsaw
58. What’s Qigsaw?
59. Qigsaw是利利⽤用AAB开发套件, 爱奇艺⾃自研的⼀一套动态组件化⽅方案
60. Why Qigsaw?
61. 开发者希望插件和基线 能在同⼀一⼯工程协作开发
62. Android P私有API访问限制
63. 利利⽤用AAB强⼤大开发套件
64. 便便于⾛走向国际
65. Qigsaw开发初体验
66. Debug阶段 library Core Http Storage Card build iqiyi.apk install AR.apk QYVideo application AR MiPus h MiPush.apk dynamic-feature adb install-multiple [base-apk, split1-apk]
67. Release阶段 library iqiyi.apk Core Http Storage assets Card build QYVideoClient application AR MiPus h AR.apk MiPush.apk dynamic-feature Qigsaw提供打包插件让开发者享受⼀一条⻰龙服务 CDN
68. Qigsaw核⼼心优势
69. “⼭山寨”Play Core Library公开接⼝口实现 开发者阅读官⽅方⽂文档即可愉快开发
70. 1 Hook,少量量私有API访问(grey list)
71. 利利⽤用AAB开发⼯工具 领略略极速开发体验
72. ⽀支持Android 4.0及以上 任何进程均可加载插件
73. 国际化应⽤用可⽆无缝切换⾄至AAB
74. 对⽐比其他插件化框架, 有啥优势!?
75. 接⼊入使⽤用超级⽅方便便, 好! ⽤用过的朋友都说
76. Qigsaw插件安装加载过程
77. 加载 安装 X Process Main Process Qigsaw Core Library QisawCoreLibrary提供SplitCompat模式让进程可⽴立即使⽤用插件。
78. Qigsaw插件加载
79. • 代码加载采⽤用单类加载器器⽅方式。 • 资源加载使⽤用Qigsaw独有⽅方式加载。
80. Qigsaw资源加载 public class MyActivity extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public Resources getResources() { SplitInstallHelper.loadResources(this, super.getResources()); return super.getResources(); } } 为避免开发者重复写⼤大量量模板代码,Qigsaw提供插件在打包过程中插⼊入模板代码。
81. 拓拓展功能
82. (⼀一)多进程⽀支持
83. GameActivity01(main process) GameActivity02(game process) 加载 Main Process 安装 Qigsaw Core Library Main Process 哪个进程发起插件安装请求,就在哪个进程加载插件
85. 插件在“:game”进程未加载导致 ClassNotFoundException
86. 解决⽅方案
87. (⼀一) 进程启动阶段加载所有已安装插件 Application#attachBaseContext
88. (⼆二) Hook PathClassLoader
89. (⼆二)续 当出现ClassNotFoundException时 •判断异常类是否为插件四⼤大组件。 • 如果是,则加载所有已安装但未加载插件。 • 当加载完成后,依然出现类找不不到异常。 •返回空四⼤大组件类防⽌止进程崩溃。
90. (⼆二)⽀支持插件Application
91. 在插件启动时创建Application实例例, 并调⽤用对应⽣生命周期⽅方法。
92. (三)⽀支持插件Provider
93. 在进程启动时候移除插件所有Provider, 在插件启动时再进⾏行行Provider安装。
94. 与Tinker融合
95. 通过Tinker Patch下发插件更更新
96. apk assets 1.0_1.0.0.json 该⽂文件记录插件信息 包括下载地址
98. apk assets 如果该⽂文件更更新了了, 那么插件也就更更新了了。 1.0_1.0.0.json Tinker开启资源修复即可。
99. Qigsaw在爱奇艺App的使⽤用
101. 从19年年年年初上线⾄至今, 踩过⽆无数坑,经受数亿⽤用户检验
102. →0%
103. Qigsaw在爱奇艺公司的使⽤用
105. 开源计划
107. Q&A
110. THANKS THANKS! THANKS!