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