• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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|![](image/client.png)|![](image/service.png)|
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  ![](image/fingerprint.png)
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![](image/permission.png)
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```