Android ContentProvider 入门:跨进程数据共享与权限边界
## Android ContentProvider:跨进程数据共享与权限问题
Android ContentProvider:跨进程数据共享与权限最常见的问题,不是代码不会写,而是数据明明能查到、权限明明配了,到了多进程或外部调用场景却突然报错、查空,或者把不该暴露的数据直接暴露出去。很多团队第一次接触 ContentProvider 时,最容易把它当成一个普通数据库出口,结果忽略了 URI 设计、权限粒度和调用边界。
## 方案
先把 URI 路由和数据表映射关系定死;再把读权限、写权限、grantUriPermission 和导出策略拆开;最后补一层调用日志与异常兜底。这个顺序的价值在于,能先把权限乱、返回乱、跨进程读写边界不清楚这三类问题压下来。继续往下做时,建议把每条 URI 对应的数据范围、调用方、是否允许外部访问都显式写进表,而不是把所有权限逻辑混在查询和写入逻辑里。
如果团队已经接过文件分享、媒体库或应用间数据共享场景,最好再补一层 provider 级别的访问审计。因为 ContentProvider 真正危险的不是查不到,而是查到了不该查到的数据。只要把访问范围和导出策略提前收死,很多安全坑都能在编码前消掉。
## 示例代码
1. Provider 定义
class DemoProvider : ContentProvider() {
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
args: Array<out String>?,
sortOrder: String?
): Cursor? {
return null
}
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
override fun delete(uri: Uri, selection: String?, args: Array<out String>?): Int = 0
override fun update(uri: Uri, values: ContentValues?, selection: String?, args: Array<out String>?): Int = 0
}
2. 调试命令
adb shell content query --uri content://com.example.provider/users
adb shell dumpsys package com.example.app | grep -i provider -n
3. URI 匹配
val matcher = UriMatcher(UriMatcher.NO_MATCH).apply {
addURI("com.example.provider", "users", 1)
addURI("com.example.provider", "users/#", 2)
}
## 注意点
先盯三类:一是 exported 和 permission 配置冲突;二是 URI 规则过宽,导致外部能扫到本不该开放的数据;三是 query 返回列和调用方预期不一致,最后把跨进程调用变成隐性兼容问题。很多 provider 问题不是数据库错,而是边界没锁死。
## 报错与排查
1. 权限异常
如果现场报 Permission Denial,先确认 manifest 里的读写权限、exported 和 grantUriPermission,再看调用端是否真的持有权限。不要一开始就怀疑 ROM。
adb shell dumpsys package com.example.app | grep -i permission -n
2. 查询结果为空
如果查询不报错但查空,先核对 URI、selection 和 projection,再确认 provider 内部是否真的匹配到了路由。很多所谓跨进程异常,最后只是 URI 写错了一层路径。
fun matchCode(uri: Uri): Int {
return matcher.match(uri)
}
## 可运行片段
1. 状态对象
data class ProviderState(
val uri: String,
val exported: Boolean,
val readGranted: Boolean
)
2. 演示入口
fun printProviderState() {
println(ProviderState("content://com.example.provider/users", false, true))
}
3. 验证命令
adb shell content query --uri content://com.example.provider/users
adb shell dumpsys package com.example.app | grep -i provider -n
## 结论
Android ContentProvider:跨进程数据共享与权限这类问题,最核心的不是把接口写通,而是先把 URI、权限和导出边界钉死。只要这三层清楚,ContentProvider 在大多数场景里都是稳定而且好维护的。
