1# IPC通信示例 2 3## 一、介绍 4 5本示例展示了如何使用[@ohos.rpc](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-ipc-kit/js-apis-rpc.md) 相关接口,开发一个IPC客户端与服务端通信的完整示例,并在此示例中演示如何使用Parcelable/ArrayBuffer对象传递字符串信息。 6 7### 1.1、示例界面: 8|客户端|服务端| 9|-----------------|----------------------| 10||| 11 12### 1.2、使用说明: 13 141. 点击“获取服务端代理”进行连接服务端,在“发送Parcelable”和“发送ArrayBuffer”底下的输入框中输入发送内容,点击对应按钮即可发送字符串信息至服务端; 15 162. 在服务端的“显示接收到的Parcelable”、“显示接收到的ArrayBuffer”文本下显示从客户端发来的对应信息; 17 18 19## 二、工程目录 20### 客户端-IPC_Client 21``` 22entry/src/main/ets/ 23|---entryability 24| |---EntryAbility.ets // 入口文件 25|---pages 26| |---Index.ets // 页面布局 27|---service/cnn 28| |---IPC_Client.ets // 客户端能力,连接服务端,发送Parcelable和ArrayBuffer 29``` 30 31### 服务端-IPC_Service 32``` 33entry/src/main/ets/ 34|---entryability 35| |---EntryAbility.ets // 入口文件 36|---pages 37| |---Index.ets // 页面布局 38|---serviceextability 39| |---IPC_Service.ets // 服务端能力,接收、处理数据 40| |---ServiceExtAbility.ets // Service通用能力 41``` 42 43## 三、具体实现 44 45* 本示例分为两大模块 46 47 ### 3.1、客户端与服务端的连接和断开模块 48 49 * 3.1.1、获取服务端代理:按下按钮后,通过connectIpc()中的connectServiceExtensionAbility()进行连接服务端; 50 ``` 51 let connect: common.ConnectOptions = { 52 //回调获取请求结果 53 onConnect: (elementName, remoteProxy) => { 54 hilog.info(DOMAIN, TAG, 'IpcClient:onConnect.callend(server),elementName:'+ 55 JSON.stringify(elementName)) 56 proxy = remoteProxy 57 ObtainResult.Result = 'success' 58 callback() 59 }, 60 onDisconnect: (elementName) => { 61 hilog.info(DOMAIN, TAG, 'IpcClient onDisconnect:' + elementName) 62 }, 63 onFailed: (code: number) => { 64 ObtainResult.Result = 'error '+code 65 hilog.info(DOMAIN, TAG, 'IpcClient onFailed,code:' + code) 66 callback() 67 }, 68 } 69 70 //连接至服务端扩展功能 71 connectid = context.connectServiceExtensionAbility(want, connect) 72 hilog.info(DOMAIN, TAG, 'IpcClient connectid:' + connectid) 73 ``` 74 * 3.1.2、断开服务端代理:按下按钮后,通过disConnectIpc()disconnectServiceExtensionAbility()进行断开连接; 75 ``` 76 function disConnectIpc(context: common.UIAbilityContext) { 77 if (connectid != undefined) { 78 context.disconnectServiceExtensionAbility(connectid); 79 proxy = undefined; 80 } 81 } 82 ``` 83 84 源码参考:[IPC_Client.ets](entry/src/main/ets/client/cnn/IPC_Client.ets); 85 86 接口参考:[@ohos.rpc](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-ipc-kit/js-apis-rpc.md); 87 88 [IPC与RPC通信开发指南](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/ipc/ipc-rpc-development-guideline.md) 89 90 91 ### 3.2、客户端发送数据与服务端接收数据 92 93 * 3.2.1、通过Parcelable对象发送数据: 94 95 (1).在客户端的IPC_Client.ets中的sendParcelable()中通过rpc.MessageSequence.create()创建MessageSequence对象; 96 ``` 97 let data = rpc.MessageSequence.create() 98 ``` 99 (2).通过MessageSequence.writeParcelable()将封装字符串信息的Parcelable对象写入MessageSequence对象中; 100 ``` 101 //取决于MyParcelable类如何定义,或需要序列化时准备传递什么数据类型; 102 //本示例中MyParcelable是以number和string为例,且服务端接收string 103 let parcelable = new MyParcelable(1, str); 104 data.writeParcelable(parcelable); 105 ``` 106 (3).通过sendData()中的rpc.RemoteObject.sendMessageRequest()将包裹待发送字符串的Parcelable对象发送到服务端进程中; 107 ``` 108 //用连接服务成功后返回的对象proxy,进行消息发送 109 proxy.sendMessageRequest(code, data, reply, options) 110 .then((result: rpc.RequestResult) => { 111 if (result.errCode === 0) { 112 hilog.info(DOMAIN, TAG, 'sendMessageRequest got result'); 113 try { 114 let rsp = result.reply.readString() 115 hilog.info(DOMAIN, TAG, 'IpcClient result.' + rsp); 116 } catch (error) { 117 let e: BusinessError = error as BusinessError; 118 hilog.error(DOMAIN, TAG, 'rpc read exception fail, error is ' + e); 119 } 120 } else { 121 hilog.error(DOMAIN, TAG, 'RPCTest: sendMessageRequest failed, errCode: ' + result.errCode); 122 } 123 }).catch((e: Error) => { 124 hilog.error(DOMAIN, TAG, 'RPCTest: sendMessageRequest got exception: ' + e); 125 }).finally (() => { 126 hilog.info(DOMAIN, TAG, 'RPCTest: sendMessageRequest ends, reclaim parcel'); 127 data.reclaim(); 128 reply.reclaim(); 129 }); 130 ``` 131 132 * 3.2.2、通过ArrayBuffer对象发送数据: 133 134 (1).在客户端的IPC_Client.ets中的sendArrayBuffer()中通过rpc.MessageSequence.create()创建MessageSequence对象; 135 ``` 136 let data = rpc.MessageSequence.create() 137 ``` 138 139 (2).然后将待发送字符串转为ArrayBuffer,之后通过MessageSequence.writeArrayBuffer()将ArrayBuffer对象写入MessageSequence对象中; 140 ``` 141 let buffer = new ArrayBuffer(str.length); 142 let Uint8View = new Uint8Array(buffer); 143 for (let i = 0; i < str.length; i++) { 144 Uint8View[i] = str.charCodeAt(i); 145 } 146 //进行校验 147 data.writeInterfaceToken(proxy.getDescriptor()) 148 //写入ArrayBuffer 149 data.writeArrayBuffer(buffer, rpc.TypeCode.UINT8_ARRAY); 150 ``` 151 152 (3).通过sendData()中的rpc.RemoteObject.sendMessageRequest()将包裹待发送字符串的ArrayBuffer对象发送到服务端进程中; 153 ``` 154 //用连接服务成功后返回的对象proxy,进行消息发送 155 proxy.sendMessageRequest(code, data, reply, options) 156 .then((result: rpc.RequestResult) => { 157 if (result.errCode === 0) { 158 hilog.info(DOMAIN, TAG, 'sendMessageRequest got result'); 159 try { 160 let rsp = result.reply.readString() 161 hilog.info(DOMAIN, TAG, 'IpcClient result.' + rsp); 162 } catch (error) { 163 let e: BusinessError = error as BusinessError; 164 hilog.error(DOMAIN, TAG, 'rpc read exception fail, error is ' + e); 165 } 166 } else { 167 hilog.error(DOMAIN, TAG, 'RPCTest: sendMessageRequest failed, errCode: ' + result.errCode); 168 } 169 }).catch((e: Error) => { 170 hilog.error(DOMAIN, TAG, 'RPCTest: sendMessageRequest got exception: ' + e); 171 }).finally (() => { 172 hilog.info(DOMAIN, TAG, 'RPCTest: sendMessageRequest ends, reclaim parcel'); 173 data.reclaim(); 174 reply.reclaim(); 175 }); 176 ``` 177 源码参考:[IPC_Client.ets](entry/src/main/ets/client/cnn/IPC_Client.ets); 178 179 接口参考:[@ohos.rpc](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-ipc-kit/js-apis-rpc.md); 180 181 [IPC与RPC通信开发指南](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/ipc/ipc-rpc-development-guideline.md); 182 183 * 3.2.3、服务端读取数据: 184 185 (1).创建一个ServiceExtensionAbility,并在onConnect回调中返回一个StubServer对象; 186 ``` 187 let globalStubServer: StubServer | undefined 188 189 function getInstance(): StubServer { 190 if (globalStubServer == undefined) { 191 globalStubServer = new StubServer('serverStub_App2') 192 } 193 return globalStubServer 194 } 195 196 export default class ServiceExtension extends ServiceExtensionAbility { 197 onCreate(want: Want) { 198 hilog.info(DOMAIN, TAG, 'ServiceExtensionAbility onCreate,want param:' + JSON.stringify(want) ?? ' ') 199 } 200 201 onRequest(want: Want, startId: number) { 202 hilog.info(DOMAIN, TAG, 203 'ServiceExtensionAbility onRequest,want param:' + JSON.stringify(want) ?? "+,startId:" + JSON.stringify(startId)) 204 } 205 206 onConnect(want: Want): rpc.RemoteObject | Promise<rpc.RemoteObject> { 207 hilog.info(DOMAIN, TAG, 'ServiceExtensionAbility onConnect,want param:' + JSON.stringify(want) ?? "") 208 return getInstance() 209 } 210 211 onDisconnect(want: Want) { 212 hilog.info(DOMAIN, TAG, 'ServiceExtensionAbility onDisconnect,want param::' + JSON.stringify(want)) 213 } 214 215 onDestroy() { 216 hilog.info(DOMAIN, TAG, 'ServiceExtensionAbility onDestroy') 217 } 218 } 219 ``` 220 221 (2).处理MessageRequest请求的接口封装在StubServer里面,在这里接收传递来的数据; 222 ``` 223 onRemoteMessageRequest(code: number, data: rpc.MessageSequence, reply: rpc.MessageSequence, 224 options: rpc.MessageOption): boolean | Promise<boolean> { 225 hilog.info(DOMAIN, TAG, 'Client Send code:' + code) 226 let descriptor = this.getDescriptor() 227 // 进行校验 228 if (descriptor != data.readInterfaceToken()) { 229 hilog.info(DOMAIN, TAG, 'VERIFICATION FAILED'); 230 return false; 231 } 232 233 onHandleClientReq(code, data, reply) 234 return true 235 } 236 ``` 237 238 (3).然后经过onHandleClientReq()处理接收的MessageSequence信息,通过不同的code值(Parcelable:1001,ArrayBuffer:1002),分别使用rpc.RemoteObject.readParcelable()和rpc.RemoteObject.readArrayBuffer()获取传递来的对象,通过解析该对象获得客户端传递来的字符串; 239 ``` 240 function onHandleClientReq(code: number, data: rpc.MessageSequence, reply: rpc.MessageSequence) { 241 hilog.info(DOMAIN, TAG, 'onHandle Client,code:' + code) 242 switch (code) { 243 //接收Parcelable对象 244 case 1001: 245 let parcelable = new MyParcelable(0, ''); 246 data.readParcelable(parcelable); 247 dataStatus.updataParcelable(parcelable.str) 248 hilog.info(DOMAIN, TAG, 'read parcelable: ' + parcelable.str); 249 break 250 //接收ArrayBuffer对象 251 case 1002: 252 let result = data.readArrayBuffer(rpc.TypeCode.UINT8_ARRAY); 253 let decoder = util.TextDecoder.create('utf-8'); 254 let stringData = decoder.decodeToString(new Uint8Array(result)); 255 dataStatus.updataArrayBuffer(stringData) 256 hilog.info(DOMAIN, TAG, 'read arraybuffer: ' + stringData); 257 break 258 default: 259 hilog.info(DOMAIN, TAG, 'onHandleClient-default,code: ' + 1001); 260 break 261 } 262 } 263 ``` 264 源码参考:[IPC_Service.ets](../IPC_Service/entry/src/main/ets/serviceextability/IPC_Service.ets); 265 266 接口参考:[@ohos.rpc](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-ipc-kit/js-apis-rpc.md); 267 268 [IPC与RPC通信开发指南](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/ipc/ipc-rpc-development-guideline.md); 269 270 271## 四、相关权限 272 273由于Service Ability(服务端所在应用)只能被系统应用调用,所以IPC通信机制在单框架上不对普通应用开放,故服务端需要申请系统应用权限。 274(服务端需提供ohos-sdk-full) 275 2764.1、配置权限:在服务端entry下的module中配置如下权限:[module.json5](IPC_Service/entry/src/main/module.json5),参考第38-45行。 277 ``` 278 "extensionAbilities": [ 279 //配置IpcServiceExtAbility能力 280 { 281 "name": "IpcServiceExtAbility", 282 "srcEntry": "./ets/serviceextability/ServiceExtAbility.ets", 283 "type": "service", 284 "exported": true, 285 "description": "service" 286 } 287 ] 288 ``` 289 2904.2、将“4.1.配置权限”中添加的权限注释起来,然后运行工程,在设备上推送服务端hap。 291 2924.3、将服务端需要的系统应用权限注册到设备: 293 294 4.3.1、 获取签名指纹,及获取install_list_capability.json文件 295 296  297 298 4.3.2、 在拉取到本地的install_list_capability.json文件中添加如下权限信息: 299 300 301 { 302 "bundleName": "应用包名", 303 "app_signature": ["4.3.1获取到的签名指纹"], 304 //添加系统应用权限 305 "allowAppUsePrivilegeExtension": true 306 }, 307 308 309 310 4.3.3、 将添加权限后的install_list_capability.json文件推送至设备原路径,并重启设备 311 312 ``` 313 hdc shell mount -o rw,remount / 314 hdc file send install_list_capability.json /system/etc/app/install_list_capability.json 315 hdc shell chmod 777 /system/etc/app/install_list_capability.json 316 hdc shell reboot 317 ``` 318 319 3204.4、将“4.1.配置权限”中添加的权限取消注释,然后运行工程,此时的hap具有IpcServiceExtAbility。 321 322## 五、依赖 323 324本应用需依赖[IPC_Service](../IPC_Service/)端来进行IPC通信。 325 326## 六、约束与限制 327 3286.1、本示例仅支持在标准系统上运行,支持RK3568; 329 3306.2、本示例涉及使用系统接口:UIAbilityContext.connectServiceExtensionAbility,需要手动替换Full SDK才能编译通过,推荐使用最新版本Full SDK。[Full SDK下载链接](https://ci.openharmony.cn/workbench/cicd/dailybuild/dailylist); 331 3326.3、本示例推荐使用DevEco Studio 5.0.2 Beta1 (Build Version: 5.0.7.100 构建 2025年1月16日)及以上版本编译运行。 333 3346.4、本示例推荐使用API version 16版本SDK,版本号:5.1.0.46。 335 336## 七、下载 337 338如需单独下载本工程及服务端,执行如下命令: 339 340``` 341git init 342git config core.sparsecheckout true 343echo code/BasicFeature/Connectivity/IPC/ObjectTransfer/ > .git/info/sparse-checkout 344git remote add origin https://gitee.com/openharmony/applications_app_samples.git 345git pull origin master 346```