前面已经把几个零件都拆出来了,现在可以把它们拼起来。
我比较倾向于保持非常小的结构,不要一开始就几十个类。
1. 推荐目录
1 | plugin/ |
插件侧:
1 | plugin-api/ |
这里特别建议把 API 单独放一个小模块。
宿主和插件都依赖 API,但宿主不直接依赖插件实现。
2. PluginInfo
每个插件至少记录:
1 | public class PluginInfo { |
后面如果需要签名校验、插件版本、插件状态,也可以继续加。
3. PluginManager
核心 API 可以非常简单:
1 | public class PluginManager { |
框架其他模块全部通过它拿插件。
4. 统一启动 Activity
不要让业务代码到处自己拼 ProxyActivity Intent。
可以封装:
1 | public void startActivity(Context context, |
这样业务侧看起来就是:
1 | pluginManager.startActivity( |
5. 为什么要保存 packageName
只保存 className 不太够。
因为以后可能同时加载:
1 | pluginA.apk |
它们甚至可能存在相同的类名。
所以路由信息最好是:
1 | packageName + className |
四大组件都一样。
6. 四大组件最终形成一套路由
1 | PluginManager |
真正的系统组件永远在宿主 Manifest 中。
插件组件只是框架运行时创建的普通对象,或者实现特定 API 的对象。
7. 这样做还有一个好处
以后插件升级的时候,不需要改宿主代码。
比如:
1 | plugin-v1.apk |
只要 API 兼容,宿主继续使用同一套 PluginManager。
8. 但别急着拿去生产
这个方案作为学习框架已经够用了。
真正生产环境还要处理:
- APK 签名和完整性校验;
- 插件版本管理;
- ClassLoader 冲突;
- 多插件资源冲突;
- Android 不同版本差异;
- 进程和线程问题;
- 插件崩溃隔离;
- 权限边界;
- Provider 跨进程;
- ProGuard/R8;
- ABI 和 native so;
- 隐藏 API 限制。
尤其是最后一点,Android 越来越不鼓励应用随便碰内部 API。
所以这个框架定位还是很明确:先把插件化最核心的运行机制看懂。
下一篇做一个完整 Demo,把宿主、插件、API 三个工程放到一起跑。