Android跨进程通信实战:基于ContentProvider实现App间安全数据共享与函数调用

1次阅读
没有评论

共计 2184 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

在开发多模块 Android 应用时,我们经常遇到需要跨进程共享数据的场景。比如电商 App 的购物车模块运行在独立进程,但需要实时同步用户数据到订单模块。传统做法是使用 AIDL,但每次新增接口都要重新定义.aidl 文件,维护成本较高。本文将介绍更轻量的 ContentProvider 方案,它能同时解决数据共享和函数调用需求。

Android 跨进程通信实战:基于 ContentProvider 实现 App 间安全数据共享与函数调用

主流 IPC 方案对比

  • AIDL:功能强大但实现复杂,适合高频 RPC 调用
  • 优点:支持双向通信,自动线程池管理
  • 缺点:需要维护接口文件,参数序列化成本高

  • Messenger:基于消息队列的轻量方案

  • 优点:实现简单,天然线程安全
  • 缺点:不支持同步调用,数据包大小受限

  • ContentProvider:本文推荐方案

  • 优点:统一数据访问接口,内置权限控制
  • 缺点:需要适配 CRUD 语义,函数调用需要封装

核心实现详解

1. 基础 ContentProvider 实现

首先创建继承 ContentProvider 的类,注意使用 AndroidX 注解:

class CrossProcessProvider : ContentProvider() {
    // Uri 匹配器配置
    private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {addURI("com.example.provider", "user/#", USER_CODE)
        addURI("com.example.provider", "function/call", FUNCTION_CALL_CODE)
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri {return when (uriMatcher.match(uri)) {
            USER_CODE -> {
                // 实际数据库操作
                val id = db.insert("user", null, values)
                ContentUris.withAppendedId(uri, id)
            }
            else -> throw IllegalArgumentException("Unsupported URI: $uri")
        }
    }

    // query/update/delete 方法同理
}

2. 函数调用功能扩展

通过 ContentResolver.call() 实现远程调用:

// 服务端注册函数
override fun call(method: String, arg: String?, extras: Bundle?): Bundle {return when (method) {
        "calculatePrice" -> {val params = extras?.getString("params")
            Bundle().apply { putDouble("result", PriceCalculator.execute(params)) }
        }
        else -> super.call(method, arg, extras)
    }
}

// 客户端调用示例
fun callRemoteFunction() {
    val result = contentResolver.call(Uri.parse("content://com.example.provider/function"),
        "calculatePrice",
        null,
        Bundle().apply { putString("params", "{...}") }
    )?.getDouble("result")
}

安全与性能优化

权限控制配置

在 AndroidManifest.xml 中声明细粒度权限:

<provider
    android:name=".CrossProcessProvider"
    android:authorities="com.example.provider"
    android:exported="true"
    android:readPermission="com.example.READ_DATA"
    android:writePermission="com.example.WRITE_DATA" />

防 SQL 注入实践

所有查询使用参数化:

fun querySafe(uri: Uri, selection: String?, selectionArgs: Array<String>?) {
    db.query("user", 
        null,
        "$selection AND valid=1", // 固定条件拼接
        selectionArgs, // 用户输入只出现在参数
        null, null, null)
}

大对象传输优化

对于超过 1MB 的数据:

  1. 使用 ParcelFileDescriptor 传输文件
  2. 实现自定义 Parcelable 时重写 describeContents()
  3. 考虑分页查询设计

生产环境检查清单

  • 并发控制
  • 对写操作使用 SQLite 事务
  • 读操作考虑 ContentProviderClient 稳定连接

  • 性能监控

  • 在 Application.onCreate() 启动预加载
  • 使用 StrictMode 检测主线程查询

  • 缓存策略

  • 客户端设置 Cursor.setNotificationUri()
  • 对静态数据使用内存缓存

通过本文方案,我们实现了:
1. 统一的数据访问入口
2. 安全的权限管控体系
3. 灵活的远程函数调用能力
实际项目中可根据业务需求,进一步封装为更易用的 SDK。比如为常用操作提供 Kotlin 扩展函数,或者结合协程实现异步调用。

正文完
 0
评论(没有评论)