Android插件化
目次
12年我还在上初中,AndroidDynamicLoader已经只吃了Fragment的插件化实现。之后不断演变,从dynamic-load-apk,到DroidPlugin,再到Atlas。
说来惭愧,时至今日才有机会接触到,不禁想一探究竟。
起源 #
在想一项技术被怎么实现、怎么应用前,总是有这样的疑问:为什么要有这项技术呢?插件化也是一样的,为什么一定要用插件化呢?
因为是25年才搜索,并没有真正的经历过插件化的演变,查资料得知:
- 解决Dex中方法数上限65536的问题;
- 大项目需求迭代,提高多个模块并行开发效率,减小应用体积,同时还能动态化修改功能(主模块之外)。
对第一个问题,Enable multidex for apps with over 64K methodsAndroid开发官方的文档中说明,从Android5.0开始,已经支持了MultiDex,用以解决65536上限的问题。
但是,考虑到应用适配的速度,尤其是一几年,没有升级到SDK版本还停留在Android 5.0之前是很正常的。虽然升级的成本要比插件化低很多😅。
插一句:Android官方提供用在Android5.0之前解决多DEX方法数上限的库中实际上也是把APK解压,通过classloader加载dex文件。
Android 5.0(API 级别 21)及更高版本使用名为 ART 的运行时,它本身支持从 APK 文件加载多个 DEX 文件。 ——为方法数超过 64K 的应用启用 MultiDex
第二个问题使用其他方式可以解决吗?至少可以解决一部分,开发效率可以考虑组件化的方式。减小应用体积动态下载这部分是不可以的。
因此,动态化是有必要的。
需要解决的问题 #
插件化即是动态下载好要执行的代码,在Android应用中涉及到三方面:
- 逻辑代码
- 四大组件
- 资源文件
实现方式 #
逻辑代码 #
逻辑代码只要能被类加载器加载过,找到对应的路径就是可以执行的。
在Android中有两个classloader被用来加载dex文件:PathClassLoader和DexClassLoader。两者在Android8.0之后实际上也没有差异了。
四大组件 #
四大组件也是类,为什么不和其他逻辑代码放到一起呢?
因为在Android中启动一个四个组件的类是会鉴别是否在清单文件中的,如果不在其中,会被拒绝启动。
解决的思路有两种:
- 清单文件中预埋容器Activity,容器中声明周期方法被调用时,手动调用实际Activity的;
- 利用hook,将插件 Activity 替换成实际Activity,等到检测完了后再换回来。
资源文件 #
当我们访问资源文件时,比如string。实际上是从ResourceImpl中的AssetsManager中返回的。
向ResourceImpl中添加的方法是assets.addAssetPath,所以我们想将插件的apk文件添加到宿主中,就可以通过反射修改这个地方。
实现步骤:
- 创建一个AssetManager对象,并调用 addAssetPath 方法,将插件 apk 的路径作为参数传入。
- 将第一步创建的AssetManager对象作为参数,创建一个新的Resources对象,并返回给插件使用。