OpenHarmony应用开发-Stage模型开发指导

素年锦时静待君丶
发布于 2023-4-10 17:29
浏览
0收藏

版本:v3.2 Beta5

组件启动规则(Stage模型)

启动组件是指一切启动或连接应用组件的行为:

  • 启动UIAbility、ServiceExtensionAbility、DataShareExtensionAbility,如使用startAbility()、startServiceExtensionAbility()、startAbilityByCall()等相关接口。
  • 连接ServiceExtensionAbility、DataShareExtensionAbility,如使用connectServiceExtensionAbility()、createDataShareHelper()等相关接口。

在OpenHarmony中,为了保证用户具有更好的使用体验,对以下几种易影响用户体验与系统安全的行为做了限制:

  • 后台应用任意弹框,如各种广告弹窗,影响用户使用。
  • 后台应用相互唤醒,不合理的占用系统资源,导致系统功耗增加或系统卡顿。
  • 前台应用任意跳转至其他应用,如随意跳转到其他应用的支付页面,存在安全风险。

鉴于此,OpenHarmony制订了一套组件启动规则,主要包括:

  • 跨应用启动组件,需校验目标组件Visible

     ○  若目标组件visible字段配置为false,则需校验​​ohos.permission.START_INVISIBLE_ABILITY​​权限

     ○  ​​组件visible配置参考​

  • 位于后台的应用,启动组件需校验BACKGROUND权限

     ○  应用前后台判断标准:若应用进程获焦或所属的UIAbility位于前台则判定为前台应用,否则为后台应用

     ○  需校验​​ohos.permission.START_ABILITIES_FROM_BACKGROUND​​权限

     ○  需校验​​ohos.permission.ABILITY_BACKGROUND_COMMUNICATION​​权限

说明:

  1. 组件启动管控自OpenHarmony v3.2 Release版本开始落地。
  2. 与原本的启动规则不同,新的组件启动规则较为严格,开发者需熟知启动规则,避免业务功能异常。

启动组件的具体校验流程见下文。

同设备组件启动规则

设备内启动组件,不同场景下的规则不同,可分为如下两种场景:

  • 启动或连接组件:UIAbility、ServiceExtensionAbility、DataShareExtensionAbility。
  • 通过startAbilityByCall接口启动UIAbility。

OpenHarmony应用开发-Stage模型开发指导-鸿蒙开发者社区

分布式跨设备组件启动规则

跨设备启动组件,不同场景下的规则不同,可分为如下两种场景:

  • 启动或连接组件:UIAbility、ServiceExtensionAbility、DataShareExtensionAbility。
  • 通过startAbilityByCall接口启动UIAbility。

OpenHarmony应用开发-Stage模型开发指导-鸿蒙开发者社区

应用组件跨设备交互(流转)

流转概述

场景介绍

随着全场景多设备的生活方式不断深入,用户拥有的设备越来越多,不同设备都能在适合的场景下提供良好的体验,例如手表可以提供及时的信息查看能力,电视可以带来沉浸的观影体验。但是,每个设备也有使用场景的局限,例如在电视上输入文本相对移动设备来说是非常糟糕的体验。当多个设备通过分布式操作系统能够相互感知、进而整合成一个超级终端时,设备与设备之间就可以取长补短、相互帮助,为用户提供更加自然流畅的分布式体验。

在OpenHarmony中,将跨多设备的分布式操作统称为流转;根据使用场景的不同,流转又分为​​跨端迁移​​​和​​多端协同​​两种具体场景。要实现应用跨设备流转,需使用应用组件的跨设备交互相关能力,这些能力目前仅对系统应用开放。

