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