文档管理中心
开发与测试开放能力API应用框架IPC Kit(进程间通信服务)远端状态订阅开发实例

远端状态订阅开发实例

IPC/RPC提供了订阅远端Stub对象状态的机制。当远端Stub对象死亡时,可以自动触发本端Proxy注册的死亡通知。这种死亡通知订阅需要调用指定接口registerDeathRecipient完成。不再需要订阅时,也需要调用指定接口unregisterDeathRecipient取消订阅。

使用这种订阅机制的用户需要继承死亡通知类DeathRecipient,并实现onRemoteDied方法清理资源。该方法会在远端Stub对象所在进程退出或当前RPC通信依赖的软总线连接断开时被回调。

注意
  • 首先,Proxy订阅Stub死亡通知,若在订阅期间Stub状态正常,则在不再需要时取消订阅。
  • 其次,若在订阅期间,Stub所在进程退出或当前RPC通信依赖的软总线连接断开,则会自动触发执行业务已向Proxy注册的自定义的onRemoteDied方法。

使用场景

IPC/RPC的订阅机制适用于以下场景:

  1. IPC通信,Proxy对象需要感知远端Stub对象所在进程的状态。
  2. RPC通信,Proxy对象需要感知远端Stub对象所在进程的状态,或者RPC通信依赖的软总线连接断开。

当Proxy感知到Stub端死亡后,应该清理本地Proxy对象以及相关资源。

注意

RPC不支持匿名Stub对象(没有向SAMgr注册)的死亡通知,IPC支持匿名Stub对象的死亡通知。

ArkTS侧接口

说明
  • 此文档中的示例代码描述的是系统应用跨进程通信。

  • 使用场景约束:客户端是第三方/系统应用,服务端是系统应用/服务

展开
接口名 返回值类型 功能描述
registerDeathRecipient void 注册用于接收远程对象死亡通知的回调,该方法应该在proxy侧调用。
unregisterDeathRecipient void 注销用于接收远程对象死亡通知的回调。
onRemoteDied void Proxy侧注册死亡通知成功后,当远端Stub对象所在进程死亡时,将自动回调本方法。

参考代码

在IPC(同设备的跨进程通信)场景中,示例代码如下:

导入相关依赖,并定义所需的变量;

收起
自动换行
深色代码主题
复制
  1. import { BusinessError } from '@kit.BasicServicesKit';
  2. import { Want, common } from '@kit.AbilityKit';
  3. import { rpc } from '@kit.IPCKit';
  4. import { hilog } from '@kit.PerformanceAnalysisKit';
  5. import { PromptAction } from '@kit.ArkUI';
  6. import { JSON } from '@kit.ArkTS';
  7. let proxy: rpc.IRemoteObject | undefined;
  8. let connectId: number | undefined;
  9. // 死亡通知
  10. class MyDeathRecipient implements rpc.DeathRecipient {
  11. onRemoteDied() {
  12. hilog.info(0x0000, 'testTag', 'server is dead');
  13. }
  14. }
  15. let deathRecipient = new MyDeathRecipient();

连接服务,获取代理对象,然后注册死亡监听。在断开连接时,移除死亡监听。

收起
自动换行
深色代码主题
复制
  1. // 连接服务
  2. function connectAbility(context:common.UIAbilityContext, promptAction: PromptAction) {
  3. hilog.info(0x00000, 'testTag', 'begin to connect Ability');
  4. let want: Want = {
  5. bundleName: 'com.example.ipc_stub',
  6. abilityName: 'ServiceAbility',
  7. };
  8. let connect: common.ConnectOptions = {
  9. onConnect: (elementName, remoteProxy) => {
  10. hilog.info(0x00000, 'testTag', 'onConnect. elementName is :' + JSON.stringify(elementName));
  11. proxy = remoteProxy;
  12. // 客户端注册死亡监听
  13. try {
  14. proxy.registerDeathRecipient(deathRecipient, 0);
  15. hilog.info(0x00000, 'testTag', 'registerDeathRecipient success');
  16. } catch (err) {
  17. let code = (err as BusinessError).code;
  18. let message = (err as BusinessError).message;
  19. hilog.error(0x0000, 'testTag', 'register failed, code is ' + code + ', message is ' + message);
  20. }
  21. // ...
  22. },
  23. onDisconnect: (elementName) => {
  24. hilog.info(0x0000, 'testTag', 'onDisconnect. elementName is ' + JSON.stringify(elementName));
  25. // 客户端移除死亡监听
  26. try {
  27. proxy?.unregisterDeathRecipient(deathRecipient, 0);
  28. hilog.info(0x00000, 'testTag', 'unregisterDeathRecipient success');
  29. } catch (err) {
  30. let code = (err as BusinessError).code;
  31. let message = (err as BusinessError).message;
  32. hilog.error(0x0000, 'testTag', 'unregister failed, code is ' + code + ', message is ' + message);
  33. }
  34. proxy = undefined;
  35. // ...
  36. },
  37. onFailed: (code: number) => {
  38. hilog.info(0x0000, 'testTag', 'onFailed. code is ' + code);
  39. // ...
  40. },
  41. }
  42. try {
  43. connectId = context.connectServiceExtensionAbility(want, connect);
  44. hilog.info(0x00000, 'testTag', 'begin to connect Ability end');
  45. } catch (err) {
  46. let code = (err as BusinessError).code;
  47. let message = (err as BusinessError).message;
  48. hilog.error(0x0000, 'testTag', 'connectAbility failed, code is ' + code + ', message is ' + message);
  49. }
  50. }
  51. // 断开连接
  52. function disconnectAbility(context: common.UIAbilityContext) {
  53. hilog.info(0x00000, 'testTag', 'begin to disconnect Ability. connectId is ' + connectId);
  54. if (connectId != undefined) {
  55. try {
  56. context.disconnectServiceExtensionAbility(connectId);
  57. } catch (err) {
  58. let code = (err as BusinessError).code;
  59. let message = (err as BusinessError).message;
  60. hilog.error(0x0000, 'testTag', 'disconnect failed, code is ' + code + ', message is ' + message);
  61. }
  62. }
  63. }