基本概念
  • 流转
    在OpenHarmony中泛指跨多设备的分布式操作。流转能力打破设备界限,多设备联动,使用户应用程序可分可合、可流转,实现如邮件跨设备编辑、多设备协同健身、多屏游戏等分布式业务。流转为开发者提供更广的使用场景和更新的产品视角,强化产品优势,实现体验升级。流转按照使用场景可分为跨端迁移多端协同
  • 跨端迁移
    在用户使用设备的过程中,当使用情境发生变化时(例如从室内走到户外或者周围有更合适的设备等),之前使用的设备可能已经不适合继续当前的任务,此时,用户可以选择新的设备来继续当前的任务,原设备退出任务,这就是跨端迁移场景。常见的跨端迁移场景实例:在平板上播放的视频,迁移到智慧屏继续播放,从而获得更佳的观看体验;平板上的视频应用退出。在应用开发层面,跨端迁移指在A端运行的UIAbility迁移到B端上,完成迁移后, B端UIAbility继续任务,而A端UIAbility退出。
  • 多端协同
    用户拥有的多个设备,可以作为一个整体,为用户提供比单设备更加高效、沉浸的体验,这就是多端协同场景。常见的多端协同场景实例:平板侧应用A做答题板,智慧屏侧应用B做直播,为用户提供更优的上网课体验。在应用开发层面,多端协同指多端上的不同UIAbility/ServiceExtensionAbility同时运行、或者交替运行实现完整的业务;或者多端上的相同UIAbility/ServiceExtensionAbility同时运行实现完整的业务。
流转架构

OpenHarmony流转提供了一组API库,可让用户应用程序更轻松、快捷地完成流转体验。OpenHarmony流转架构有如下优势:

  • 支持远程服务调用等能力,可轻松设计业务。
  • 支持多个应用同时进行流转。
  • 支持不同形态设备,如平板、智慧屏、手表等。

流转架构如下图所示。

图1 流转架构图

OpenHarmony应用开发-Stage模型开发指导-鸿蒙开发者社区

  • 跨端迁移任务管理:在迁移发起端,接受用户迁移的意图,提供迁移流转入口,迁移结果显示等能力。(该能力尚未构建。)
  • 多端协同任务管理:在协同发起端,接受用户应用程序注册,提供协同入口、状态显示、退出流转等管理能力。(该能力尚未构建。)
  • 分布式组件管理服务:提供远程服务启动、远程服务连接、远程迁移等能力,并通过不同能力组合,支撑用户应用程序完成跨端迁移或多端协同的业务体验。
  • 分布式安全:提供E2E的加密通道,为用户应用程序提供安全的跨端传输机制,保证“正确的人,通过正确的设备,正确地使用数据”。
  • 分布式软总线:使用基于平板、智能穿戴、智慧屏等分布式设备的统一通信基座,为设备之间的互联互通提供统一的分布式通信能力。

跨端迁移(仅对系统应用开放)

功能描述

跨端迁移的主要工作是实现将应用当前任务(包括页面控件状态变量等)迁移到目标设备,能在目标设备上接续。主要功能包括:

  • 支持用户自定义数据存储及恢复。
  • 支持页面路由信息和页面控件状态数据的存储及恢复。
  • 支持应用兼容性检测。
跨端迁移流程

跨端迁移流程如下图所示。

图1 跨端迁移流程图   

OpenHarmony应用开发-Stage模型开发指导-鸿蒙开发者社区

约束限制
  • 由于“跨端迁移任务管理”能力尚未具备,开发者当前只能开发具备跨端迁移能力的应用,但不能发起迁移。
  • 跨端迁移要求在同UIAbility之间进行,也就是需要相同的bundleName、abilityName和签名。
最佳实践

为了获得最佳体验,使用wantParam传输的数据建议在100KB以下。

接口说明

跨端迁移主要接口如下。详细接口介绍请参见​​API参考​​。

表1 跨端迁移接口

接口名

描述

onContinue(wantParam : {[key: string]: any}): OnContinueResult

迁移发起端在该回调中保存迁移所需要的数据,同时返回是否同意迁移:

- AGREE:表示同意。

- REJECT:表示拒绝。

- MISMATCH:表示版本不匹配。

onCreate(want: Want, param: AbilityConstant.LaunchParam): void;

