BroadcastReceiver 是四大组件里面代码最短的一个,但插件化以后有一个非常明显的分叉:
动态注册和 Manifest 注册,要分开看。
1. 动态 Receiver
如果插件自己调用:
1 | context.registerReceiver(receiver, filter); |
我们其实可以让插件的 PluginContext 接管这个方法。
插件写:
1 | registerReceiver(myReceiver, filter); |
最终变成框架自己的注册逻辑。
例如:
1 | public void registerReceiver( |
这里最简单的方式甚至不需要修改系统。
2. ProxyReceiver
1 | public class ProxyReceiver extends BroadcastReceiver { |
所以动态 Receiver 是最好处理的。
3. Manifest Receiver 就不同了
插件 Manifest 里可能有:
1 | <receiver android:name=".BootReceiver"> |
插件没有安装,PackageManager 就不会替它建立这份注册信息。
因此系统广播到来的时候,不会找到插件 Receiver。
4. 最轻量的办法
启动插件的时候读取插件 APK 的 Manifest 信息,把 Receiver 定义解析出来。
然后由宿主统一注册代理 Receiver:
1 | plugin Manifest |
例如:
1 | PackageInfo info = packageManager |
拿到:
1 | info.receivers |
再读取每个 Receiver 的信息。
不过 PackageInfo 主要告诉我们有哪些组件,真正的 intent-filter 还需要进一步解析 APK Manifest,工程实现时建议专门做一个 PluginManifestParser。
5. 一个容易忽略的问题
并不是所有广播都可以随便动态注册。
Android 不同版本对隐式广播、后台行为以及动态 Receiver 都做过不少限制。
所以这个教学框架不要承诺“任何系统广播都能工作”。
我们先验证普通自定义广播:
1 | Intent intent = new Intent("com.demo.PLUGIN_EVENT"); |
这样最容易观察整个链路。
6. Receiver 的核心其实很简单
只要记住:
1 | 动态注册:PluginContext 接管注册 |
这两个方案组合起来,就能覆盖大部分教学场景。
真正困难的四大组件其实还在后面——ContentProvider。
因为 Provider 的创建时机和系统启动过程更特殊。