在RPC(跨设备的跨进程通信)场景中,示例代码如下:

导入相关依赖,并定义所需的变量;

收起
自动换行
深色代码主题
复制
  1. import { BusinessError } from '@kit.BasicServicesKit';
  2. import { rpc } from '@kit.IPCKit';
  3. import { hilog } from '@kit.PerformanceAnalysisKit';
  4. import { distributedDeviceManager } from '@kit.DistributedServiceKit';
  5. import { abilityAccessCtrl, PermissionRequestResult, common, Want} from '@kit.AbilityKit';
  6. import { JSON } from '@kit.ArkTS';
  7. import { PromptAction } from '@kit.ArkUI';
  8. let proxy: rpc.IRemoteObject | undefined;
  9. let connectId: number | undefined;
  10. let dmInstance: distributedDeviceManager.DeviceManager;
  11. let deviceList: Array<distributedDeviceManager.DeviceBasicInfo> | undefined;
  12. let deviceId: string| undefined;
  13. // 死亡通知
  14. class MyDeathRecipient implements rpc.DeathRecipient {
  15. onRemoteDied() {
  16. hilog.info(0x0000, 'testTag', 'server is dead');
  17. }
  18. };
  19. let deathRecipient = new MyDeathRecipient();

获取允许多设备协同的权限,在组网的情况下获取到对端的设备ID(组网场景下对应设备的唯一网络标识符,可以使用distributedDeviceManager获取目标设备的NetworkId)后连接服务,获取代理对象并注册死亡监听。当代理对象与服务端的通信结束后,在断开连接时,移除死亡监听。

