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.ets。 22 23 ``` 24 ├── ets 25 │ ├── ServiceExtAbility 26 │ │ ├── ServiceExtAbility.ets 27 └ 28 ``` 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)