很多初学者写鸿蒙 RPC 代码时,最容易出问题的地方不是连接服务,而是消息对象的读写细节。比如客户端 writeString、writeInt 的顺序和服务端 readString、readInt 不一致,就可能导致读到错误数据;异步调用时还想立刻从 reply 里取值,也会出现空结果。
所以第二篇我们专门拆 MessageParcel / MessageSequence、sendMessageRequest、DeathRecipient 和资源释放。把这些点弄清楚,RPC 代码就会稳定很多。
图 3 消息对象的读写顺序
1. MessageParcel 和 MessageSequence 怎么理解
|
对象 |
常见用途 |
注意事项 |
|
MessageParcel |
旧接口或兼容场景中常见,用于读写基础类型、数组、远端对象等 |
部分 sendRequest 相关接口在新 API 中已不建议继续使用 |
|
MessageSequence |
API 9+ 推荐与 sendMessageRequest 搭配使用 |
客户端和服务端要严格保持字段顺序、类型和接口令牌一致 |
|
MessageOption |
声明同步或异步调用模式 |
异步模式下 reply 通常不能按同步返回值理解 |
MessageSequence 的思路可以类比一个顺序队列:写入端按 A、B、C 放进去,读取端也必须按 A、B、C 取出来。它不会自动根据字段名匹配,也不会帮你判断“这里本来应该是 string”。因此,RPC 协议最怕两端代码各改各的:客户端多写了一个字段,服务端没有同步读取,后面的字段就会全部错位。
如果传输的是复杂对象,建议先把字段拆成基础类型,或者把对象序列化成 JSON 字符串,并在 JSON 中携带 version。基础类型适合高频、小数据量调用;JSON 适合字段经常变化但体积不大的业务对象;如果是大文件、图片、视频,不建议直接塞进 RPC 消息里,更适合传文件描述符、URI 或通过专门的传输通道处理。
2. 服务端处理请求的模板
class BookRemoteObject extends rpc.RemoteObject {
constructor() { super('com.demo.BookService'); }
onRemoteMessageRequest(code: number, data: rpc.MessageSequence,
reply: rpc.MessageSequence, option: rpc.MessageOption): boolean {
if (code === REQUEST_GET_BOOK) {
data.readInterfaceToken();
let bookId = data.readString();
reply.writeNoException();
reply.writeString('HarmonyOS RPC Guide: ' + bookId);
return true;
}
return false;
}
}

3. sendMessageRequest 的同步和异步
官方接口里 MessageOption 可以声明调用模式。同步模式更像普通函数调用:客户端等待服务端处理完,再从 reply 中读取结果。它适合“查询配置”“读取小段状态”“校验一个值”这种短耗时任务。异步模式更适合长耗时任务或跨设备调用,客户端不应该立刻依赖 reply,而是通过回调对象、事件通知或状态查询拿最终结果。
选择同步还是异步,核心看两个问题:业务结果是不是马上要用,服务端处理会不会阻塞。如果页面点击按钮后必须立即展示结果,并且服务端只做轻量计算,可以用同步;如果服务端要扫描设备、上传文件、等待网络响应,就应当用异步。否则用户会感觉界面卡住,严重时还可能触发超时或进程调度问题。
4. 为什么要 reclaim
消息对象底层涉及跨进程通信缓冲区,不应该等垃圾回收器慢慢处理。实践中建议把 data、reply 的释放写进 finally,保证成功、失败、异常路径都会执行。这样做不仅代码整洁,也能避免高频调用时出现资源占用累积。
同样重要的是异常路径。很多示例代码只写 then 里的成功读取,但真实业务中要同时处理 sendMessageRequest 本身失败、服务端写入异常、readException 读到远端异常、reply 字段为空等情况。把这些异常统一封装成业务错误,再返回给 UI 层,会比在页面里到处 try/catch 更可维护。

5. 常见问题排查表
|
现象 |
可能原因 |
建议处理 |
|
服务端收不到请求 |
未连接成功、IRemoteObject 为空、请求码不一致 |
先打印 onConnect,再统一维护请求码常量 |
|
读取参数错位 |
write/read 顺序或类型不一致 |
把接口协议写成固定模板,客户端和服务端共用定义 |
|
异步调用没有返回值 |
把异步模式当同步模式使用 |
确认 MessageOption 模式,异步结果走回调或业务通知 |
|
服务重启后调用失败 |
客户端持有的远端对象已死亡 |
注册 DeathRecipient,死亡后重新连接服务 |
6. 推荐写法清单
- 请求码使用常量集中管理,不要在多处手写数字。
- 每个接口先写 interface token,服务端先校验 token,再处理业务参数。
- 读写字段顺序写进注释或 IDL,不要靠记忆维护协议。
- Promise / callback 中处理 errCode 和 readException,不要只写成功路径。
- finally 中 reclaim 消息对象,死亡通知中清空代理并触发重连。
7. DeathRecipient 什么时候需要
当服务进程被系统回收、崩溃、升级重启,或者分布式设备离线时,客户端手里的远端对象就可能失效。DeathRecipient 的作用就是让客户端知道“这个远端对象已经死了”。收到通知后,最稳的处理方式不是继续重试同一个对象,而是清空缓存代理、提示业务层进入未连接状态,并按连接流程重新获取远端对象。
如果业务是一次性短调用,死亡通知可能不是必须;如果业务是长连接、设备控制、后台同步、持续订阅,就很有必要注册。注册后也别忘了在不再需要时注销,否则生命周期管理会变得混乱。可以把注册和注销放进连接管理器里,而不是散落在每个页面。
8. 小结
鸿蒙 RPC 的写法看起来是 API 调用,底层却是严格的消息协议。稳定的 RPC 代码通常有三个特征:协议常量清晰、消息读写对称、异常和生命周期处理完整。掌握这三点,再去看官方 @ohos.rpc 文档,很多接口就能自然串起来。
参考资料
- HarmonyOS 官方文档:@ohos.rpc (RPC) API 参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-rpc
- HarmonyOS 官方文档:ServiceExtensionAbility 开发参考:https://developer.huawei.com/consumer/cn/doc/HarmonyOS-Guides/app-service-extension-ability
- HarmonyOS 文档中心:IPC Kit / Ability Kit 等开发文档入口:https://developer.huawei.com/consumer/cn/doc/
- 参考写作风格:CSDN 技术博客式的“概念拆解 + 图示 + 表格 + 代码 + 总结”结构。




