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.ets。 28 29 ``` 30 ├── ets 31 │ ├── ServiceExtAbility 32 │ │ ├── ServiceExtAbility.ets 33 └ 34 ``` 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)