鸿蒙 @ohos.rpc 到底是怎么完成跨进程通信的?
在鸿蒙应用开发中,如果一个 UI Ability 想调用另一个进程里的 ServiceExtensionAbility,就不能像普通对象那样直接 new 后调用方法。原因很简单:两个对象不在同一个进程空间,参数、返回值和异常都需要被系统框架打包、传输、再解包。@ohos.rpc 就是用来处理这类 IPC/RPC 通信的基础模块。
从开发者视角看,RPC 调用像是在调用远端方法;从系统视角看,它其实是一次带请求码的消息传递。客户端把参数写进 data,服务端按相同顺序读取,处理后把结果写进 reply。

图 1 @ohos.rpc 通信模型
官方 RPC 文档里有一个容易被忽略的点:RPC 模块不直接关心你的业务类名,它关心的是远端对象、消息序列和请求码。也就是说,客户端调用“查询图书详情”这个业务方法时,真正传过去的是一个整数 code、一段按顺序写好的 MessageSequence,以及同步或异步的调用选项。服务端收到后,先判断 code,再按照约定读取字段,最后把结果写回 reply。把它看成“轻量协议”会比看成“远端函数调用”更准确。
在实际项目里,RPC 常被放在 UI Ability 与后台 ServiceExtensionAbility 之间。例如前台页面负责展示扫码、支付、设备控制等交互,后台服务负责长连接、文件传输、设备发现或数据同步。这样做的好处是职责清晰:页面进程可以保持轻量,服务进程可以封装更稳定的能力;坏处是你必须认真处理连接、断连、远端死亡和序列化异常,否则问题会表现成“偶发调用失败”。
1. 先分清 IPC 和 RPC
|
概念 |
通信范围 |
底层机制 |
开发关注点 |
|
IPC |
同一设备内不同进程 |
Binder 驱动 |
接口描述符、请求码、参数序列化、同步/异步模式 |
|
RPC |
跨设备或分布式场景 |
软总线能力 |
远端对象生命周期、网络/设备状态、调用失败兜底 |
2. 四个核心角色
- IRemoteObject:远端对象的抽象,客户端拿到它后才能向服务端发送请求。
- RemoteProxy:客户端侧代理,负责把请求码和参数包发送给远端对象。
- RemoteObject:服务端侧对象,重写 onRemoteMessageRequest 处理客户端请求。
- MessageSequence / MessageParcel:承载序列化数据,读写顺序必须一致。

图 2 ServiceExtensionAbility 连接与调用生命周期
3. 连接服务时应该关注什么
从生命周期看,RPC 调用不是第一步。第一步通常是通过 Want 指定目标服务,再通过连接回调拿到 IRemoteObject。只有拿到远端对象后,客户端才有资格构造代理并发送请求。很多“sendMessageRequest 调不通”的问题,根源其实不在 sendMessageRequest,而在服务连接阶段:bundleName 或 abilityName 写错、目标服务没有导出、设备 ID 不正确、权限没有申请,都会导致客户端拿不到可用对象。
建议把连接状态当成 UI 状态的一部分管理:连接中禁用业务按钮,连接成功后再允许调用;onDisconnect 或死亡通知触发时把代理置空;下一次业务调用前检查 proxy 是否存在,不存在就重新连接。这个模式虽然多写几行代码,但能把“空对象调用”“服务重启后继续调用旧对象”这类问题挡在入口处。

图 3 一次 RPC 调用的典型流程
4. 代码骨架怎么写
import rpc from '@ohos.rpc';
const REQUEST_GET_BOOK = 1001;
let data = rpc.MessageSequence.create();
let reply = rpc.MessageSequence.create();
let option = new rpc.MessageOption();
data.writeInterfaceToken('com.demo.BookService');
data.writeString('book-001');
remoteProxy.sendMessageRequest(REQUEST_GET_BOOK, data, reply, option)
.then((result: rpc.RequestResult) => {
result.reply.readException();
let name = result.reply.readString();
})
.finally(() => { data.reclaim(); reply.reclaim(); });

图 4 请求码与远端能力映射示例
5. 请求码不是随便写的数字
请求码是客户端和服务端之间最稳定的“方法编号”。在小 demo 里写 1、2、3 似乎没有问题,但项目一复杂,魔法数字会很快失控。更稳的做法是把请求码放进单独的常量文件或协议文件里,按业务域预留区间,例如 1000 段给图书查询,2000 段给订阅能力,9000 段给诊断能力。新增接口时只增加新 code,不轻易改变旧 code 的含义。
另外,接口描述符也不要省略。客户端写入 interface token,服务端读取并校验,可以避免一个远端对象被错误协议调用。这个动作类似 Web 接口里的路径和版本校验:它不能替代权限控制,但能让协议错误更早暴露。对于多人协作的鸿蒙项目,建议把“code、字段顺序、字段类型、返回值、错误码”整理成一张协议表,客户端和服务端按表实现。
6. 小结
理解 @ohos.rpc 的关键,不是背 API 名称,而是把它看成一套“请求码 + 数据包 + 远端对象”的协议。只要客户端和服务端约定好接口描述符、请求码、参数顺序和返回格式,就能把跨进程调用写得像普通方法调用一样清晰。
更多推荐




所有评论(0)