鸿蒙跨设备协同开发06——应用接续
如果你也对鸿蒙开发感兴趣,加入“Harmony自习室”吧!扫描下方名片,关注公众号,公众号更新更快,同时也有更多学习资料和技术讨论群。
1、概 述
应用接续是指:用户在一个设备上操作某个应用时,可以在另一个设备的同一个应用中快速切换,并无缝衔接上一个设备的应用体验。
如下图所示,用户在手机上编辑备忘录,到办公室后切换到平板上继续编辑,完成任务的无缝衔接。
针对不同类型的应用,推荐的应用接续发起的界面及接续同步内容如下:
-
浏览器:网页内容详情页,网页浏览进度同步
-
备忘录:备忘录详情页,备忘浏览进度同步
-
新闻:新闻详情页,新闻浏览进度同步
-
阅读:小说阅读页,小说阅读进度同步
-
视频:视频播放页,视频播放进度同步
-
音乐:音乐播放页,歌单播放页,音乐播放进度同步
-
会议:会议界面,当前会议同步
-
邮件:新建邮件、回复转发邮件、阅读某封邮件界面,编辑内容及附件同步
-
办公编辑:某条编辑页面,编辑内容同步
-
CAD:CAD编辑界面,编辑内容同步
-
地图:路线查询、导航界面,当前路线及导航同步
应用接续可以实现将应用当前任务(包括页面控件状态变量等)迁移到目标设备并在目标设备上接续使用。可以实现的功能包括:
-
存储及恢复自定义数据(应用业务内容)。
-
存储及恢复页面路由信息和页面控件状态数据。
-
应用兼容性检测。
-
支持应用根据实际使用场景动态设置迁移状态(默认迁移状态为ACTIVE激活状态)。
-
如编辑类应用在编辑文本的页面下才需要迁移,其他页面不需要迁移,则可以通过setMissionContinueState进行控制。
-
支持应用动态选择是否进行页面栈恢复(默认进行页面栈信息恢复)。
-
如应用希望自定义迁移到其他设备后显示的页面,则可以通过wantConstant.Params进行控制。
-
支持应用动态选择流转成功后是否退出迁移源端应用(默认流转成功后退出迁移源端应用)。则可以通过@ohos.app.ability.wantConstant (wantConstant)进行控制。
使用应用接续,有以下条件需要满足:
-
设备的系统版本需要在HarmonyOS NEXT Developer Preview0及以上;
-
双端设备需要登录同一华为账号、打开Wi-Fi和蓝牙开关。
-
条件允许时,建议双端设备接入同一个局域网,可提升数据传输的速度。
-
应用接续只能在同应用(UIAbility)之间触发,双端设备都需要有该应用。
-
为了接续体验,在onContinue回调中使用wantParam传输的数据需要控制在100KB以下(大数据量使用分布式数据对象进行同步)
2、应用接续开发
应用接续的核心接口定义如下:
/*
接续源端在该回调中保存迁移所需要的数据,同时返回是否同意迁移:
AGREE:表示同意。
REJECT:表示拒绝,如应用在onContinue中异常可以直接REJECT。
MISMATCH:表示版本不匹配,接续源端应用可以在onContinue中获取到迁移对端应用的版本号,进行协商后,如果版本不匹配导致无法迁移,可以返回该错误。
*/
onContinue(wantParam : {[key: string]: Object}): OnContinueResult
/*
接续目的端为冷启动或多实例应用热启动时,在该回调中完成数据恢复,并触发页面恢复。
*/
onCreate(want: Want, param: AbilityConstant.LaunchParam): void;
/*
接续目的端为单实例应用热启动时,在该回调中完成数据恢复,并触发页面恢复。
*/
onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void;
👉🏻 step 1:开启应用接续
在module.json5文件的abilities中,将continuable标签配置为“true”,表示该UIAbility可被迁移。配置为false的UIAbility将被系统识别为无法迁移且该配置(默认值为false)。示例如下:
{
"module": {
...
"abilities": [
{
...
"continuable": true,
}
]
}
}
👉🏻 step 2:配置应用启动模式
系统提供了三种启动模式:
-
-
singleton(单实例模式)
-
multiton(多实例模式)
-
specified(指定实例模式)
-
以singleton为例,配置方式如下:
{
"module": {
// ...
"abilities": [
{
"launchType": "singleton",
// ...
}
]
}
}
👉🏻 step 3:在源端UIAbility中配置onContinue()接口
当应用触发迁移时,onContinue()接口在源端被调用,开发者可以在该接口中保存迁移数据,实现应用兼容性检测,决定是否支持此次迁移。
-
保存迁移数据:开发者可以将要迁移的数据通过键值对的方式保存在wantParam中。
-
应用兼容性检测:开发者可以从onContinue()入参wantParam.version获取到迁移对端应用的版本号,然后与迁移源端应用版本号做兼容校验。
-
迁移决策:开发者可以通过onContinue接口的返回值决定是否支持此次迁移。
示例如下:
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
export default class EntryAbility extends UIAbility {
onContinue(wantParam: Record<string, Object>) {
let versionDst = wantParam.version; // 获取迁移对端应用的版本号
let versionSrc: number = 0; // 获取迁移源端即本端应用的版本号
if (versionDst > versionSrc) { // 兼容性校验
// 兼容性校验不满足
return AbilityConstant.OnContinueResult.MISMATCH;
}
console.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`)
// 迁移数据保存
let continueInput = '迁移的数据';
if (continueInput) {
// 将要迁移的数据保存在wantParam的自定义字段(如:data)中;
wantParam["data"] = continueInput;
}
return AbilityConstant.OnContinueResult.AGREE;
}
}
👉🏻 step 4:接续端数据恢复、加载界面
在Stage模型中,应用在不同启动模式下将调用不同的接口,以恢复数据、加载界面。
不同情况下的函数调用如下图所示:
在应用接续启动时,无论是冷启动还是热启动,都会在执行完onCreate()/onNewWant()后,触发onWindowStageRestore()生命周期函数,不执行onWindowStageCreate()生命周期函数。
我们如果在onWindowStageCreate()中进行了一些应用启动时必要的初始化,那么迁移后需要在onWindowStageRestore()中执行同样的初始化操作,避免应用异常。
在接续端UIAbility中实现onCreate()与onNewWant()接口,恢复迁移数据。
⭐️ onCreate实现示例;
-
目的端设备上,在onCreate中根据launchReason判断该次启动是否为迁移LaunchReason.CONTINUATION。
-
从want中获取保存的迁移数据。
-
若我们使用系统页面栈恢复功能,则需要在onCreate()/onNewWant()执行完成前,调用restoreWindowStage(),来触发带有页面栈的页面恢复。
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import Want from '@ohos.app.ability.Want';
export default class EntryAbility extends UIAbility {
storage : LocalStorage = new LocalStorage();
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
// 将上述的保存的数据取出恢复
let continueInput = '';
if (want.parameters != undefined) {
continueInput = JSON.stringify(want.parameters.data);
console.info(`continue input ${continueInput}`)
}
// 触发页面恢复
this.context.restoreWindowStage(this.storage);
}
}
}
⭐️ 如果是单实例应用,需要额外实现onNewWant()接口,实现方式与onCreate()的实现相同。
在onNewWant()中判断迁移场景,恢复数据,并触发页面恢复。
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import Want from '@ohos.app.ability.Want';
export default class EntryAbility extends UIAbility {
storage : LocalStorage = new LocalStorage();
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
console.info(`EntryAbility onNewWant ${AbilityConstant.LaunchReason.CONTINUATION}`)
if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
// 将上述的保存的数据取出恢复
let continueInput = '';
if (want.parameters != undefined) {
continueInput = JSON.stringify(want.parameters.data);
console.info(`continue input ${continueInput}`);
}
this.context.restoreWindowStage(this.storage);
}
}
}