• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# IPC与RPC通信开发指导(ArkTS)
2<!--Kit: IPC Kit-->
3<!--Subsystem: Communication-->
4<!--Owner: @xdx19211@luodonghui0157-->
5<!--Designer: @zhaopeng_gitee-->
6<!--Tester: @maxiaorong-->
7<!--Adviser: @zhang_yixin13-->
8
9## 场景介绍
10
11IPC/RPC的主要工作是跨进程建立对象通信的连接(客户端进程的Proxy和服务端进程的Stub建立一一对应关系),从而通过Proxy的接口可以和Stub进行IPC/RPC通信。
12
13## 开发步骤
14
15> **说明:**
16>
17> - 当前不支持三方应用实现ServiceExtensionAbility,三方应用的UIAbility组件可以通过[Context](../application-models/uiability-usage.md#获取uiability的上下文信息)连接系统提供的ServiceExtensionAbility。
18>
19> - 使用场景约束:客户端是第三方/系统应用,服务端是系统应用/服务。
20
21### 创建ServiceExtensionAbility,实现服务端
22
23在工程中手动新建一个ServiceExtensionAbility,具体步骤如下:
24
251. 在工程Module的ets目录下,右键选择“New > Directory”,新建一个目录并命名为ServiceExtAbility。
26
272. 在ServiceExtAbility目录,右键选择“New > ArkTS File”,新建一个文件并命名为ServiceExtAbility.ets28
29    ```
30      ├── ets
31      │ ├── ServiceExtAbility
32      │ │   ├── ServiceExtAbility.ets
3334    ```
35
363. 在ServiceExtAbility.ets文件中,导入ServiceExtensionAbility的依赖包,自定义类继承ServiceExtensionAbility并实现生命周期回调。定义一个继承自[rpc.RemoteObject](../reference/apis-ipc-kit/js-apis-rpc.md#remoteobject)的stub类,实现[onRemoteMessageRequest](../reference/apis-ipc-kit/js-apis-rpc.md#onremotemessagerequest9)方法,用来处理客户端的请求。在onConnect生命周期回调函数里,创建之前定义的Stub对象并返回。
37
38   ```ts
39    import { ServiceExtensionAbility, Want } from '@kit.AbilityKit';
40    import { rpc } from '@kit.IPCKit';
41    import { hilog } from '@kit.PerformanceAnalysisKit';
42
43    // 定义服务端
44    class Stub extends rpc.RemoteObject {
45      constructor(descriptor: string) {
46        super(descriptor);
47      }
48      // 业务自行复写onRemoteMessageRequest方法,用来处理客户端的请求
49      onRemoteMessageRequest(code: number, data: rpc.MessageSequence, reply: rpc.MessageSequence, option: rpc.MessageOption): boolean | Promise<boolean> {
50        // 根据code处理客户端的请求
51        switch (code) {
52          case 1:
53            {
54              // 按照客户端写入顺序读取对应数据,具体看业务逻辑
55              // 此处是根据后面客户端发送信息给服务端做的示例
56              data.readString();
57              reply.writeString('huichuanxinxi');
58            }
59        }
60        return true;
61      }
62    }
63
64    // 定义后台服务
65    export default class ServiceAbility extends ServiceExtensionAbility {
66      onCreate(want: Want): void {
67        hilog.info(0x0000, 'testTag', 'onCreate');
68      }
69
70      onRequest(want: Want, startId: number): void {
71        hilog.info(0x0000, 'testTag', 'onRequest');
72      }
73
74      onConnect(want: Want): rpc.RemoteObject {
75        hilog.info(0x0000, 'testTag', 'onConnect');
76        // 返回Stub对象,客户端获取后便可以与ServiceExtensionAbility进行通信
77        return new Stub('rpcTestAbility');
78      }
79
80      onDisconnect(want: Want): void {
81        hilog.info(0x0000, 'testTag', 'onDisconnect');
82      }
83
84      onDestroy(): void {
85        hilog.info(0x0000, 'testTag', 'onDestroy');
86      }
87    }
88   ```
89
90### 客户端连接服务,获取服务代理对象Proxy
91
92**创建变量want和connect**
93
941. 创建变量want,指定要连接的Ability所在应用的包名、组件名。在跨设备的场景下,还需要连接目标设备的NetworkId(组网场景下对应设备的标识符,可以使用distributedDeviceManager获取目标设备的NetworkId)。
95
962. 创建变量connect,指定连接成功、连接失败和断开连接时的回调函数。
97
98  在IPC场景中,创建变量want和connect。
99  ```ts
100    import { Want, common } from '@kit.AbilityKit';
101    import { rpc } from '@kit.IPCKit';
102    import { hilog } from '@kit.PerformanceAnalysisKit';
103
104    let proxy: rpc.IRemoteObject | undefined;
105
106    let want: Want = {
107      // 包名和组件名写实际的值
108      bundleName: "ohos.rpc.test.server",
109      abilityName: "ohos.rpc.test.server.ServiceAbility",
110    };
111    let connect: common.ConnectOptions = {
112      onConnect: (elementName, remoteProxy) => {
113        hilog.info(0x0000, 'testTag', 'RpcClient: js onConnect called');
114        proxy = remoteProxy;
115      },
116      onDisconnect: (elementName) => {
117        hilog.info(0x0000, 'testTag', 'RpcClient: onDisconnect');
118      },
119      onFailed: () => {
120        hilog.info(0x0000, 'testTag', 'RpcClient: onFailed');
121      }
122    };
123  ```
124
125  在RPC场景中,创建变量want和connect。
126  ```ts
127    import { Want, common } from '@kit.AbilityKit';
128    import { rpc } from '@kit.IPCKit';
129    import { hilog } from '@kit.PerformanceAnalysisKit';
130    import { distributedDeviceManager } from '@kit.DistributedServiceKit';
131    import { BusinessError } from '@kit.BasicServicesKit';
132
133    let dmInstance: distributedDeviceManager.DeviceManager | undefined;
134    let proxy: rpc.IRemoteObject | undefined;
135    let deviceList: Array<distributedDeviceManager.DeviceBasicInfo> | undefined;
136    let networkId: string | undefined;
137    let want: Want | undefined;
138    let connect: common.ConnectOptions | undefined;
139
140    try{
141      dmInstance = distributedDeviceManager.createDeviceManager("ohos.rpc.test");
142    } catch(error) {
143      let err: BusinessError = error as BusinessError;
144      hilog.error(0x0000, 'testTag', 'createDeviceManager errCode:' + err.code + ', errMessage:' + err.message);
145    }
146
147    // 使用distributedDeviceManager获取目标设备NetworkId
148    if (dmInstance != undefined) {
149      try {
150        deviceList = dmInstance.getAvailableDeviceListSync();
151        if (deviceList.length !== 0) {
152          networkId = deviceList[0].networkId;
153          want = {
154            bundleName: "ohos.rpc.test.server",
155            abilityName: "ohos.rpc.test.service.ServiceAbility",
156            deviceId: networkId,
157          };
158          connect = {
159            onConnect: (elementName, remoteProxy) => {
160              hilog.info(0x0000, 'testTag', 'RpcClient: js onConnect called');
161              proxy = remoteProxy;
162            },
163            onDisconnect: (elementName) => {
164              hilog.info(0x0000, 'testTag', 'RpcClient: onDisconnect');
165            },
166            onFailed: () => {
167              hilog.info(0x0000, 'testTag', 'RpcClient: onFailed');
168            }
169          };
170        }
171      }catch(error) {
172        let err: BusinessError = error as BusinessError;
173        hilog.error(0x0000, 'testTag', 'createDeviceManager err:' + err);
174      }
175    }
176  ```
177
178**连接服务**
179
180  FA模型使用[connectAbility](../reference/apis-ability-kit/js-apis-ability-featureAbility.md#featureabilityconnectability7)接口连接Ability。
181
182  <!--code_no_check_fa-->
183  ```ts
184    import { featureAbility } from '@kit.AbilityKit';
185
186    // 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入
187    let connectId = featureAbility.connectAbility(want, connect);
188  ```
189
190  Stage模型使用common.UIAbilityContext的[connectServiceExtensionAbility](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectserviceextensionability)接口连接Ability。
191  在本文档的示例中,通过this.getUIContext().getHostContext()来获取UIAbilityContext,其中this代表继承自UIAbility的UIAbility实例。如需要在页面中使用UIAbilityContext提供的能力,请参见[获取UIAbility的上下文信息](../application-models/uiability-usage.md#获取uiability的上下文信息)。
192
193  <!--code_no_check-->
194  ```ts
195
196    let context: common.UIAbilityContext = this.getUIContext().getHostContext(); // UIAbilityContext
197    // 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入
198    let connectId = context.connectServiceExtensionAbility(want,connect);
199   ```
200
201### 客户端发送信息给服务端
202
203   成功连接服务后,可以通过onConnect回调函数获取服务端的代理对象Proxy。然后,使用该Proxy调用[sendMessageRequest](../reference/apis-ipc-kit/js-apis-rpc.md#sendmessagerequest9-2)方法发起请求。当服务端处理请求并返回数据时,可在Promise契约(用于表示一个异步操作的成功/失败的结果值)中接收结果。
204
205   ```ts
206    import { rpc } from '@kit.IPCKit';
207    import { hilog } from '@kit.PerformanceAnalysisKit';
208
209    // 此示例代码段中的proxy是在与服务端连接成功后的onConnect回调里拿到的proxy
210    let proxy: rpc.IRemoteObject | undefined;
211
212    // 使用Promise契约
213    let option = new rpc.MessageOption();
214    let data = rpc.MessageSequence.create();
215    let reply = rpc.MessageSequence.create();
216    // 在data里写入参数,以传递字符串为例
217    data.writeString("hello world");
218
219    if (proxy != undefined) {
220      proxy.sendMessageRequest(1, data, reply, option)
221        .then((result: rpc.RequestResult) => {
222          if (result.errCode != 0) {
223            hilog.error(0x0000, 'testTag', 'sendMessageRequest failed, errCode: ' + result.errCode);
224            return;
225          }
226          // 从result.reply里读取结果
227          // 此处是根据前面创建ServiceExtensionAbility,实现服务端做的示例
228          result.reply.readString();
229        })
230        .catch((e: Error) => {
231          hilog.error(0x0000, 'testTag', 'sendMessageRequest got exception: ' + e);
232        })
233        .finally(() => {
234          data.reclaim();
235          reply.reclaim();
236        })
237    }
238   ```
239
240### 服务端处理客户端请求
241
242   服务端在onConnect回调函数里返回继承自[rpc.RemoteObject](../reference/apis-ipc-kit/js-apis-rpc.md#remoteobject)的Stub对象,该对象需要实现[onRemoteMessageRequest](../reference/apis-ipc-kit/js-apis-rpc.md#onremotemessagerequest9)方法,处理客户端的请求。
243
244   ```ts
245    import { rpc } from '@kit.IPCKit';
246    import { hilog } from '@kit.PerformanceAnalysisKit';
247
248    class Stub extends rpc.RemoteObject {
249      constructor(descriptor: string) {
250        super(descriptor);
251      }
252      onRemoteMessageRequest(code: number, data: rpc.MessageSequence, reply: rpc.MessageSequence, option: rpc.MessageOption): boolean | Promise<boolean> {
253        // 服务端Stub根据不同的请求code分别执行对应的处理流程
254        if (code == 1) {
255          let str = data.readString();
256          hilog.info(0x0000, 'testTag', 'stub receive str : ' + str);
257          // 服务端使用reply回传请求处理的结果给客户端
258          reply.writeString("hello rpc");
259          return true;
260        } else {
261            hilog.info(0x0000, 'testTag', 'stub unknown code: ' + code);
262            return false;
263        }
264      }
265    }
266   ```
267
268### 断开连接
269
270   IPC通信结束后,FA模型使用[disconnectAbility](../reference/apis-ability-kit/js-apis-ability-featureAbility.md#featureabilitydisconnectability7)接口断开连接,此处的connectId是在连接服务时保存的。
271
272  <!--code_no_check_fa-->
273  ```ts
274    import { featureAbility } from "@kit.AbilityKit";
275    import { hilog } from '@kit.PerformanceAnalysisKit';
276
277    function disconnectCallback() {
278      hilog.info(0x0000, 'testTag', 'disconnect ability done');
279    }
280    // 断开连接,使用连接服务成功时保存下来的connectId断开连接
281    featureAbility.disconnectAbility(connectId, disconnectCallback);
282   ```
283
284   Stage模型使用common.UIAbilityContext提供的[disconnectServiceExtensionAbility](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectserviceextensionability-1)接口断开连接,此处的connectId是在连接服务时保存的。
285   在本文档的示例中,通过this.getUIContext().getHostContext()来获取UIAbilityContext,其中this代表继承自UIAbility的UIAbility实例。如需要在页面中使用UIAbilityContext提供的能力,请参见[获取UIAbility的上下文信息](../application-models/uiability-usage.md#获取uiability的上下文信息)。
286
287  <!--code_no_check-->
288  ```ts
289    let context: common.UIAbilityContext = this.getUIContext().getHostContext(); // UIAbilityContext
290
291    // 断开连接,使用连接服务成功时保存下来的connectId断开连接
292    context.disconnectServiceExtensionAbility(connectId);
293   ```
294
295## 完整示例
296
297针对IPC与RPC通信开发,端到端的完整示例,请参考:
298
299- [IPC通信完整样例-使用Parcelable/ArrayBuffer通信](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/SystemFeature/IPC/ObjectTransfer)