多实例应用迁移接收端在该回调中完成数据恢复,并触发页面恢复。

onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void;

单实例应用迁移接收端在该回调中完成数据恢复,并触发页面恢复。

开发步骤
  1. 在module.json5配置数据同步权限,示例代码如下。

{
  "module": {
    "requestPermissions":[  
      {  
        "name" : "ohos.permission.DISTRIBUTED_DATASYNC",
      }
    ]
  }
}
  1. 在配置文件中配置跨端迁移相关标签字段。
  • 配置应用支持迁移 在module.json5中配置continuable标签:true表示支持迁移,false表示不支持,默认为false。配置为false的UIAbility将被系统识别为无法迁移。

{
  "module": {
    // ...
    "abilities": [
      {
        // ...
        "continuable": true,
      }
    ]
  }
}
  1. 申请数据同步权限,弹框示例代码。

requestPermission() {   
    let context = this.context
    let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']   
    context.requestPermissionsFromUser(permissions).then((data) => {   
        console.info("Succeed to request permission from user with data: "+ JSON.stringify(data))
    }).catch((error) => {       
        console.info("Failed to request permission from user with error: "+ JSON.stringify(error))   
    }) 
}
  1. 在发起端UIAbility中实现​​onContinue()​​​接口。 当应用触发迁移时,​​onContinue()​​接口在发起端被调用,开发者可以在该接口中保存迁移数据,实现应用兼容性检测,决定是否支持此次迁移。
  • 保存迁移数据:开发者可以将要迁移的数据通过键值对的方式保存在wantParam中。
  • 应用兼容性检测:开发者可以通过从wantParam中获取目标应用的版本号与本应用版本号做兼容性校验。
  • 迁移决策:开发者可以通过onContinue接口的返回值决定是否支持此次迁移,返回值信息见​​接口说明​​​。
    示例如下:

import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';

