Android 轻量插件化:ContentProvider 为什么是四大组件里最麻烦的

前面的 Activity、Service、Receiver 都是系统先启动一个宿主组件,然后我们把请求转给插件。

ContentProvider 不太一样。

它经常在进程启动阶段就被系统创建,而且还有 authority 这一套机制。

所以 Provider 是这个轻量框架里最值得单独讲的一部分。

1. 最简单的 Provider

插件可能有:

1
2
3
4
5
6
7
8
public class PluginProvider implements PluginContentProvider {

@Override
public Cursor query(Uri uri, String[] projection) {
// 查询插件数据
return null;
}
}

Manifest:

1
2
3
<provider
android:name=".PluginProvider"
android:authorities="com.demo.plugin.provider" />

但因为 APK 没安装,这个 authority 对系统来说不存在。

2. ProxyProvider

宿主注册一个 Provider:

1
2
3
<provider
android:name=".plugin.ProxyProvider"
android:authorities="com.demo.host.plugin" />

外部访问:

1
content://com.demo.plugin.provider/xxx

不能直接交给系统,因为系统只认识宿主 Provider。

所以更简单的教学方案是统一使用宿主 authority:

1
content://com.demo.host.plugin/pluginA/xxx

ProxyProvider 根据第一段路径找到对应插件。

3. Provider 内部路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public Cursor query(Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder) {

String plugin = uri.getPathSegments().get(0);
PluginContentProvider provider =
manager.getProvider(plugin);

return provider.query(uri,
projection,
selection,
selectionArgs,
sortOrder);
}

这样就把 Provider 变成了一个路由器。

4. insert/update/delete

其他方法也是一样:

1
2
3
4
5
6
7
query
insert
update
delete
getType
openFile
call

全部从 ProxyProvider 转发给插件对象。

5. 为什么不能简单做到完全透明

如果你要求:

1
content://com.demo.plugin.provider/xxx

这个 URI 完全不改,系统还要在插件没有安装的情况下找到 Provider,那么就要更深入系统的 Provider 注册和 AMS/ActivityThread 相关机制。

这已经不是一个“最轻量”框架应该碰的地方了。

所以这里建议明确区分两种目标:

教学版

统一 authority:

1
content://host.plugin/<plugin>/<path>

优点是简单、稳定、代码少。

深度兼容版

尝试让插件原始 authority 对外表现得像真实安装的 Provider。

这通常需要处理系统内部 Provider 注册流程,Android 版本升级后也很容易失效。

6. Provider 的启动问题

还有一个坑。

如果宿主启动的时候 Provider 已经被系统创建,那么 ProxyProvider 可以在 onCreate() 中初始化插件管理器。

但插件 Provider 不应该真的要求系统帮它创建。

也就是说:

1
2
3
4
5
系统创建 ProxyProvider

ProxyProvider 初始化 PluginManager

按需创建 PluginProvider

而不是:

1
系统创建 PluginProvider

后者系统根本做不到,因为插件没有安装。

7. 到这里四大组件基本闭环

现在可以把四种组件放在一起:

1
2
3
4
Activity         -> ProxyActivity
Service -> ProxyService
Receiver -> ProxyReceiver
ContentProvider -> ProxyProvider

不过真正使用时,还缺一个统一的 PluginManager 和组件路由层。

下一篇把这几个东西真正拼起来。

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