HarmonyOS 应用接续功能适配详解
1 引言
应用接续是 HarmonyOS 提供的一项跨设备协同能力:当用户在一台设备上操作某个应用时,可以在另一台设备的相同应用中快速切换,无缝衔接上一个设备的应用体验。在内容编辑、邮件撰写等需要连续性的场景中,用户往往希望从手机切换到平板后,已输入的文字、插入的图片等都能原样保留,而不必重新开始。本文结合两个官方 Codelabs——内容编辑场景与分布式邮件场景——系统介绍如何在 HarmonyOS 应用中适配接续能力,重点说明源端数据保存与对端数据恢复的实现方法,并对关键概念进行讲解。
2 基础概念与前置条件
2.1 应用接续
应用接续,指当用户在一个设备上操作某个应用时,可以在另一个设备的相同应用中快速切换,无缝衔接上一个设备的应用体验。其触发方式通常为:在源端设备前台运行应用,在对端设备 Dock 栏点击该应用的接续图标,系统即启动迁移流程。
2.2 分布式数据对象
分布式数据对象(@ohos.data.distributedDataObject)是 HarmonyOS 提供的一种数据管理能力。它是一个 JS 对象型的封装,每一个分布式数据对象实例会创建一个内存数据库中的数据表;每个应用程序创建的内存数据库相互隔离,对分布式数据对象的“读取”或“赋值”会自动映射到对应数据库的 get/put 操作。在接续场景中,利用分布式数据对象可以在源端设备保存待迁移的数据,并使对端设备加入同一会话后读取该数据,从而实现跨设备数据传递。
2.3 环境与设备要求
硬件要求:两台及以上 HarmonyOS 系统版本为 5.0.5 Release 及以上的设备,支持直板机、双折叠、三折叠、平板等。软件要求:DevEco Studio 6.1.1 Release 及以上,HarmonyOS SDK 6.1.1 Release 及以上。模拟器暂不支持接续功能。
2.4 使用限制与权限
接续功能要求:
- 双端设备登录同一华为账号;
- 双端设备打开 WLAN 和蓝牙开关,或在设置中启用“多设备协同增强服务”;
- 双端设备在设置中开启“多设备协同 > 接续”功能;
- 双端设备均安装该应用。
权限方面,自 API 12 起无需申请 ohos.permission.DISTRIBUTED_DATASYNC 权限;API 11 及以前版本需要声明该权限,并在首次启动或进入接续页面时向用户申请授权。
3 适配流程总览
应用接续适配可概括为四个步骤:
- 启用应用接续能力:在工程配置中声明 UIAbility 可迁移;
- 配置应用启动模式:推荐使用单实例模式;
- 源端保存迁移数据:在
onContinue回调中构建并保存待迁移数据; - 对端恢复数据:在生命周期回调中恢复分布式数据对象,并将数据写入 UI。
下面按照该顺序逐一讲解。
4 工程配置:启用接续能力与启动模式
4.1 配置 continuable
在 module.json5 文件的 abilities 中,将 continuable 标签配置为 true,表示该 UIAbility 可被迁移。默认值为 false,系统将识别为无法迁移。
// entry/src/main/module.json5
{
"module": {
"abilities": [
{
"continuable": true
}
]
}
}
4.2 配置 launchType
启动模式影响接续时应用实例的创建策略,推荐使用 singleton(单实例模式)。在内容编辑、邮件编写等接续场景中,单实例可以确保全局只存在一个实例,避免因多实例导致的数据不一致问题。
| 启动模式 | 配置值 | 特点 | 适用场景 |
|---|---|---|---|
| singleton | "singleton" |
单实例模式,应用全局只存在一个实例 | 接续场景推荐,确保数据一致性 |
| standard | "standard" |
多实例模式,每次启动创建新实例 | 适合需要独立处理多个任务的场景 |
| specified | "specified" |
指定实例模式,根据 MissionKey 决定是否创建新实例 | 复杂的文档按 ID 复用实例等场景 |
{
"module": {
"abilities": [
{
"launchType": "singleton"
}
]
}
}
5 源端数据保存与迁移
5.1 数据保存的基本原理
在接续触发前,源端应用需要将用户正在编辑的数据实时保存到全局存储中。HarmonyOS 提供 @StorageLink 装饰器,它可以将组件属性与 AppStorage 全局存储进行双向绑定:当组件中的数据发生变化时,自动更新 AppStorage 中的对应值;反之亦然。这样,在 onContinue 回调触发时,可以从 AppStorage 中读取到最新的编辑内容。
当源端设备满足接续条件且用户点击对端 Dock 栏接续图标时,系统会自动调用源端 UIAbility 的 onContinue 回调。开发者需要在该回调中完成数据打包与传输。需要注意的是,onContinue 回调中通过 wantParam 传输的数据应控制在 100KB 以下;对于大数据量(如图片文件),应使用分布式对象迁移数据。
5.2 构建数据模型
在内容编辑场景中,可以通过静态方法 buildFromAppStorage 从 AppStorage 中构建完整的数据模型。以 ContentInfo 为例,它包含标题、正文、图片及位置信息等字段,形成一个核心数据对象。对于图片等附件资源,需要将 ImageInfo 数组转换为 Asset 数组,并调用 flatAssets() 方法将模型扁平化,转换为可传输的 Record 结构。
5.3 创建并保存分布式数据对象
在 onContinue 中,核心工作是创建分布式数据对象并保存到目标设备。一般流程如下:
- 生成会话 ID:调用
genSessionId()生成全局唯一标识,用于源端与对端建立组网; - 创建分布式对象:调用
distributedDataObject.create()创建实例,并填充扁平化后的数据; - 设置会话:调用
setSessionId(sessionId)加入组网,同时将sessionId写入wantParam.distributedSessionId,以便对端读取后加入同一会话; - 持久化保存:调用
save()方法将分布式对象保存到目标设备,确保源端应用退出后数据仍可被对端获取。
下面给出一个简化后的 onContinue 实现示例:
// entry/src/main/ets/entryability/EntryAbility.ets
export default class EntryAbility extends UIAbility {
private distributedObject: distributedDataObject.DataObject | undefined = undefined;
async onContinue(wantParam: Record<string, Object | undefined>): Promise<AbilityConstant.OnContinueResult> {
try {
// 从 AppStorage 构建待迁移的数据模型,并进行扁平化处理
let content = ContentInfo.buildFromAppStorage();
let flatData = content.flatAssets();
// 创建分布式数据对象
this.distributedObject = distributedDataObject.create(this.context);
// 将扁平化数据填充到分布式对象中
for (let key in flatData) {
this.distributedObject[key] = flatData[key];
}
// 生成会话 ID 并设置组网
let sessionId = distributedDataObject.genSessionId();
this.distributedObject.setSessionId(sessionId);
wantParam.distributedSessionId = sessionId;
// 保存到目标设备
await this.distributedObject.save(wantParam.targetDevice as string);
} catch (err) {
// 记录错误日志
}
// 返回同意接续
return AbilityConstant.OnContinueResult.AGREE;
}
}
在实际工程中,可将上述步骤封装为一个工具函数(例如 saveDistributedDataForContinue),其执行流程包括生成会话 ID、读取数据、转换资产、构建模型、扁平化处理、创建分布式对象、建立会话、返回结果等,使 onContinue 更简洁。
6 对端数据恢复
当源端完成数据准备并传输后,对端设备需要根据应用当前是否已运行,分别走冷启动或热启动流程执行数据恢复。
6.1 冷启动与热启动
- 冷启动:应用未运行,系统创建应用实例并调用
onCreate回调。此时需要判断本次启动是否为接续启动,并初始化分布式数据连接。 - 热启动:应用已在后台运行,系统不再新建实例,而是调用
onNewWant回调。此时需要执行接续数据更新逻辑。
无论冷启动还是热启动,在应用迁移启动后,都会在执行完 onCreate/onNewWant 后触发 onWindowStageRestore 生命周期函数,可以在该函数中手动加载要恢复的页面。
为了保证迁移后的应用仍然具备可以迁移回源端的能力,需要在 onCreate 和 onNewWant 中调用 setMissionContinueState(),将迁移状态设置为 ACTIVE。
6.2 恢复分布式数据对象
对端恢复流程如下:
- 创建空的分布式数据对象,用于接收恢复的数据;
- 从
want参数中读取源端传递过来的分布式数据对象组网 ID(distributedSessionId); - 调用
setSessionId(sessionId)加入与源端一致的组网,激活分布式数据对象; - 注册状态监听:调用
on()接口监听数据变更,当收到status为restored的事件回调时,表示数据已恢复完成; - 在回调中通过分布式数据对象读取源端保存的数据,并写入
AppStorage,供页面使用。
以下是对端恢复的示例代码(简化):
// entry/src/main/ets/entryability/EntryAbility.ets
export default class EntryAbility extends UIAbility {
private distributedObject: distributedDataObject.DataObject | undefined = undefined;
async restoreDistributedObject(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
// 设置迁移状态为 ACTIVE,保证后续可继续迁移
this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE);
// 创建空的分布式数据对象
this.distributedObject = distributedDataObject.create(this.context);
// 从 want 读取组网 ID 并加入会话
let sessionId = want.parameters?.distributedSessionId as string;
this.distributedObject.setSessionId(sessionId);
// 注册状态监听
this.distributedObject.on('status', (data) => {
if (data.status === 'restored') {
// 将分布式对象中的数据恢复到 AppStorage
AppStorage.setOrCreate('mainTitle', this.distributedObject['mainTitle']);
AppStorage.setOrCreate('textContent', this.distributedObject['textContent']);
// 如有文件资产,执行文件复制
// ...
}
});
// 恢复窗口舞台
this.context.restoreWindowStage(new LocalStorage());
}
onWindowStageRestore(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Home', (err, data) => {
if (err.code) {
// 日志
return;
}
});
}
}
6.3 数据恢复到 AppStorage
文本类数据(如标题、正文、邮件收件人、发件人、主题等)可以直接从分布式数据对象中读取并写入 AppStorage。页面组件通过 @StorageLink 绑定这些键值,当 AppStorage 数据变化时,UI 会自动刷新,无需手动调用刷新方法。
6.4 文件资产迁移与复制
在内容编辑场景中,图片等文件资产通过分布式对象进行传输。数据恢复时,需要将这些文件从分布式目录复制到本地目录,以便应用正常访问。一般流程为:
- 遍历分布式对象中的附件资产;
- 将文件从
distributedFilesDir复制到本地filesDir目录; - 读取文件并创建
PixelMap图像对象,供页面展示。
这一过程通常封装在 fileCopy() 之类的工具函数中,包含文件读取、写入、图像源创建等完整流程,确保接续后图片能够正常显示。
6.5 页面数据自动刷新
页面组件使用 @StorageLink 装饰器绑定 AppStorage 中的数据,实现了双向数据绑定。具体机制为:当 AppStorage 中数据变化时,系统自动触发组件监测,执行页面重新渲染。例如:
@Component
export struct EditorComponent {
@StorageLink('mainTitle') mainTitle: string = '';
@StorageLink('textContent') textContent: string = '';
build() {
Flex({ direction: FlexDirection.Column }) {
TextInput({ text: this.mainTitle, placeholder: '请输入标题' })
.onChange((value: string) => {
this.mainTitle = value;
})
TextArea({ text: this.textContent, placeholder: '请输入正文' })
// ...
}
}
}
上述代码中,mainTitle 和 textContent 通过 @StorageLink 与全局存储绑定;源端编辑时实时更新 AppStorage,对端恢复后 AppStorage 更新,页面自动同步显示。
7 分布式邮件场景的页面实现要点
在“分布式邮件”示例中,页面主要由顶部标题栏和邮件信息内容区两部分组成。顶部标题栏使用 Flex 容器组件以弹性方式布局子组件,通过 SymbolGlyph 展示返回按钮和发送按钮,使用 Text 组件展示应用标题,并通过 flexGrow 属性使标题占满剩余空间。邮件信息内容区使用 Row 组件逐行展示收件人、发件人、主题和内容,使用 TextInput 和 TextArea 组件展示具体信息并实现输入,数据来源为 AppStorage 中存储的邮件信息。
8 注意事项与最佳实践
- 大数据量应使用分布式对象:
onContinue回调中通过wantParam传输的数据需控制在 100KB 以下,图片、文件等资产应通过分布式数据对象迁移。 - 合理选择启动模式:接续场景推荐
singleton单实例模式,确保数据一致性;如需多任务并行,可考虑standard或specified。 - 会话 ID 一致性:源端通过
genSessionId()生成的会话 ID 必须通过wantParam.distributedSessionId传递给对端,对端使用相同 ID 调用setSessionId()才能加入同一组网。 - 恢复后保持可迁移能力:对端在
onCreate/onNewWant中调用setMissionContinueState()将状态设置为ACTIVE,保证迁移后的应用仍可迁回源端。 - 监听恢复状态:对端应在分布式对象上注册状态监听,待收到
restored事件后再进行数据读取和 UI 更新,避免数据尚未同步完成就读取导致内容缺失。 - 文件资产路径处理:对端恢复文件时,要将文件从
distributedFilesDir复制到本地filesDir,并创建相应图像对象,确保文件可长期访问。 - 满足双端条件:开发调试前确保双端登录同一华为账号、开启 WLAN 和蓝牙或“多设备协同增强服务”、开启“接续”功能、双端均安装应用。
9 总结
本文基于内容编辑与分布式邮件两个场景,详细介绍了 HarmonyOS 应用接续功能的适配方法。核心步骤包括:在 module.json5 中启用 continuable 并配置合适的启动模式;在源端通过 @StorageLink 实时保存数据,并在 onContinue 回调中使用分布式数据对象保存和传输数据;在对端根据冷启动或热启动分别处理,恢复分布式对象、监听恢复状态、将数据写入 AppStorage,并完成文件资产复制与页面自动刷新。掌握这些方法后,开发者可以高效地为应用添加跨设备无缝接续能力,提升用户的连续工作体验。
更多推荐

所有评论(0)