onContinue(wantParam : {[key: string]: any}) {         
    console.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`)         
    let workInput = AppStorage.Get<string>('ContinueWork');         
    // set user input data into want params         
    wantParam["work"] = workInput // set user input data into want params         
    console.info(`onContinue input = ${wantParam["input"]}`);         
    return AbilityConstant.OnContinueResult.AGREE     
}
  1. 在目标端设备UIAbility中实现onCreate()/onNewWant()接口,恢复迁移数据。
  • 多实例场景onCreate实现示例

    ○  目标端设备上,在onCreate中根据launchReason判断该次启动是否为迁移LaunchReason.CONTINUATION。

    ○  开发者可以从want中获取保存的迁移数据。

    ○  完成数据恢复后,开发者需要调用restoreWindowStage来触发页面恢复。

import UIAbility from '@ohos.app.ability.UIAbility'; 
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import distributedObject from '@ohos.data.distributedDataObject';  

export default class EntryAbility extends UIAbility {     
    storage : LocalStorage;     
    onCreate(want, launchParam) {         
        console.info(`EntryAbility onCreate ${AbilityConstant.LaunchReason.CONTINUATION}`)         
        if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {             
            // get user data from want params             
            let workInput = want.parameters.work             
            console.info(`work input ${workInput}`)             
            AppStorage.SetOrCreate<string>('ContinueWork', workInput)             
            this.storage = new LocalStorage();             
            this.context.restoreWindowStage(this.storage);         
        }     
    } 
}

    ○  如果是单实例应用,则采用同样的代码实现onNewWant()接口即可。

多端协同(仅对系统应用开放)

功能描述

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

多端协同流程

多端协同流程如下图所示。

图1 多端协同流程图   

OpenHarmony应用开发-Stage模型开发指导-鸿蒙开发者社区

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

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

接口说明

表1 跨设备启动API接口功能介绍

接口名

描述

startAbility(want: Want, callback: AsyncCallback<void>): void;

启动UIAbility和ServiceExtensionAbility(callback形式)。

开发步骤
  1. 申请​​ohos.permission.DISTRIBUTED_DATASYNC​​​权限,配置方式请参阅​​访问控制授权申请指导​​。
  2. 申请数据同步权限,弹框示例代码。

requestPermission() {   
    let context = this.context
    let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']   
    context.requestPermissionsFromUser(permissions).then((data) => {   
        console.info("Succeed to request permission from user with data: "+ JSON.stringify(data))
    }).catch((error) => {       
        console.info("Failed to request permission from user with error: "+ JSON.stringify(error))   
    }) 
}
  1. 获取目标设备的设备ID。

import deviceManager from '@ohos.distributedHardware.deviceManager';

let dmClass;
function initDmClass() {
    // 其中createDeviceManager接口为系统API
    deviceManager.createDeviceManager('ohos.samples.demo', (err, dm) => {
        if (err) {
            // ...
            return
        }
        dmClass = dm
    })
}
function getRemoteDeviceId() {
    if (typeof dmClass === 'object' && dmClass !== null) {
        let list = dmClass.getTrustedDeviceListSync()
        if (typeof (list) === 'undefined' || typeof (list.length) === 'undefined') {
            console.info('EntryAbility onButtonClick getRemoteDeviceId err: list is null')
            return;
        }
        return list[0].deviceId
    } else {
        console.info('EntryAbility onButtonClick getRemoteDeviceId err: dmClass is null')
    }
}
  1. 设置目标组件参数,调用startAbility()接口,启动UIAbility或ServiceExtensionAbility。

let want = {
    deviceId: getRemoteDeviceId(), 
    bundleName: 'com.example.myapplication',
    abilityName: 'FuncAbility',
    moduleName: 'module1', // moduleName非必选
}
// context为发起端UIAbility的AbilityContext
this.context.startAbility(want).then(() => {
    // ...
}).catch((err) => {
    // ...
})
通过跨设备启动UIAbility组件实现多端协同(获取返回数据)

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

接口说明

表2 跨设备启动,返回结果数据API接口功能描述

接口名

描述

startAbilityForResult(want: Want, callback: AsyncCallback<AbilityResult>): void;

启动UIAbility并在该Ability退出的时候返回执行结果(callback形式)。

terminateSelfWithResult(parameter: AbilityResult, callback: AsyncCallback<void>): void;

停止UIAbility,配合startAbilityForResult使用,返回给接口调用方AbilityResult信息(callback形式)。

terminateSelfWithResult(parameter: AbilityResult): Promise<void>;

停止UIAbility,配合startAbilityForResult使用,返回给接口调用方AbilityResult信息(promise形式)。

开发步骤
  1. 申请​​ohos.permission.DISTRIBUTED_DATASYNC​​​权限,配置方式请参阅​​访问控制授权申请指导​​。
  2. 申请数据同步权限,弹框示例代码。

requestPermission() {   
    let context = this.context
    let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']   
    context.requestPermissionsFromUser(permissions).then((data) => {   
        console.info("Succeed to request permission from user with data: "+ JSON.stringify(data))
    }).catch((error) => {       
        console.info("Failed to request permission from user with error: "+ JSON.stringify(error))   
    }) 
}
  1. 在发起端设置目标组件参数,调用startAbilityForResult()接口启动目标端UIAbility,异步回调中的data用于接收目标端UIAbility停止自身后返回给调用方UIAbility的信息。getRemoteDeviceId方法参照​​通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据​​。

let want = {
    deviceId: getRemoteDeviceId(), 
    bundleName: 'com.example.myapplication',
    abilityName: 'FuncAbility',
    moduleName: 'module1', // moduleName非必选
}
// context为发起端UIAbility的AbilityContext
this.context.startAbilityForResult(want).then((data) => {
    // ...
}).catch((err) => {
    // ...
})
  1. 在目标端UIAbility任务完成后,调用terminateSelfWithResult()方法,将数据返回给发起端的UIAbility。

const RESULT_CODE: number = 1001;
let abilityResult = {
    resultCode: RESULT_CODE,
    want: {
        bundleName: 'com.example.myapplication',
        abilityName: 'FuncAbility',
        moduleName: 'module1',
    },
}
// context为目标端UIAbility的AbilityContext
this.context.terminateSelfWithResult(abilityResult, (err) => {
    // ...
});
  1. 发起端UIAbility接收到目标端UIAbility返回的信息,对其进行处理。

const RESULT_CODE: number = 1001;

// ...

// context为调用方UIAbility的AbilityContext
this.context.startAbilityForResult(want).then((data) => {
    if (data?.resultCode === RESULT_CODE) {
        // 解析目标端UIAbility返回的信息
        let info = data.want?.parameters?.info
        // ...
    }
}).catch((err) => {
    // ...
})
通过跨设备连接ServiceExtensionAbility组件实现多端协同

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

接口说明

表3 跨设备连接API接口功能介绍

接口名

描述

connectServiceExtensionAbility(want: Want, options: ConnectOptions): number;

连接ServiceExtensionAbility。

disconnectServiceExtensionAbility(connection: number, callback:AsyncCallback<void>): void;

断开连接(callback形式)。

disconnectServiceExtensionAbility(connection: number): Promise<void>;

断开连接(promise形式)。

开发步骤
  1. 在module.json5配置数据同步权限,示例代码如下。

{
  "module": {
    "requestPermissions":[  
      {  
        "name" : "ohos.permission.DISTRIBUTED_DATASYNC",
      }
    ]
  }
}
  1. 申请数据同步权限,弹框示例代码。

requestPermission() {   
    let context = this.context
    let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']   
    context.requestPermissionsFromUser(permissions).then((data) => {   
        console.info("Succeed to request permission from user with data: "+ JSON.stringify(data))
    }).catch((error) => {       
        console.info("Failed to request permission from user with error: "+ JSON.stringify(error))   
    }) 
}
  1. 如果已有后台服务,请直接进入下一步;如果没有,则​​实现一个后台服务​​。
  2. 连接一个后台服务。
  • 实现IAbilityConnection接口。IAbilityConnection提供了以下方法供开发者实现:onConnect()是用来处理连接Service成功的回调,onDisconnect()是用来处理Service异常终止的回调,onFailed()是用来处理连接Service失败的回调。
  • 设置目标组件参数,包括目标设备ID、包名、ability名。
  • 调用connectServiceExtensionAbility发起连接。
  • 连接成功,收到目标设备返回的服务句柄。
  • 进行跨设备调用,获得目标端服务返回的结果。

import rpc from '@ohos.rpc';

const REQUEST_CODE = 99;
let want = {
    "deviceId": getRemoteDeviceId(), 
    "bundleName": "com.example.myapplication",
    "abilityName": "ServiceExtAbility"
};
let options = {
    onConnect(elementName, remote) {
        console.info('onConnect callback');
        if (remote === null) {
            console.info(`onConnect remote is null`);
            return;
        }
        let option = new rpc.MessageOption();
        let data = new rpc.MessageParcel();
        let reply = new rpc.MessageParcel();
        data.writeInt(1);
        data.writeInt(99);  // 开发者可发送data到目标端应用进行相应操作

        // @param code 表示客户端发送的服务请求代码。
        // @param data 表示客户端发送的{@link MessageParcel}对象。
        // @param reply 表示远程服务发送的响应消息对象。
        // @param options 指示操作是同步的还是异步的。
        // 
        // @return 如果操作成功返回{@code true}; 否则返回 {@code false}。
        remote.sendRequest(REQUEST_CODE, data, reply, option).then((ret) => {
            let msg = reply.readInt();   // 在成功连接的情况下,会收到来自目标端返回的信息(100)
            console.info(`sendRequest ret:${ret} msg:${msg}`);
        }).catch((error) => {
            console.info('sendRequest failed');
        });
    },
    onDisconnect(elementName) {
        console.info('onDisconnect callback')
    },
    onFailed(code) {
        console.info('onFailed callback')
    }
}
// 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入
let connectionId = this.context.connectServiceExtensionAbility(want, options);

getRemoteDeviceId方法参照​​通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据​​。

  1. 断开连接。调用disconnectServiceExtensionAbility()断开与后台服务的连接。

let connectionId = 1 // 在通过connectServiceExtensionAbility绑定服务时返回的Id
this.context.disconnectServiceExtensionAbility(connectionId).then((data) => {
    console.info('disconnectServiceExtensionAbility success');
}).catch((error) => {
    console.error('disconnectServiceExtensionAbility failed');
})
通过跨设备Call调用实现多端协同

跨设备Call调用的基本原理与设备内Call调用相同,请参见​​通过Call调用实现UIAbility交互(仅对系统应用开放)​​。

下面介绍跨设备Call调用实现多端协同的方法。

接口说明

表4 Call API接口功能介绍

接口名

描述

startAbilityByCall(want: Want): Promise<Caller>;

启动指定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<void>

向通用组件Callee发送约定序列化数据。

callWithResult(method: string, data: rpc.Parcelable): Promise<rpc.MessageSequence>

向通用组件Callee发送约定序列化数据, 并将Callee返回的约定序列化数据带回。

release(): void

释放通用组件的Caller通信接口。

on(type: “release”, callback: OnReleaseCallback): void

注册通用组件通信断开监听通知。

开发步骤
  1. 在module.json5配置数据同步权限,示例代码如下。

{
  "module": {
    "requestPermissions":[  
      {  
        "name" : "ohos.permission.DISTRIBUTED_DATASYNC",
      }
    ]
  }
}
  1. 申请数据同步权限,弹框示例代码。

requestPermission() {   
    let context = this.context
    let permissions: Array<string> = ['ohos.permission.DISTRIBUTED_DATASYNC']   
    context.requestPermissionsFromUser(permissions).then((data) => {   
        console.info("Succeed to request permission from user with data: "+ JSON.stringify(data))
    }).catch((error) => {       
        console.info("Failed to request permission from user with error: "+ JSON.stringify(error))   
    }) 
}
  1. 创建被调用端UIAbility。 被调用端UIAbility需要实现指定方法的数据接收回调函数、数据的序列化及反序列化方法。在需要接收数据期间,通过on接口注册监听,无需接收数据时通过off接口解除监听。

  a.  配置UIAbility的启动模式。 配置module.json5,将CalleeAbility配置为单实例"singleton"。

Json字段

字段说明

“launchType”

Ability的启动模式,设置为"singleton"类型。

UIAbility配置标签示例如下:

"abilities":[{
    "name": ".CalleeAbility",
    "srcEntrance": "./ets/CalleeAbility/CalleeAbility.ts",
    "launchType": "singleton",
    "description": "$string:CalleeAbility_desc",
    "icon": "$media:icon",
    "label": "$string:CalleeAbility_label",
    "visible": true
}]

  b.  导入UIAbility模块。

import Ability from '@ohos.app.ability.UIAbility' 

  c.  定义约定的序列化数据。 调用端及被调用端发送接收的数据格式需协商一致,如下示例约定数据由number和string组成。

export default class MyParcelable {
    num: number = 0
    str: string = ""

    constructor(num, string) {
        this.num = num
        this.str = string
    }

    marshalling(messageSequence) {
        messageSequence.writeInt(this.num)
        messageSequence.writeString(this.str)
        return true
    }

    unmarshalling(messageSequence) {
        this.num = messageSequence.readInt()
        this.str = messageSequence.readString()
        return true
    }
}

  d.  实现Callee.on监听及Callee.off解除监听。 如下示例在Ability的onCreate注册MSG_SEND_METHOD监听,在onDestroy取消监听,收到序列化数据后作相应处理并返回。应用开发者根据实际业务需要做相应处理。

const TAG: string = '[CalleeAbility]'
const MSG_SEND_METHOD: string = 'CallSendMsg'

function sendMsgCallback(data) {
    console.info('CalleeSortFunc called')

    // 获取Caller发送的序列化数据
    let receivedData = new MyParcelable(0, '')
    data.readParcelable(receivedData)
    console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`)

    // 作相应处理
    // 返回序列化数据result给Caller
    return new MyParcelable(receivedData.num + 1, `send ${receivedData.str} succeed`)
}

