这一篇把前面的东西收一下。
如果自己动手实现,我建议不要一上来就追求“兼容所有 Android 版本”。先把最小 Demo 跑起来。
1. 工程结构
1 | AndroidPluginDemo |
最终:
1 | app-debug.apk |
宿主安装,插件只是复制到宿主可以读取的位置。
2. 启动流程
整个 Activity 流程:
1 | 加载 plugin.apk |
Service、Receiver、Provider 也是同一个大方向。
3. 一个很重要的认识
很多人第一次接触插件化,会觉得:
“是不是要把插件 APK 注入 Android 系统?”
其实不完全是。
至少这个轻量方案不是这么做的。
我们只是利用了两套能力:
第一套:Java/Dex 的动态加载。
让插件代码进入宿主进程。
第二套:宿主已经注册好的系统组件。
让系统以为自己启动的是宿主组件。
中间再做一次转发。
所以整个框架可以浓缩成一句话:
代码自己加载,组件借宿主的身份运行。
4. 四大组件对应关系
| Android 组件 | 宿主注册 | 插件实际对象 |
|---|---|---|
| Activity | ProxyActivity | PluginActivity |
| Service | ProxyService | PluginService |
| Receiver | ProxyReceiver | PluginReceiver |
| Provider | ProxyProvider | PluginContentProvider |
这里 Provider 是最特殊的一个,因为 authority 和创建时机都需要额外处理。
5. 为什么我不建议一开始就做“透明插件”
如果目标是:
1 | 插件代码完全不用改 |
那么你最后一定会走向大量 Android 内部机制。
比如 Activity 的 token、Instrumentation、ActivityThread,Provider 的系统注册关系等等。
这种方案确实可以研究,但代码复杂度会突然上一个台阶。
而且 Android 每次系统升级,内部实现都有可能调整。
对于自己学习 Android Framework 来说,当然值得研究;但如果目标只是一个轻量业务插件系统,未必划算。
6. 真正需要补的东西
如果这个 Demo 要继续往生产方向走,我会优先补下面几个:
插件安全
不能让用户随便指定一个 APK 就加载。
至少应该做签名校验、文件完整性校验和插件来源控制。
插件版本
需要保存:
1 | packageName |
ClassLoader 隔离
多个插件之间不要随便共享实现类,否则很容易出现依赖冲突。
生命周期
尤其是 Service、Provider,需要把销毁和异常处理补完整。
Android 版本兼容
这是最费时间的一块。
不要看到某个版本能跑,就认为所有 Android 都可以。
7. 最后总结一下
如果只是为了理解 Android 插件化,我觉得这个路线挺合适:
1 | 第一篇:先理解整体架构 |
这样一篇一篇写,比直接看一个几万行的插件框架舒服很多。
而且等这个最小版本真正跑通以后,再去看大型插件框架,会容易理解很多。