IPC通信示例
介绍
本示例展示了如何使用@ohos.rpc 相关接口,开发一个IPC客户端与服务端通信的完整示例。在此示例中仅演示如何传递字符串信息,若有除此之外接口的诉求,请自行参考接口文档中的示例代码。
效果预览
| 客户端 | 服务端 |
|---|---|
![]() |
![]() |
使用说明:
- 点击 connectAbility 按钮进行连接服务端,获取到服务端的代理对象proxy,并在此时注册死亡监听,当服务端所在进程死亡时,会触发此监听,提示服务端已死亡,并断开连接服务端;
- 点击 sendRequest_string 按钮传递字符串信息至服务端,服务端会收到这次传递的字符串('hello world'),并返回字符串('hello rpc')到客户端,代表此次通信结束;
- 点击 disconnectAbility 按钮断开连接服务端。
工程目录
- 客户端-IPC_Client
entry/src/main/ets/
|---entryability
| |---EntryAbility.ets
|---entrybackupability
| |---EntryBackupAbility.ets
|---pages
| |---Index.ets // 页面布局、客户端实现
- 服务端-IPC_Service
entry/src/main/ets/
|---entryability
| |---EntryAbility.ets
|---entrybackupability
| |---EntryBackupAbility.ets
|---pages
| |---Index.ets
|---serviceeextability
| |---ServiceExtAbility.ets // 服务端实现
以上工程目录中未进行说明的部分,是默认工程目录结构,并未进行修改。
具体实现
- 创建ServiceExtensionAbility,实现服务端
// 定义服务端
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 is ' + str);
// 服务端使用reply回传请求处理的结果给客户端
reply.writeString('hello rpc');
return true;
} else {
hilog.info(0x0000, 'testTag', 'stub unknown code is ' + code);
return false;
}
}
}
// 定义后台服务
export default class ServiceAbility extends ServiceExtensionAbility {
// ......
onConnect(want: Want): rpc.RemoteObject {
hilog.info(0x0000, 'testTag', 'onConnect');
// 返回Stub对象,客户端获取后便可以与ServiceExtensionAbility进行通信
return new Stub('IPCStubTest');
}
// ......
}
- 客户端连接服务
function connectAbility(context:common.UIAbilityContext, promptAction: PromptAction) {
hilog.info(0x00000, 'testTag', 'begin to connect Ability');
let want: Want = {
bundleName: 'com.example.ipc_stub',
abilityName: 'ServiceAbility',
};
let connect: common.ConnectOptions = {
onConnect: (elementName, remoteProxy) => {
hilog.info(0x00000, 'testTag', 'onConnect. elementName is :' + JSON.stringify(elementName));
proxy = remoteProxy;
// 客户端注册死亡监听
try {
proxy.registerDeathRecipient(deathRecipient, 0);
hilog.info(0x00000, 'testTag', 'registerDeathRecipient success');
} catch (err) {
let code = (err as BusinessError).code;
let message = (err as BusinessError).message;
hilog.error(0x0000, 'testTag', 'register failed, code is ' + code + ', message is ' + message);
}
// 弹窗显示成功连接服务
try {
promptAction.showToast({
message: 'connectAbility success',
duration: 2000
});
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
hilog.error(0x0000, 'testTag', 'showToast failed, code is ' + code + ', message is ' + message);
};
},
onDisconnect: (elementName) => {
hilog.info(0x0000, 'testTag', 'onDisconnect. elementName is ' + JSON.stringify(elementName));
// 客户端移除死亡监听
try {
proxy?.unregisterDeathRecipient(deathRecipient, 0);
hilog.info(0x00000, 'testTag', 'unregisterDeathRecipient success');
} catch (err) {
let code = (err as BusinessError).code;
let message = (err as BusinessError).message;
hilog.error(0x0000, 'testTag', 'unregister failed, code is ' + code + ', message is ' + message);
}
proxy = undefined;
isDisconnect = true;
// 弹窗显示与服务端断开连接成功
try {
promptAction.showToast({
message: 'disconnectAbility success',
duration: 2000
});
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
hilog.error(0x0000, 'testTag', 'showToast failed, code is ' + code + ', message is ' + message);
};
},
onFailed: (code: number) => {
hilog.info(0x0000, 'testTag', 'onFailed. code is ' + code);
// 弹窗显示连接服务失败
try {
promptAction.showToast({
message: 'Connect failed. Please ensure that the service is running in the background.',
duration: 2000
});
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
hilog.error(0x0000, 'testTag', 'showToast failed, code is ' + code + ', message is ' + message);
};
},
}
try {
connectId = context.connectServiceExtensionAbility(want, connect);
hilog.info(0x00000, 'testTag', 'begin to connect Ability end');
} catch (err) {
let code = (err as BusinessError).code;
let message = (err as BusinessError).message;
hilog.error(0x0000, 'testTag', 'connectAbility failed, code is ' + code + ', message is ' + message);
}
}
- 客户端发送字符串给服务端
async function sendString(promptAction: PromptAction) : Promise <void> {
hilog.info(0x00000, 'testTag', 'begin to send String');
let option = new rpc.MessageOption();
let data = rpc.MessageSequence.create();
let reply = rpc.MessageSequence.create();
// 在data里写入参数,以传递字符串为例
data.writeString('hello world');
if (proxy != undefined) {
await proxy.sendMessageRequest(1, data, reply, option)
.then((result: rpc.RequestResult) => {
if (result.errCode != 0) {
hilog.error(0x0000, 'testTag', 'sendMessageRequest failed, errCode is ' + result.errCode);
}
// 从result.reply里读取结果
let str = result.reply.readString();
hilog.info(0x0000, 'testTag', 'sendMessageRequest receive str is ' + str);
try {
promptAction.showToast({
message: 'sendRequest success',
duration: 2000
});
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
hilog.error(0x0000, 'testTag', 'showToast failed, code is ' + code + ', message is ' + message);
};
})
.catch((e: Error) => {
hilog.error(0x0000, 'testTag', 'sendMessageRequest failed, error is ' + JSON.stringify(e));
try {
promptAction.showToast({
message: 'sendRequest failed, please connect to the server first',
duration: 2000
});
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
hilog.error(0x0000, 'testTag', 'showToast failed, code is ' + code + ', message is ' + message);
};
})
.finally(() => {
data.reclaim();
reply.reclaim();
})
} else {
hilog.error(0x0000, 'testTag', 'proxy is invalid');
try {
promptAction.showToast({
message: 'sendRequest failed, please connect to the server first',
duration: 2000
});
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
hilog.error(0x0000, 'testTag', 'showToast failed, code is ' + code + ', message is ' + message);
};
}
hilog.info(0x0000, 'testTag', 'sendString end');
}
- 客户端断开连接服务
function disconnectAbility(context: common.UIAbilityContext) {
hilog.info(0x00000, 'testTag', 'begin to disconnect Ability. connectId is ' + connectId);
if (connectId != undefined) {
try {
context.disconnectServiceExtensionAbility(connectId);
} catch (err) {
let code = (err as BusinessError).code;
let message = (err as BusinessError).message;
hilog.error(0x0000, 'testTag', 'disconnect failed, code is ' + code + ', message is ' + message);
}
}
}
相关权限
不涉及
依赖
本示例中按键之间存在依赖关系,具体依赖如下:
- 服务端需保持在后台运行状态下,客户端才可以进行连接服务的操作('connectAbility');
- 在连接服务成功的情况下,客户端才可进行发送信息的操作('sendRequest_string');
- 在建立连接的情况下,客户端才可进行断连的操作('disconnectAbility')。
约束与限制
-
本示例仅支持标准系统上运行,支持设备:RK3568。
-
本示例推荐使用DevEco Studio 5.0.2 Beta1 (Build Version: 5.0.7.100 构建 2025年1月16日)及以上版本编译运行。
-
本示例需要使用@ohos.app.ability.ServiceExtensionAbility,该模块仅对系统应用开放,业务使用时,需自行替换当前工程中的SDK为FULL SDK。使用Full SDK时需要手动从镜像站点获取,并在DevEcoStudio中替换,具体操作可参考替换指南 。
-
本示例使用了ServiceExtensionAbility,需要在module.json5中进行相应的配置。如下:
在服务端entry下的module.json5中配置如下字段:module.json5,参考第48-54行。
"extensionAbilities": [
{
"name": "ServiceAbility",
"srcEntry": "./ets/serviceextability/ServiceExtAbility.ets",
"type": "service",
"exported": true,
"description": "service"
}
]
下载
如需单独下载本工程及服务端,执行如下命令:
git init
git config core.sparsecheckout true
echo code/DocsSample/IPC/IPC_sendMessage/ > .git/info/sparse-checkout
git remote add origin https://gitcode.com/openharmony/applications_app_samples.git
git pull origin master
安装问题(9568344)
因上述应用的module.json5中extensionAbilities字段中type属性为service,普通的安装方法会报错,需要按照以下方式进行安装:
- 注释module.json5中extensionAbilities字段

- 获取app_signature
hdc shell bm dump -n <bundleName> | findstr finger

- 添加白名单
将rk设备的install_list_capability.json配置文件拉取到本地
hdc shell mount -o rw,remount /
hdc file recv /system/etc/app/install_list_capability.json ---rk的方式

在拉下来的json文件中添加不能安装成功的应用,格式如下:
{
"install_list": [
{
......
},
{
"bundleName": "应用包名",
"app_signature" : ["上面获取的app_signature"],
"allowAppUsePrivilegeExtension": true
}
]
}

- 将修改后的白名单推送到设备上进行替换并重启
hdc shell mount -o rw,remount /
hdc file send install_list_capability.json /system/etc/app/install_list_capability.json
hdc shell chmod 777 /system/etc/app/install_list_capability.json
hdc shell reboot
- 取消module.json5中extensionAbilities的相关注释,重新安装hap包

