多端协同主要应用场景介绍 - KaihongOS技术社区 - 电子技术论坛 - 广受欢迎的专业电子论坛
分享 收藏 返回
好名字 关注 私信
[文章]

多端协同主要应用场景介绍

多端协同

功能描述

多端协同主要包括如下场景:

  • 通过跨设备启动UIAbility和ServiceExtensionAbility组件实现多端协同(无返回数据)
  • 通过跨设备启动UIAbility组件实现多端协同(获取返回数据)
  • 通过跨设备连接ServiceExtensionAbility组件实现多端协同
  • 通过跨设备Call调用实现多端协同

多端协同流程

多端协同流程如下图所示。
图1 多端协同流程图  
约束限制


  • 由于“多端协同任务管理”能力尚未具备,开发者当前只能通过开发系统应用获取设备列表,不支持三方应用接入。
  • 多端协同需遵循分布式跨设备组件启动规则。
  • 为了获得最佳体验,使用want传输的数据建议在100KB以下。

通过跨设备启动UIAbility和ServiceExtensionAbility组件实现多端协同(无返回数据)

在设备A上通过发起端应用提供的启动按钮,启动设备B上指定的UIAbility与ServiceExtensionAbility。
接口说明

表1 跨设备启动API接口功能介绍
接口名描述
startAbility(want: Want, callback: AsyncCallback): void;启动UIAbility和ServiceExtensionAbility(callback形式)。
stopServiceExtensionAbility(want: Want, callback: AsyncCallback): void;退出启动的ServiceExtensionAbility(callback形式)。
stopServiceExtensionAbility(want: Want): Promise;退出启动的ServiceExtensionAbility(Promise形式)。
开发步骤


  • 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限,配置方式请参见声明权限。
  • 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见向用户申请授权。
  • 获取目标设备的设备ID。
    import deviceManager from '@ohos.distributedDeviceManager';import hilog from '@ohos.hilog';const TAG: string = '[Page_CollaborateAbility]';const DOMAIN_NUMBER: number = 0xFF00;let dmClass: deviceManager.DeviceManager;function initDmClass(): void {  // 其中createDeviceManager接口为系统API  try {    dmClass = deviceManager.createDeviceManager('com.samples.stagemodelabilitydevelop');    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass) ?? '');  } catch (err) {    hilog.error(DOMAIN_NUMBER, TAG, 'createDeviceManager err: ' + JSON.stringify(err));  };}function getRemoteDeviceId(): string | undefined {  if (typeof dmClass === 'object' && dmClass !== null) {    let list = dmClass.getAvailableDeviceListSync();    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));    if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {      hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');      return;    }    if (list.length === 0) {      hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);      return;    }    return list[0].networkId;  } else {    hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');    return;  }}

  • 设置目标组件参数,调用startAbility()接口,启动UIAbility或ServiceExtensionAbility。
    import { BusinessError } from '@ohos.base';import hilog from '@ohos.hilog';import Want from '@ohos.app.ability.Want';import deviceManager from '@ohos.distributedDeviceManager';import common from '@ohos.app.ability.common';const TAG: string = '[Page_CollaborateAbility]';const DOMAIN_NUMBER: number = 0xFF00;let dmClass: deviceManager.DeviceManager;function getRemoteDeviceId(): string | undefined {  if (typeof dmClass === 'object' && dmClass !== null) {    let list = dmClass.getAvailableDeviceListSync();    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));    if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {      hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');      return;    }    if (list.length === 0) {      hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);      return;    }    return list[0].networkId;  } else {    hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');    return;  }};@Entry@Componentstruct Page_CollaborateAbility {  private context = getContext(this) as common.UIAbilityContext;  build() {    // ...    Button('startAbility')      .onClick(() => {        let want: Want = {          deviceId: getRemoteDeviceId(),          bundleName: 'com.samples.stagemodelabilityinteraction',          abilityName: 'CollaborateAbility',      moduleName: 'entry' // moduleName非必选        }           // context为发起端UIAbility的AbilityContext        this.context.startAbility(want).then(() => {                    // ...        }).catch((err: BusinessError) => {                    // ...          hilog.error(DOMAIN_NUMBER, TAG, `startAbility err: ` + JSON.stringify(err));        });      }      )  }}

  • 当设备A发起端应用不需要设备B上的ServiceExtensionAbility时,可调用stopServiceExtensionAbility接口退出。(该接口不支持UIAbility的退出,UIAbility由用户手动通过任务管理退出)
    import Want from '@ohos.app.ability.Want';import hilog from '@ohos.hilog';import { BusinessError } from '@ohos.base';import deviceManager from '@ohos.distributedDeviceManager';import common from '@ohos.app.ability.common';const TAG: string = '[Page_CollaborateAbility]';const DOMAIN_NUMBER: number = 0xFF00;let dmClass: deviceManager.DeviceManager;function getRemoteDeviceId(): string | undefined {  if (typeof dmClass === 'object' && dmClass !== null) {    let list = dmClass.getAvailableDeviceListSync();    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));    if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {      hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');      return;    }    if (list.length === 0) {      hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);      return;    }    return list[0].networkId;  } else {    hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');    return;  }};@Entry@Componentstruct Page_CollaborateAbility {  private context = getContext(this) as common.UIAbilityContext;  build() {    // ...    Button('stopServiceExtensionAbility')      .onClick(() => {        let want: Want = {          deviceId: getRemoteDeviceId(),          bundleName: 'com.example.myapplication',          abilityName: 'FuncAbility',          moduleName: 'module1', // moduleName非必选        }        // 退出由startAbility接口启动的ServiceExtensionAbility        this.context.stopServiceExtensionAbility(want).then(() => {          console.info("stop service extension ability success")        }).catch((err: BusinessError) => {          console.info("stop service extension ability err is " + JSON.stringify(err))        })      })  }}

通过跨设备启动UIAbility组件实现多端协同(获取返回数据)

在设备A上通过应用提供的启动按钮,启动设备B上指定的UIAbility,当设备B上的UIAbility退出后,会将返回值发回设备A上的发起端应用。
接口说明

表2 跨设备启动,返回结果数据API接口功能描述
接口名描述
startAbilityForResult(want: Want, callback: AsyncCallback): void;启动UIAbility并在该Ability退出的时候返回执行结果(callback形式)。
terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback): void;停止UIAbility,配合startAbilityForResult使用,返回给接口调用方AbilityResult信息(callback形式)。
terminateSelfWithResult(parameter: AbilityResult): Promise;停止UIAbility,配合startAbilityForResult使用,返回给接口调用方AbilityResult信息(promise形式)。
开发步骤


  • 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限,配置方式请参见声明权限。
  • 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见向用户申请授权。
  • 在发起端设置目标组件参数,调用startAbilityForResult()接口启动目标端UIAbility,异步回调中的data用于接收目标端UIAbility停止自身后返回给调用方UIAbility的信息。getRemoteDeviceId方法参照通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据。
    import common from '@ohos.app.ability.common';import hilog from '@ohos.hilog';import { BusinessError } from '@ohos.base';import Want from '@ohos.app.ability.Want';import deviceManager from '@ohos.distributedDeviceManager';const DOMAIN_NUMBER: number = 0xFF00;const TAG: string = '[Page_CollaborateAbility]';let dmClass: deviceManager.DeviceManager;function getRemoteDeviceId(): string | undefined {  if (typeof dmClass === 'object' && dmClass !== null) {    let list = dmClass.getAvailableDeviceListSync();    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));    if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {      hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');      return;    }    if (list.length === 0) {      hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);      return;    }    return list[0].networkId;  } else {    hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');    return;  }};@Entry@Componentstruct Page_CollaborateAbility {  private context = getContext(this) as common.UIAbilityContext;  build() {    // ...    Button('多端协同有返回数据')      .onClick(()=>{        let want: Want = {          deviceId: getRemoteDeviceId(),          bundleName: 'com.samples.stagemodelabilityinteraction',          abilityName: 'CollaborateAbility',          moduleName: 'entry' // moduleName非必选        };        // context为发起端UIAbility的AbilityContext        this.context.startAbilityForResult(want).then((data) => {          // ...        }).catch((error: BusinessError) => {          hilog.error(DOMAIN_NUMBER, TAG, `startAbilityForResult err: ` + JSON.stringify(error));        })      }      )  }}

  • 在目标端UIAbility任务完成后,调用terminateSelfWithResult()方法,将数据返回给发起端的UIAbility。
    import common from '@ohos.app.ability.common';import hilog from '@ohos.hilog';import { BusinessError } from '@ohos.base';const DOMAIN_NUMBER: number = 0xFF00;const TAG: string = '[Page_CollaborateAbility]';@Entry@Componentstruct PageName {     private context = getContext(this) as common.UIAbilityContext;     build() {     // ...     Button('关闭多设备协同界面并返回数据')       .onClick(()=>{       const RESULT_CODE: number = 1001;       // context为目标端UIAbility的AbilityContext       this.context.terminateSelfWithResult(         {           resultCode: RESULT_CODE,           want: {             bundleName: 'ohos.samples.stagemodelabilitydevelop',             abilityName: 'CollaborateAbility',             moduleName: 'entry',             parameters: {               info: '来自Page_CollaborateAbility页面'             }           }         },         (err: BusinessError) => {           hilog.info(DOMAIN_NUMBER, TAG, `terminateSelfWithResult err: ` + JSON.stringify(err));         });     })   }}

  • 发起端UIAbility接收到目标端UIAbility返回的信息,对其进行处理。
    import common from '@ohos.app.ability.common';import deviceManager from '@ohos.distributedDeviceManager';import hilog from '@ohos.hilog';import Want from '@ohos.app.ability.Want';import { BusinessError } from '@ohos.base';const TAG: string = '[Page_CollaborateAbility]';const DOMAIN_NUMBER: number = 0xFF00;let dmClass: deviceManager.DeviceManager;function getRemoteDeviceId(): string | undefined {  if (typeof dmClass === 'object' && dmClass !== null) {    let list = dmClass.getAvailableDeviceListSync();    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));    if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {      hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');      return;    }    if (list.length === 0) {      hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);      return;    }    return list[0].networkId;  } else {    hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');    return;  }};@Entry@Componentstruct PageName {  private context = getContext(this) as common.UIAbilityContext;  build() {    // ...    Button('多端协同有返回数据')      .onClick(() => {        let want: Want = {          deviceId: getRemoteDeviceId(),          bundleName: 'com.samples.stagemodelabilityinteraction',          abilityName: 'CollaborateAbility',          moduleName: 'entry' // moduleName非必选        };        const RESULT_CODE: number = 1001;        // ...        // context为调用方UIAbility的UIAbilityContext        this.context.startAbilityForResult(want).then((data) => {          if (data?.resultCode === RESULT_CODE) {            // 解析目标端UIAbility返回的信息            let info = data.want?.parameters?.info;            // ...          }        }).catch((error: BusinessError) => {          // ...        })      }      )  }}

通过跨设备连接ServiceExtensionAbility组件实现多端协同

系统应用可以通过connectServiceExtensionAbility()跨设备连接一个服务,实现跨设备远程调用。比如:分布式游戏场景,平板作为遥控器,智慧屏作为显示器。
接口说明

表3 跨设备连接API接口功能介绍
[tr]接口名描述[/tr]
connectServiceExtensionAbility(want: Want, options: ConnectOptions): number;连接ServiceExtensionAbility。
disconnectServiceExtensionAbility(connection: number, callback:AsyncCallback): void;断开连接(callback形式)。
disconnectServiceExtensionAbility(connection: number): Promise;断开连接(promise形式)。
开发步骤


  • 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限,配置方式请参见声明权限。
  • 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见向用户申请授权。
  • 如果已有后台服务,请直接进入下一步;如果没有,则实现一个后台服务(仅对系统应用开放)。
  • 连接一个后台服务。


    • 实现IAbilityConnection接口。IAbilityConnection提供了以下方法供开发者实现:onConnect()是用来处理连接Service成功的回调,onDisconnect()是用来处理Service异常终止的回调,onFailed()是用来处理连接Service失败的回调。
    • 设置目标组件参数,包括目标设备ID、Bundle名称、Ability名称。
    • 调用connectServiceExtensionAbility发起连接。
    • 连接成功,收到目标设备返回的服务句柄。
    • 进行跨设备调用,获得目标端服务返回的结果。
      import common from '@ohos.app.ability.common';import deviceManager from '@ohos.distributedDeviceManager';import hilog from '@ohos.hilog';import rpc from '@ohos.rpc';import Want from '@ohos.app.ability.Want';import { BusinessError } from '@ohos.base';const TAG: string = '[Page_CollaborateAbility]';const DOMAIN_NUMBER: number = 0xFF00;const REQUEST_CODE = 1;let dmClass: deviceManager.DeviceManager;let connectionId: number;let options: common.ConnectOptions = {  onConnect(elementName, remote) {    hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');    if (remote === null) {      hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`);      return;    }    let option = new rpc.MessageOption();    let data = new rpc.MessageSequence();    let reply = new rpc.MessageSequence();    data.writeInt(99); // 开发者可发送data到目标端应用进行相应操作    // @param code 表示客户端发送的服务请求代码。    // @param data 表示客户端发送的{@link MessageSequence}对象。    // @param reply 表示远程服务发送的响应消息对象。    // @param options 指示操作是同步的还是异步的。    //    // @return 如果操作成功返回{@code true}; 否则返回 {@code false}。    remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret: rpc.RequestResult) => {      let errCode = reply.readInt(); // 在成功连接的情况下,会收到来自目标端返回的信息(100)      let msg: number = 0;      if (errCode === 0) {        msg = reply.readInt();      }  // 成功连接后台服务      hilog.info(DOMAIN_NUMBER, TAG, `sendRequest msg:${msg}`);    }).catch((error: BusinessError) => {      hilog.info(DOMAIN_NUMBER, TAG, `sendRequest failed, ${JSON.stringify(error)}`);    });  },  onDisconnect(elementName) {    hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');  },  onFailed(code) {    hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback');  }};function getRemoteDeviceId(): string | undefined {  if (typeof dmClass === 'object' && dmClass !== null) {    let list = dmClass.getAvailableDeviceListSync();    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));    if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {      hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');      return;    }    if (list.length === 0) {      hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);      return;    }    return list[0].networkId;  } else {    hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');    return;  }}@Entry@Componentstruct PageName {  private context = getContext(this) as common.UIAbilityContext;  build() {    // ...    Button('connectServiceExtensionAbility')      .onClick(()=>{        let want: Want = {          'deviceId': getRemoteDeviceId(),          'bundleName': 'com.samples.stagemodelabilityinteraction',          'abilityName': 'ServiceExtAbility'        };        // 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入        connectionId = this.context.connectServiceExtensionAbility(want, options);      })  }}getRemoteDeviceId方法参照通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据。

  • 断开连接。调用disconnectServiceExtensionAbility()断开与后台服务的连接。
    import common from '@ohos.app.ability.common';import { BusinessError } from '@ohos.base';import hilog from '@ohos.hilog';import Want from '@ohos.app.ability.Want';import rpc from '@ohos.rpc';import IdlServiceExtProxy from '../IdlServiceExt/idl_service_ext_proxy';let connectionId: number;const TAG: string = '[Page_ServiceExtensionAbility]';const DOMAIN_NUMBER: number = 0xFF00;let want: Want = {  deviceId: '',  bundleName: 'com.samples.stagemodelabilitydevelop',  abilityName: 'ServiceExtAbility'};let options: common.ConnectOptions = {  onConnect(elementName, remote: rpc.IRemoteObject): void {    hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');    if (remote === null) {      hilog.info(DOMAIN_NUMBER, TAG, 'onConnect remote is null');      return;    }    let serviceExtProxy: IdlServiceExtProxy = new IdlServiceExtProxy(remote);    // 通过接口调用的方式进行通信,屏蔽了RPC通信的细节,简洁明了    serviceExtProxy.processData(1, (errorCode: number, retVal: number) => {      hilog.info(DOMAIN_NUMBER, TAG, `processData, errorCode: ${errorCode}, retVal: ${retVal}`);    });    serviceExtProxy.insertDataToMap('theKey', 1, (errorCode: number) => {      hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, errorCode: ${errorCode}`);    })  },  onDisconnect(elementName): void {    hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');  },  onFailed(code: number): void {    hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback', JSON.stringify(code));  }};@Entry@Componentstruct PageName {  private context = getContext(this) as common.UIAbilityContext;  build() {    // ...    Button('disconnectServiceExtensionAbility')      .onClick(() => {        this.context.disconnectServiceExtensionAbility(connectionId).then(() => {          connectionId = this.context.connectServiceExtensionAbility(want, options);          hilog.info(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility success');          // 成功断连后台服务        }).catch((error: BusinessError) => {          hilog.error(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility failed');        })      })  }}

通过跨设备Call调用实现多端协同

跨设备Call调用的基本原理与设备内Call调用相同,请参见通过Call调用实现UIAbility交互(仅对系统应用开放)。
下面介绍跨设备Call调用实现多端协同的方法。
接口说明

表4 Call API接口功能介绍
接口名描述
startAbilityByCall(want: Want): Promise;启动指定UIAbility至前台或后台,同时获取其Caller通信接口,调用方可使用Caller与被启动的Ability进行通信。
on(method: string, callback: CalleeCallBack): void通用组件Callee注册method对应的callback方法。
off(method: string): void通用组件Callee解注册method的callback方法。
call(method: string, data: rpc.Parcelable): Promise向通用组件Callee发送约定序列化数据。
callWithResult(method: string, data: rpc.Parcelable): Promise向通用组件Callee发送约定序列化数据, 并将Callee返回的约定序列化数据带回。
release(): void释放通用组件的Caller通信接口。
on(type: “release”, callback: OnReleaseCallback): void注册通用组件通信断开监听通知。
开发步骤


  • 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限,配置方式请参见声明权限。
  • 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见向用户申请授权。
  • 创建被调用端UIAbility。被调用端UIAbility需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。

    • 配置UIAbility的启动模式。配置module.json5,将CalleeAbility配置为单实例"singleton"。
      [tr]Json字段字段说明[/tr]
      “launchType”Ability的启动模式,设置为"singleton"类型。
      UIAbility配置标签示例如下:
      "abilities":[{    "name": ".CalleeAbility",    "srcEntry": "./ets/CalleeAbility/CalleeAbility.ts",    "launchType": "singleton",    "description": "$string:CalleeAbility_desc",    "icon": "$media:icon",    "label": "$string:CalleeAbility_label",    "exported": true}]

    • 导入UIAbility模块。
      import UIAbility from '@ohos.app.ability.UIAbility';

    • 定义约定的序列化数据。调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。
      import rpc from '@ohos.rpc'class MyParcelable {  num: number = 0;  str: string = '';  constructor(num: number, string: string) {    this.num = num;    this.str = string;  }  mySequenceable(num: number, string: string): void {    this.num = num;    this.str = string;  }  marshalling(messageSequence: rpc.MessageSequence): boolean {    messageSequence.writeInt(this.num);    messageSequence.writeString(this.str);    return true;  };  unmarshalling(messageSequence: rpc.MessageSequence): boolean {    this.num = messageSequence.readInt();    this.str = messageSequence.readString();    return true;  };};

    • 实现Callee.on监听及Callee.off解除监听。如下示例在Ability的onCreate注册MSG_SEND_METHOD监听,在onDestroy取消监听,收到序列化数据后作相应处理并返回。应用开发者根据实际业务需要做相应处理。
      import type AbilityConstant from '@ohos.app.ability.AbilityConstant';import UIAbility from '@ohos.app.ability.UIAbility';import type Want from '@ohos.app.ability.Want';import hilog from '@ohos.hilog';import type rpc from '@ohos.rpc';import type { Caller } from '@ohos.app.ability.UIAbility';const TAG: string = '[CalleeAbility]';const MSG_SEND_METHOD: string = 'CallSendMsg';const DOMAIN_NUMBER: number = 0xFF00;class MyParcelable {  num: number = 0;  str: string = '';  constructor(num: number, string: string) {    this.num = num;    this.str = string;  };  mySequenceable(num: number, string: string): void {    this.num = num;    this.str = string;  };  marshalling(messageSequence: rpc.MessageSequence): boolean {    messageSequence.writeInt(this.num);    messageSequence.writeString(this.str);    return true;  };  unmarshalling(messageSequence: rpc.MessageSequence): boolean {    this.num = messageSequence.readInt();    this.str = messageSequence.readString();    return true;  };};function sendMsgCallback(data: rpc.MessageSequence): rpc.Parcelable {  hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'CalleeSortFunc called');  // 获取Caller发送的序列化数据  let receivedData: MyParcelable = new MyParcelable(0, '');  data.readParcelable(receivedData);  hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `receiveData[${receivedData.num}, ${receivedData.str}]`);  let num: number = receivedData.num;  // 作相应处理  // 返回序列化数据result给Caller  return new MyParcelable(num + 1, `send ${receivedData.str} succeed`) as rpc.Parcelable;}export default class CalleeAbility extends UIAbility {  caller: Caller | undefined;  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {    try {      this.callee.on(MSG_SEND_METHOD, sendMsgCallback);    } catch (error) {      hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`)    };  }  onDestroy(): void {    try {      this.callee.off(MSG_SEND_METHOD);      hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Callee OnDestroy');      this.releaseCall();    } catch (error) {      hilog.error(DOMAIN_NUMBER, TAG, '%{public}s', `Failed to register. Error is ${error}`)    };  }}


  • 获取Caller接口,访问被调用端UIAbility。

    • 导入UIAbility模块。
      import UIAbility from '@ohos.app.ability.UIAbility';

    • 获取Caller通信接口。Ability的context属性实现了startAbilityByCall方法,用于获取指定通用组件的Caller通信接口。如下示例通过this.context获取Ability实例的context属性,使用startAbilityByCall拉起Callee被调用端并获取Caller通信接口,注册Caller的onRelease和onRemoteStateChange监听。应用开发者根据实际业务需要做相应处理。
      import { Caller } from '@ohos.app.ability.UIAbility';import { BusinessError } from '@ohos.base';import common from '@ohos.app.ability.common';import deviceManager from '@ohos.distributedDeviceManager';import hilog from '@ohos.hilog';const TAG: string = '[Page_CollaborateAbility]';const DOMAIN_NUMBER: number = 0xFF00;let caller: Caller | undefined;let dmClass: deviceManager.DeviceManager;function getRemoteDeviceId(): string | undefined {  if (typeof dmClass === 'object' && dmClass !== null) {    let list = dmClass.getAvailableDeviceListSync();    hilog.info(DOMAIN_NUMBER, TAG, JSON.stringify(dmClass), JSON.stringify(list));    if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {      hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: list is null');      return;    }    if (list.length === 0) {      hilog.info(DOMAIN_NUMBER, TAG, `getRemoteDeviceId err: list is empty`);      return;    }    return list[0].networkId;  } else {    hilog.info(DOMAIN_NUMBER, TAG, 'getRemoteDeviceId err: dmClass is null');    return;  }}@Entry@Componentstruct Page_CollaborateAbility {  private context = getContext(this) as common.UIAbilityContext;  build() {    // ...    Button('多端协同有返回数据')      .onClick(() => {        this.context.startAbilityByCall({          deviceId: getRemoteDeviceId(),          bundleName: 'com.samples.stagemodelabilityinteraction',          abilityName: 'CalleeAbility'        }).then((data) => {          if (data !== null) {            caller = data;            hilog.info(DOMAIN_NUMBER, TAG, 'get remote caller success');            // 注册caller的release监听            caller.onRelease((msg) => {              hilog.info(DOMAIN_NUMBER, TAG, `remote caller onRelease is called ${msg}`);            })            hilog.info(DOMAIN_NUMBER, TAG, 'remote caller register OnRelease succeed');            // 注册caller的协同场景下跨设备组件状态变化监听通知            try {              caller.onRemoteStateChange((str) => {                hilog.info(DOMAIN_NUMBER, TAG, 'Remote state changed ' + str);              });            } catch (error) {              hilog.info(DOMAIN_NUMBER, TAG, `Caller.onRemoteStateChange catch error, error.code: ${JSON.stringify(error.code)}, error.message: ${JSON.stringify(error.message)}`);            };          }        }).catch((error: BusinessError) => {          hilog.error(DOMAIN_NUMBER, TAG, `get remote caller failed with ${error}`);        });      }      )  }}getRemoteDeviceId方法参照通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据。


  • 向被调用端UIAbility发送约定序列化数据。

    • 向被调用端发送Parcelable数据有两种方式,一种是不带返回值,一种是获取被调用端返回的数据,method以及序列化数据需要与被调用端协商一致。如下示例调用Call接口,向Callee被调用端发送数据。
      import UIAbility, { Caller } from '@ohos.app.ability.UIAbility';import type rpc from '@ohos.rpc';const MSG_SEND_METHOD: string = 'CallSendMsg';class MyParcelable {  num: number = 0;  str: string = '';  constructor(num: number, string: string) {    this.num = num;    this.str = string;  };  mySequenceable(num: number, string: string): void {    this.num = num;    this.str = string;  };  marshalling(messageSequence: rpc.MessageSequence): boolean {    messageSequence.writeInt(this.num);    messageSequence.writeString(this.str);    return true;  };  unmarshalling(messageSequence: rpc.MessageSequence): boolean {    this.num = messageSequence.readInt();    this.str = messageSequence.readString();    return true;  };};export default class EntryAbility extends UIAbility {  // ...  caller: Caller | undefined;  async onButtonCall(): Promise {    try {      let msg: MyParcelable = new MyParcelable(1, 'origin_Msg');      if (this.caller) {        await this.caller.call(MSG_SEND_METHOD, msg);      }    } catch (error) {      hilog.info(DOMAIN_NUMBER, TAG, `caller call failed with ${error}`);    };  }  // ...}

    • 如下示例调用CallWithResult接口,向Callee被调用端发送待处理的数据originMsg,并将’CallSendMsg’方法处理完毕的数据赋值给backMsg。
      import UIAbility, { Caller } from '@ohos.app.ability.UIAbility';import rpc from '@ohos.rpc';const MSG_SEND_METHOD: string = 'CallSendMsg';let originMsg: string = '';let backMsg: string = '';class MyParcelable {  num: number = 0;  str: string = '';  constructor(num: number, string: string) {    this.num = num;    this.str = string;  };  mySequenceable(num: number, string: string): void {    this.num = num;    this.str = string;  };  marshalling(messageSequence: rpc.MessageSequence): boolean {    messageSequence.writeInt(this.num);    messageSequence.writeString(this.str);    return true;  };  unmarshalling(messageSequence: rpc.MessageSequence): boolean {    this.num = messageSequence.readInt();    this.str = messageSequence.readString();    return true;  };};export default class EntryAbility extends UIAbility {  // ...  caller: Caller | undefined;  async onButtonCallWithResult(originMsg: string, backMsg: string): Promise {    try {      let msg: MyParcelable = new MyParcelable(1, originMsg);      if (this.caller) {        const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg);        hilog.info(DOMAIN_NUMBER, TAG, 'caller callWithResult succeed');        let result: MyParcelable = new MyParcelable(0, '');        data.readParcelable(result);        backMsg = result.str;        hilog.info(DOMAIN_NUMBER, TAG, `caller result is [${result.num}, ${result.str}]`);      }    } catch (error) {      hilog.info(DOMAIN_NUMBER, TAG, `caller callWithResult failed with ${error}`);    };  }  // ...}


  • 释放Caller通信接口。Caller不再使用后,应用开发者可以通过release接口释放Caller。
    import UIAbility, { Caller } from '@ohos.app.ability.UIAbility';export default class EntryAbility extends UIAbility {  caller: Caller | undefined;  releaseCall(): void {    try {      if (this.caller) {        this.caller.release();        this.caller = undefined;      }      hilog.info(DOMAIN_NUMBER, TAG, 'caller release succeed');    } catch (error) {      hilog.info(DOMAIN_NUMBER, TAG, `caller release failed with ${error}`);    };  }}

更多回帖

×
发帖