鸿蒙 跨进程通信:IPC与RPC
鸿蒙应用开发中,IPC(同设备进程通信)和RPC(跨设备进程通信)是核心通信机制。客户端通过Proxy对象发起请求,服务端通过Stub对象处理请求。开发需导入相关模块,客户端需创建Want对象建立连接,通过sendMessageRequest发送消息;服务端需实现RemoteObject的Stub类处理请求。通信完成后需断开连接释放资源。注意事项包括线程模型(默认同步)和数据类型支持(基本类型、P
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
鸿蒙开发中,IPC(Inter-Process Communication,进程间通信) 和 RPC(Remote Procedure Call,远程过程调用) 是跨进程通信的核心机制。
| 术语 | 说明 |
|---|---|
| IPC | 同一设备内不同进程之间的通信 |
| RPC | 跨设备的不同进程之间的通信(远程调用) |
| Proxy | 客户端进程中的代理对象,用于调用服务端接口 |
| Stub | 服务端进程中的存根对象,用于处理客户端请求 |
IPC/RPC的主要工作是跨进程建立对象通信的连接,使客户端进程的Proxy和服务端进程的Stub建立一一对应关系,从而通过Proxy的接口可以和Stub进行IPC/RPC通信。
二、开发准备:导入所需模块
在进行IPC/RPC通信开发前,需要导入相关模块:
// 基础模块
import { Want, common } from '@kit.AbilityKit'; // Ability相关
import { rpc } from '@kit.IPCKit'; // IPC/RPC核心模块
import { hilog } from '@kit.PerformanceAnalysisKit'; // 日志打印
import { BusinessError } from '@kit.BasicServicesKit'; // 错误处理
// RPC场景额外需要的模块(跨设备通信)
import { distributedDeviceManager } from '@kit.DistributedServiceKit';
三、客户端开发步骤
3.1 创建Want和Connect
IPC场景(同设备通信)
// 定义变量
let proxy: rpc.IRemoteObject | undefined;
let want: Want = {
// 包名和组件名写实际的值
bundleName: "ohos.rpc.test.server", // 服务端应用包名
abilityName: "ohos.rpc.test.server.ServiceAbility", // 服务端Ability名称
};
// 创建连接选项
let connect: common.ConnectOptions = {
// 连接成功回调
onConnect: (elementName, remoteProxy) => {
hilog.info(0x0000, 'testTag', 'RpcClient: js onConnect called');
proxy = remoteProxy; // 保存服务端代理对象
},
// 断开连接回调
onDisconnect: (elementName) => {
hilog.info(0x0000, 'testTag', 'RpcClient: onDisconnect');
},
// 连接失败回调
onFailed: () => {
hilog.info(0x0000, 'testTag', 'RpcClient: onFailed');
}
};
RPC场景(跨设备通信)
let dmInstance: distributedDeviceManager.DeviceManager | undefined;
let proxy: rpc.IRemoteObject | undefined;
let deviceList: Array<distributedDeviceManager.DeviceBasicInfo> | undefined;
let networkId: string | undefined;
let want: Want | undefined;
let connect: common.ConnectOptions | undefined;
// 1. 创建设备管理器
try {
dmInstance = distributedDeviceManager.createDeviceManager("ohos.rpc.test");
} catch (error) {
let err: BusinessError = error as BusinessError;
hilog.error(0x0000, 'testTag',
'createDeviceManager errCode:' + err.code + ', errMessage:' + err.message);
}
// 2. 获取目标设备NetworkId
if (dmInstance != undefined) {
try {
deviceList = dmInstance.getAvailableDeviceListSync();
if (deviceList.length !== 0) {
networkId = deviceList[0].networkId; // 获取第一个可用设备的NetworkId
// 3. 创建Want,包含deviceId
want = {
bundleName: "ohos.rpc.test.server",
abilityName: "ohos.rpc.test.service.ServiceAbility",
deviceId: networkId, // 指定目标设备
};
// 4. 创建连接选项
connect = {
onConnect: (elementName, remoteProxy) => {
hilog.info(0x0000, 'testTag', 'RpcClient: js onConnect called');
proxy = remoteProxy;
},
onDisconnect: (elementName) => {
hilog.info(0x0000, 'testTag', 'RpcClient: onDisconnect');
},
onFailed: () => {
hilog.info(0x0000, 'testTag', 'RpcClient: onFailed');
}
};
}
} catch (error) {
let err: BusinessError = error as BusinessError;
hilog.error(0x0000, 'testTag', 'createDeviceManager err:' + err);
}
}
3.2 连接服务
FA模型(Feature Ability)
import { featureAbility } from '@kit.AbilityKit';
// 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入
let connectId = featureAbility.connectAbility(want, connect);
Stage模型
// 获取UIAbilityContext
let context: common.UIAbilityContext = this.getUIContext().getHostContext();
// 连接ServiceExtensionAbility
let connectId = context.connectServiceExtensionAbility(want, connect);
注意事项:
-
connectId必须保存,断开连接时需要用到 -
在Stage模型中,需要通过
getUIContext().getHostContext()获取UIAbilityContext
3.3 发送消息到服务端
成功连接服务后,可以通过onConnect回调函数获取服务端的代理对象Proxy,然后使用该Proxy调用sendMessageRequest方法发起请求。
import { rpc } from '@kit.IPCKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
// 此示例代码段中的proxy是在与服务端连接成功后的onConnect回调里拿到的proxy
let proxy: rpc.IRemoteObject | undefined;
// 使用Promise契约发送请求
let option = new rpc.MessageOption(); // 消息选项
let data = rpc.MessageSequence.create(); // 发送数据序列
let reply = rpc.MessageSequence.create(); // 接收数据序列
// 在data里写入参数,以传递字符串为例
data.writeString("hello world");
if (proxy != undefined) {
proxy.sendMessageRequest(1, data, reply, option)
.then((result: rpc.RequestResult) => {
if (result.errCode != 0) {
hilog.error(0x0000, 'testTag',
'sendMessageRequest failed, errCode: ' + result.errCode);
return;
}
// 从result.reply里读取结果
// 此处是根据前面创建ServiceExtensionAbility,实现服务端做的示例
let response = result.reply.readString();
hilog.info(0x0000, 'testTag', '收到服务端响应: ' + response);
})
.catch((e: Error) => {
hilog.error(0x0000, 'testTag', 'sendMessageRequest got exception: ' + e);
})
.finally(() => {
// 释放资源
data.reclaim();
reply.reclaim();
});
}
sendMessageRequest参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| code | number | 请求码,用于区分不同的请求类型 |
| data | MessageSequence | 发送给服务端的数据 |
| reply | MessageSequence | 接收服务端返回的数据 |
| option | MessageOption | 消息选项(如同步/异步) |
MessageSequence常用方法:
| 方法 | 说明 |
|---|---|
| writeString(val: string) | 写入字符串 |
| writeInt(val: number) | 写入整型 |
| writeBoolean(val: boolean) | 写入布尔值 |
| writeParcelable(val: Object) | 写入可序列化对象 |
| readString() | 读取字符串 |
| readInt() | 读取整型 |
| reclaim() | 释放资源 |
四、服务端开发步骤
4.1 创建Stub对象
服务端需要在onConnect回调函数里返回继承自rpc.RemoteObject的Stub对象,该对象需要实现onRemoteMessageRequest方法,处理客户端的请求。
import { rpc } from '@kit.IPCKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
class Stub extends rpc.RemoteObject {
constructor(descriptor: string) {
super(descriptor);
}
// 处理客户端请求的核心方法
onRemoteMessageRequest(code: number, data: rpc.MessageSequence,
reply: rpc.MessageSequence,
option: rpc.MessageOption): boolean | Promise<boolean> {
// 服务端Stub根据不同的请求code分别执行对应的处理流程
if (code == 1) {
// 读取客户端发送的数据
let str = data.readString();
hilog.info(0x0000, 'testTag', 'stub receive str : ' + str);
// 服务端使用reply回传请求处理的结果给客户端
reply.writeString("hello rpc");
return true; // 处理成功
} else {
hilog.info(0x0000, 'testTag', 'stub unknown code: ' + code);
return false; // 未知请求码
}
}
}
4.2 在ServiceExtensionAbility中返回Stub
// ServiceAbility.ts
import { ServiceExtensionAbility, Want } from '@kit.AbilityKit';
import { rpc } from '@kit.IPCKit';
export default class ServiceAbility extends ServiceExtensionAbility {
// 当客户端连接时调用,需要返回Stub对象
onConnect(want: Want): rpc.RemoteObject {
return new Stub("service stub");
}
// 其他生命周期方法...
}
Stub对象说明:
-
onRemoteMessageRequest是处理客户端请求的核心方法 -
code参数用于区分不同的业务请求 -
必须通过
reply返回处理结果给客户端 -
返回
true表示处理成功,false表示失败
五、断开连接
通信结束后,需要断开与服务的连接,释放资源。
FA模型
import { featureAbility } from "@kit.AbilityKit";
import { hilog } from '@kit.PerformanceAnalysisKit';
function disconnectCallback() {
hilog.info(0x0000, 'testTag', 'disconnect ability done');
}
// 断开连接,使用连接服务成功时保存下来的connectId断开连接
featureAbility.disconnectAbility(connectId, disconnectCallback);
Stage模型
// 获取UIAbilityContext
let context: common.UIAbilityContext = this.getUIContext().getHostContext();
// 断开连接,使用连接服务成功时保存下来的connectId断开连接
context.disconnectServiceExtensionAbility(connectId);
注意事项
线程模型
-
IPC/RPC调用默认是同步的,可通过
MessageOption设置为异步 -
服务端的
onRemoteMessageRequest运行在IPC线程,不应执行耗时操作
-
确保bundleName和abilityName正确无误
-
RPC场景需要正确获取目标设备的NetworkId
-
跨设备通信需要确保设备在同一个组网内
数据序列化
支持的数据类型:
-
基本类型:string、number、boolean
-
实现了
Parcelable接口的自定义对象 -
数组和List集合
更多推荐



所有评论(0)