最后做一个最小 Demo:Java 插件化框架从加载到四大组件

这一篇把前面的东西收一下。

如果自己动手实现,我建议不要一上来就追求“兼容所有 Android 版本”。先把最小 Demo 跑起来。

1. 工程结构

1
2
3
4
AndroidPluginDemo
├── app # 宿主
├── plugin-api # 宿主和插件共享接口
└── demo-plugin # 插件 APK

最终:

1
2
app-debug.apk
plugin-debug.apk

宿主安装,插件只是复制到宿主可以读取的位置。

2. 启动流程

整个 Activity 流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
加载 plugin.apk

创建 DexClassLoader

创建 Plugin Resources

解析 PluginInfo

业务请求启动 PluginActivity

改成 ProxyActivity

Android 启动 ProxyActivity

ClassLoader 加载插件类

创建 PluginActivity

PluginContext

插件页面显示

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
2
3
4
5
packageName
versionCode
versionName
hash
signature

ClassLoader 隔离

多个插件之间不要随便共享实现类,否则很容易出现依赖冲突。

生命周期

尤其是 Service、Provider,需要把销毁和异常处理补完整。

Android 版本兼容

这是最费时间的一块。

不要看到某个版本能跑,就认为所有 Android 都可以。

7. 最后总结一下

如果只是为了理解 Android 插件化,我觉得这个路线挺合适:

1
2
3
4
5
6
7
8
第一篇:先理解整体架构
第二篇:DexClassLoader + Resources
第三篇:Activity Proxy
第四篇:Service Proxy
第五篇:BroadcastReceiver Proxy
第六篇:ContentProvider Proxy
第七篇:PluginManager 统一管理
第八篇:完整 Demo + 限制

这样一篇一篇写,比直接看一个几万行的插件框架舒服很多。

而且等这个最小版本真正跑通以后,再去看大型插件框架,会容易理解很多。

坚持原创技术分享,您的支持将鼓励我继续创作!