1# 远端状态订阅开发实例 2 3IPC/RPC提供了订阅远端Stub对象状态的机制。当远端Stub对象死亡时,可以自动触发本端Proxy注册的死亡通知。这种死亡通知订阅需要调用指定接口[registerDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#registerdeathrecipient9-1)完成。不再需要订阅时,也需要调用指定接口[unregisterDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#unregisterdeathrecipient9-1)取消订阅。 4 5使用这种订阅机制的用户需要继承死亡通知类[DeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#deathrecipient),并实现[onRemoteDied](../reference/apis-ipc-kit/js-apis-rpc.md#onremotedied)方法清理资源。该方法会在远端Stub对象所在进程退出或当前RPC通信依赖的软总线连接断开时被回调。 6 7> **注意:** 8> - 首先,Proxy订阅Stub死亡通知,若在订阅期间Stub状态正常,则在不再需要时取消订阅。 9> - 其次,若在订阅期间,Stub所在进程退出或当前RPC通信依赖的软总线连接断开,则会自动触发执行业务已向Proxy注册的自定义的[onRemoteDied](../reference/apis-ipc-kit/js-apis-rpc.md#onremotedied)方法。 10 11## 使用场景 12 13IPC/RPC的订阅机制适用于以下场景:</br> 141. IPC通信,Proxy对象需要感知远端Stub对象所在进程的状态。 152. RPC通信,Proxy对象需要感知远端Stub对象所在进程的状态,或者RPC通信依赖的软总线连接断开。 16当Proxy感知到Stub端死亡后,应该清理本地Proxy对象以及相关资源。 17> **注意:** RPC不支持匿名Stub对象(没有向SAMgr注册)的死亡通知,IPC支持匿名Stub对象的死亡通知。 18 19## ArkTS侧接口 20 21> **说明:** 22> 23> - 此文档中的示例代码描述的是系统应用跨进程通信。 24> 25> - 使用场景约束:客户端是第三方/系统应用,服务端是系统应用/服务 26 27| 接口名 | 返回值类型 | 功能描述 | 28| ------------------------------------------------------------ | ---------- | ------------------------------------------------------------ | 29| [registerDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#registerdeathrecipient9-1) | void | 注册用于接收远程对象死亡通知的回调,该方法应该在proxy侧调用。 | 30| [unregisterDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#unregisterdeathrecipient9-1) | void | 注销用于接收远程对象死亡通知的回调。 | 31| [onRemoteDied](../reference/apis-ipc-kit/js-apis-rpc.md#onremotedied) | void | Proxy侧注册死亡通知成功后,当远端Stub对象所在进程死亡时,将自动回调本方法。 | 32 33### 参考代码 34 35 在IPC场景中,创建变量want和connect。 36 ```ts 37 import { Want, common } from '@kit.AbilityKit'; 38 import { rpc } from '@kit.IPCKit'; 39 import { hilog } from '@kit.PerformanceAnalysisKit'; 40 import { distributedDeviceManager } from '@kit.DistributedServiceKit'; 41 42 let dmInstance: distributedDeviceManager.DeviceManager | undefined; 43 let proxy: rpc.IRemoteObject | undefined; 44 45 let want: Want = { 46 // 包名和组件名写实际的值 47 bundleName: "ohos.rpc.test.server", 48 abilityName: "ohos.rpc.test.server.ServiceAbility", 49 }; 50 let connect: common.ConnectOptions = { 51 onConnect: (elementName, remoteProxy) => { 52 hilog.info(0x0000, 'testTag', 'RpcClient: js onConnect called'); 53 proxy = remoteProxy; 54 }, 55 onDisconnect: (elementName) => { 56 hilog.info(0x0000, 'testTag', 'RpcClient: onDisconnect'); 57 }, 58 onFailed: () => { 59 hilog.info(0x0000, 'testTag', 'RpcClient: onFailed'); 60 } 61 }; 62 ``` 63 64 在RPC场景中,创建变量want和connect。 65 ```ts 66 import { Want, common } from '@kit.AbilityKit'; 67 import { rpc } from '@kit.IPCKit'; 68 import { hilog } from '@kit.PerformanceAnalysisKit'; 69 import { distributedDeviceManager } from '@kit.DistributedServiceKit'; 70 import { BusinessError } from '@kit.BasicServicesKit'; 71 72 let dmInstance: distributedDeviceManager.DeviceManager | undefined; 73 let proxy: rpc.IRemoteObject | undefined; 74 75 try{ 76 dmInstance = distributedDeviceManager.createDeviceManager("ohos.rpc.test"); 77 } catch(error) { 78 let err: BusinessError = error as BusinessError; 79 hilog.error(0x0000, 'testTag', 'createDeviceManager errCode:' + err.code + ', errMessage:' + err.message); 80 } 81 82 // 使用distributedDeviceManager获取目标设备NetworkId 83 if (dmInstance != undefined) { 84 let deviceList = dmInstance.getAvailableDeviceListSync(); 85 let networkId = deviceList[0].networkId; 86 let want: Want = { 87 bundleName: "ohos.rpc.test.server", 88 abilityName: "ohos.rpc.test.service.ServiceAbility", 89 deviceId: networkId, 90 }; 91 92 let connect: common.ConnectOptions = { 93 onConnect: (elementName, remoteProxy) => { 94 hilog.info(0x0000, 'testTag', 'RpcClient: js onConnect called'); 95 proxy = remoteProxy; 96 }, 97 onDisconnect: (elementName) => { 98 hilog.info(0x0000, 'testTag', 'RpcClient: onDisconnect'); 99 }, 100 onFailed: () => { 101 hilog.info(0x0000, 'testTag', 'RpcClient: onFailed'); 102 } 103 }; 104 } 105 ``` 106 107 FA模型使用[connectAbility](../reference/apis-ability-kit/js-apis-ability-featureAbility.md#featureabilityconnectability7)接口连接Ability。 108 109 <!--code_no_check_fa--> 110 ```ts 111 import { featureAbility } from '@kit.AbilityKit'; 112 113 // 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入 114 let connectId = featureAbility.connectAbility(want, connect); 115 ``` 116 117 Stage模型使用common.UIAbilityContext的[connectServiceExtensionAbility](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextconnectserviceextensionability)接口连接Ability。 118 119 <!--code_no_check--> 120 ```ts 121 let context: common.UIAbilityContext = this.getUIContext().getHostContext(); // UIAbilityContext 122 // 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入 123 let connectId = context.connectServiceExtensionAbility(want,connect); 124 ``` 125 126 成功连接服务后,onConnect回调函数中的Proxy对象会被赋值。此时,可以调用Proxy对象的[registerDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#registerdeathrecipient9-1)接口方法注册死亡回调,在Proxy不再使用的时候,调用[unregisterDeathRecipient](../reference/apis-ipc-kit/js-apis-rpc.md#unregisterdeathrecipient9-1)接口方法注销死亡回调。 127 128 ```ts 129 import { rpc } from '@kit.IPCKit'; 130 import { hilog } from '@kit.PerformanceAnalysisKit'; 131 132 let proxy: rpc.IRemoteObject | undefined; 133 134 class MyDeathRecipient implements rpc.DeathRecipient{ 135 onRemoteDied() { 136 hilog.info(0x0000, 'testTag', 'server died'); 137 } 138 } 139 let deathRecipient = new MyDeathRecipient(); 140 if (proxy != undefined) { 141 // 此处的0为注册死亡监听的死亡通知的保留标志,暂无实际意义 142 proxy.registerDeathRecipient(deathRecipient, 0); 143 proxy.unregisterDeathRecipient(deathRecipient, 0); 144 } 145 ``` 146 147## Stub反向感知Proxy死亡状态(匿名Stub的特殊用法) 148 149正向的死亡通知是Proxy感知Stub的状态,要实现反向的死亡通知(即Stub感知Proxy的状态),可以利用反向死亡通知。例如,进程A(原Stub所在进程)和进程B(原Proxy所在进程),进程B获取到进程A的原Proxy对象后,在B进程新建一个匿名Stub对象(未向SAMgr注册),称为回调Stub,通过[sendMessageRequest](../reference/apis-ipc-kit/js-apis-rpc.md#sendmessagerequest9-2)接口将回调Stub传给进程A的原Stub,进程A就可以获取到进程B的回调Proxy。只要向回调Proxy注册了死亡通知,当进程B(回调Stub)死亡或者RPC通信依赖的软总线连接断开时,回调Proxy会感知并通知进程A(原Stub),从而实现反向死亡通知。 150 151> **注意:** 152> - 反向死亡通知仅限设备内跨进程通信使用,不可用于跨设备。 153> - 当匿名Stub对象没有被任何一个Proxy引用时,对象会被自动释放。 154