收起
自动换行
深色代码主题
复制
  1. // 获取权限
  2. function getPermission(context:common.UIAbilityContext) {
  3. hilog.info(0x00000, 'testTag', 'begin to requestPermissions');
  4. try {
  5. let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  6. atManager.requestPermissionsFromUser(context, ['ohos.permission.DISTRIBUTED_DATASYNC'],
  7. (err: BusinessError, data: PermissionRequestResult) => {
  8. if (err) {
  9. hilog.error(0x0000, 'testTag', 'requestPermissions failed, code is ' + err.code);
  10. hilog.error(0x0000, 'testTag', 'requestPermissions failed, message is ' + err.message);
  11. } else {
  12. hilog.info(0x0000, 'testTag', 'requestPermissions success, result is ' + JSON.stringify(data));
  13. hilog.info(0x0000, 'testTag', 'data permissions is ' + data.permissions);
  14. hilog.info(0x0000, 'testTag', 'data authResults is ' + data.authResults);
  15. hilog.info(0x0000, 'testTag', 'data dialogShownResults is ' + data.dialogShownResults);
  16. }
  17. });
  18. } catch (err) {
  19. let code = (err as BusinessError).code;
  20. let message = (err as BusinessError).message;
  21. hilog.error(0x0000, 'testTag', 'getPermission failed, code is ' + code + ', message is ' + message);
  22. }
  23. }
  24. // 获取对端设备信息
  25. function getDeviceId(promptAction: PromptAction) {
  26. hilog.info(0x00000, 'testTag', 'begin to getDeviceId');
  27. try {
  28. dmInstance = distributedDeviceManager.createDeviceManager('com.example.rpc_client');
  29. hilog.info(0x0000, 'testTag', 'createDeviceManager success');
  30. deviceList = dmInstance.getAvailableDeviceListSync();
  31. hilog.info(0x0000, 'testTag', 'deviceList is ' + JSON.stringify(deviceList));
  32. if (deviceList.length !== 0) {
  33. deviceId = deviceList[0].networkId;
  34. hilog.info(0x0000, 'testTag', 'networkId is ' + deviceId);
  35. // ...
  36. }
  37. } catch (err) {
  38. let code = (err as BusinessError).code;
  39. let message = (err as BusinessError).message;
  40. hilog.error(0x0000, 'testTag', 'getDeviceId failed, code is ' + code + ', message is ' + message);
  41. // ...
  42. }
  43. }
  44. // 连接服务
  45. function connectAbility(context:common.UIAbilityContext, promptAction: PromptAction) {
  46. hilog.info(0x00000, 'testTag', 'begin to connect Ability');
  47. let want: Want = {
  48. bundleName: 'com.example.rpc_stub',
  49. abilityName: 'ServiceAbility',
  50. deviceId: deviceId,
  51. }
  52. let connect: common.ConnectOptions = {
  53. onConnect: (elementName, remoteProxy) => {
  54. hilog.info(0x00000, 'testTag', 'onConnect. elementName is ' + JSON.stringify(elementName));
  55. proxy = remoteProxy;
  56. // 客户端注册死亡监听
  57. try {
  58. proxy.registerDeathRecipient(deathRecipient, 0);
  59. hilog.info(0x00000, 'testTag', 'registerDeathRecipient success');
  60. } catch (err) {
  61. let code = (err as BusinessError).code;
  62. let message = (err as BusinessError).message;
  63. hilog.error(0x0000, 'testTag', 'register failed, code is ' + code + ', message is ' + message);
  64. };
  65. // ...
  66. },
  67. onDisconnect: (elementName) => {
  68. hilog.info(0x0000, 'testTag', 'onDisconnect. elementName is ' + JSON.stringify(elementName));
  69. // 客户端移除死亡监听
  70. try {
  71. proxy?.unregisterDeathRecipient(deathRecipient, 0);
  72. hilog.info(0x00000, 'testTag', 'unregisterDeathRecipient success');
  73. } catch (err) {
  74. let code = (err as BusinessError).code;
  75. let message = (err as BusinessError).message;
  76. hilog.error(0x0000, 'testTag', 'unregister failed, code is ' + code + ', message is ' + message);
  77. }
  78. proxy = undefined;
  79. // ...
  80. },
  81. onFailed: (code: number) => {
  82. hilog.info(0x0000, 'testTag', 'onFailed. code is ' + code);
  83. // ...
  84. },
  85. }
  86. try {
  87. connectId = context.connectServiceExtensionAbility(want, connect);
  88. } catch (err) {
  89. let code = (err as BusinessError).code;
  90. let message = (err as BusinessError).message;
  91. hilog.error(0x0000, 'testTag', 'connectService failed, code is ' + code + ', message is ' + message);
  92. }
  93. }
  94. // 断开连接
  95. function disconnectAbility(context: common.UIAbilityContext) {
  96. hilog.info(0x00000, 'testTag', 'begin to disconnect Ability');
  97. if (connectId != undefined) {
  98. try {
  99. context.disconnectServiceExtensionAbility(connectId);
  100. } catch (err) {
  101. let code = (err as BusinessError).code;
  102. let message = (err as BusinessError).message;
  103. hilog.error(0x0000, 'testTag', 'disconnectService failed, code is ' + code + ', message is ' + message);
  104. }
  105. }
  106. }

Stub反向感知Proxy死亡状态(匿名Stub的特殊用法)

正向的死亡通知是Proxy感知Stub的状态,要实现反向的死亡通知(即Stub感知Proxy的状态),可以利用反向死亡通知。例如,进程A(原Stub所在进程)和进程B(原Proxy所在进程),进程B获取到进程A的原Proxy对象后,在B进程新建一个匿名Stub对象(未向SAMgr注册),称为回调Stub,通过sendMessageRequest接口将回调Stub传给进程A的原Stub,进程A就可以获取到进程B的回调Proxy。只要向回调Proxy注册了死亡通知,当进程B(回调Stub)死亡或者RPC通信依赖的软总线连接断开时,回调Proxy会感知并通知进程A(原Stub),从而实现反向死亡通知。

注意
  • 反向死亡通知仅限设备内跨进程通信使用,不可用于跨设备。
  • 当匿名Stub对象没有被任何一个Proxy引用时,对象会被自动释放。
在 开发与测试 开放能力API 中进行搜索
请输入您想要搜索的关键词