export default class CalleeAbility extends Ability {
    onCreate(want, launchParam) {
        try {
            this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
        } catch (error) {
            console.info(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`)
        }
    }

    onDestroy() {
        try {
            this.callee.off(MSG_SEND_METHOD)
        } catch (error) {
            console.error(TAG, `${MSG_SEND_METHOD} unregister failed with error ${JSON.stringify(error)}`)
        }
    }
}
  1. 获取Caller接口,访问被调用端UIAbility。

  a.  导入UIAbility模块。

import Ability from '@ohos.app.ability.UIAbility' 

  b.  获取Caller通信接口。 Ability的context属性实现了startAbilityByCall方法,用于获取指定通用组件的Caller通信接口。如下示例通过this.context获取Ability实例的context属性,使用startAbilityByCall拉起Callee被调用端并获取Caller通信接口,注册Caller的onRelease监听。应用开发者根据实际业务需要做相应处理。

async onButtonGetRemoteCaller() {
    var caller = undefined
    var context = this.context

    context.startAbilityByCall({
        deviceId: getRemoteDeviceId(),
        bundleName: 'com.samples.CallApplication',
        abilityName: 'CalleeAbility'
    }).then((data) => {
        if (data != null) {
            caller = data
            console.info('get remote caller success')
            // 注册caller的release监听
            caller.onRelease((msg) => {
                console.info(`remote caller onRelease is called ${msg}`)
            })
            console.info('remote caller register OnRelease succeed')
        }
    }).catch((error) => {
        console.error(`get remote caller failed with ${error}`)
    })
}

getRemoteDeviceId方法参照​​通过跨设备启动uiability和serviceextensionability组件实现多端协同无返回数据​​。

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

  a.  向被调用端发送Parcelable数据有两种方式,一种是不带返回值,一种是获取被调用端返回的数据,method以及序列化数据需要与被调用端协商一致。如下示例调用Call接口,向Callee被调用端发送数据。

const MSG_SEND_METHOD: string = 'CallSendMsg'
async onButtonCall() {
    try {
        let msg = new MyParcelable(1, 'origin_Msg')
        await this.caller.call(MSG_SEND_METHOD, msg)
    } catch (error) {
        console.info(`caller call failed with ${error}`)
    }
}

  b.  如下示例调用CallWithResult接口,向Callee被调用端发送待处理的数据originMsg,并将’CallSendMsg’方法处理完毕的数据赋值给backMsg。

const MSG_SEND_METHOD: string = 'CallSendMsg'
originMsg: string = ''
backMsg: string = ''
async onButtonCallWithResult(originMsg, backMsg) {
    try {
        let msg = new MyParcelable(1, originMsg)
        const data = await this.caller.callWithResult(MSG_SEND_METHOD, msg)
        console.info('caller callWithResult succeed')

        let result = new MyParcelable(0, '')
        data.readParcelable(result)
        backMsg(result.str)
        console.info(`caller result is [${result.num}, ${result.str}]`)
    } catch (error) {
        console.info(`caller callWithResult failed with ${error}`)
    }
}
  1. 释放Caller通信接口。 Caller不再使用后,应用开发者可以通过release接口释放Caller。

releaseCall() {
    try {
        this.caller.release()
        this.caller = undefined
        console.info('caller release succeed')
    } catch (error) {
        console.info(`caller release failed with ${error}`)
    }
}




文章转载自:​​https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/application-dev/application-models/hop-multi-device-collaboration.md/​

已于2023-4-10 17:29:07修改
收藏
回复
举报
回复
    相关推荐