README.md
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```