HarmonyOS 应用接续实战:从跨端迁移到数据恢复完整方案
用户在手机上编辑备忘录,走到办公室后切换到平板上继续编辑。这不是简单的"重新打开",而是把手机上的编辑进度、光标位置、甚至未保存的内容,全部搬到平板上。这就是应用接续——当用户在一个设备上操作应用时,可以在另一个设备的相同应用中快速切换,无缝衔接上一个设备的应用体验。鸿蒙系统已经把底层的事情干完了:设备发现、连接、组网,都不需要你操心。你只需要关注两件事:怎么保存数据,怎么恢复数据。应用接续的核心
把应用从一个设备搬到另一个设备,无缝衔接,不让用户感觉到"断"
什么是应用接续
用户在手机上编辑备忘录,走到办公室后切换到平板上继续编辑。这不是简单的"重新打开",而是把手机上的编辑进度、光标位置、甚至未保存的内容,全部搬到平板上。
这就是应用接续——当用户在一个设备上操作应用时,可以在另一个设备的相同应用中快速切换,无缝衔接上一个设备的应用体验。
鸿蒙系统已经把底层的事情干完了:设备发现、连接、组网,都不需要你操心。你只需要关注两件事:怎么保存数据,怎么恢复数据。
实现原理

接续的前提条件
不是随便就能接续的,有硬性条件:
设备条件:
- HarmonyOS NEXT Developer Preview0 及以上版本
- 双端设备登录同一华为账号
- 双端设备打开 WLAN 和蓝牙开关,或者启用"多设备协同增强服务"
- 双端设备在"设置"中开启"多设备协同 > 接续"功能
- 双端设备都安装了该应用
数据条件:
- onContinue 回调中传输的数据控制在 100KB 以下
- 大数据量请用分布式对象迁移
权限条件(API11及以前版本):
- 需要声明 ohos.permission.DISTRIBUTED_DATASYNC 权限
- 需要向用户申请授权
API12起,不再需要申请权限。
哪些场景需要接续?哪些不需要?
不是所有应用都适合接续,要看场景:
工具类(备忘录、笔记、日历、邮箱、浏览器)
场景:备忘录详情页、笔记编辑页、日历日程页面、邮件编辑页面、网页详情页
同步内容:浏览进度、编辑进度、附件
源端处理:退出
比如你在手机上写邮件,写到一半换到平板继续写。手机上的邮件应用可以退出,因为任务已经搬到平板上了。
出行导航类(地图服务)
场景:路线查询、导航界面
同步内容:当前路线、导航进度
源端处理:退出
影音娱乐类(视频、音乐、直播)
场景:音视频播放页、直播页
同步内容:播放进度、直播进度
源端处理:按需适配
这类应用比较特殊。音乐播放时,源端可以选择不退出,只暂停播放;直播时,源端可以不退出也不暂停,因为用户可能想两边都看。
新闻阅读类(听书、电子书、新闻)
场景:书籍首页、小说阅读页、听书页、新闻详情页
同步内容:阅读进度、听书进度
源端处理:退出,但听书或直播类可以不退出
办公类(会议、CAD编辑)
场景:会议界面、CAD编辑界面
同步内容:会议状态、编辑内容
源端处理:
- 会议:不退出应用,只退出会议,返回聊天框界面
- CAD:按需适配
社交通讯类(社交媒体平台)
场景:图文浏览、视频浏览、编辑页
同步内容:浏览进度、编辑进度
源端处理:按需适配
其他类(拍摄美化、便捷生活、金融理财、游戏)
按需适配。核心原则:看用户是否需要同时在多端使用,如果需要,源端不退出;如果不需要,源端退出。
接续怎么运作?
三个步骤:源端保存 → 系统传输 → 对端恢复
源端:onContinue() 回调
用户触发迁移时,源端的 onContinue() 被调用。你要在这里保存迁移数据。
onContinue(wantParam: Record<string, Object>) {
// 获取对端应用版本号,做兼容校验
const targetVersion = wantParam.version;
if (targetVersion < 0) {
promptAction.showToast({
message: '对端应用版本号过低,不支持接续',
duration: 2000
});
return AbilityConstant.OnContinueResult.MISMATCH;
}
// 保存迁移数据
const continueInput = '迁移的数据';
if (continueInput) {
wantParam['data'] = continueInput;
}
return AbilityConstant.OnContinueResult.AGREE;
}
返回值决定是否支持迁移:
- AGREE:同意
- REJECT:拒绝(应用异常时)
- MISMATCH:版本不匹配
wantParam 中的系统预置字段:
- version:对端应用版本号
- targetDevice:对端设备的 networkId
对端:onCreate() / onNewWant() 回调
对端启动时,根据启动模式调用不同接口:
- 冷启动或多实例应用热启动:onCreate()
- 单实例应用热启动:onNewWant()
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);
}
// 恢复页面栈
this.context.restoreWindowStage(this.storage);
}
}
重要:restoreWindowStage() 必须在同步接口方法中执行,如果在异步回调中执行,页面可能加载失败。
开发步骤
1. 启用接续能力
在 module.json5 中配置:
{
"module": {
"abilities": [
{
"continuable": true
}
]
}
}
2. 配置启动模式
参考 UIAbility 组件启动模式,根据业务需求选择。
3. 源端保存数据
在 onContinue() 中保存数据,可选做兼容校验。
4. 对端恢复数据
在 onCreate() / onNewWant() 中恢复数据,调用 restoreWindowStage() 恢复页面栈。

高级配置
同应用不同 Ability 迁移
如果应用在不同设备上的 Ability 名称不同(比如手机叫 EntryAbility,平板叫 PadAbility),需要用 continueType 关联:
// 设备A
{
"abilities": [
{
"name": "Ability-deviceA",
"continueType": ['continueType1']
}
]
}
// 设备B
{
"abilities": [
{
"name": "Ability-deviceB",
"continueType": ['continueType1']
}
]
}
continueType 必须一致,在本应用中唯一,最大长度127字节,不支持中文。
同应用不同 BundleName 迁移
如果应用在不同设备上使用不同的 BundleName(比如手机是 com.demo.example1,平板是 com.demo.example2),需要配置 continueBundleName:
// 设备A(BundleName: com.demo.example1)
{
"abilities": [
{
"continueType": ['continueType'],
"continueBundleName": ["com.demo.example2"]
}
]
}
// 设备B(BundleName: com.demo.example2)
{
"abilities": [
{
"continueType": ['continueType'],
"continueBundleName": ["com.demo.example1"]
}
]
}
如果是不同开发者发布的应用,需要在 AppGallery Connect 平台申请"接续服务",填写对方的 APP ID。
快速启动目标应用
默认情况下,发起迁移后不会立即拉起对端应用,而是等待数据传输完成。如果想立即拉起,减少等待时间,可以在 continueType 后添加 “_ContinueQuickStart” 后缀:
{
"abilities": [
{
"continueType": ['EntryAbility_ContinueQuickStart']
}
]
}
配置快速启动后,会收到两次启动请求:
- 第一次:PREPARE_CONTINUATION(提前拉起)
- 第二次:CONTINUATION(接续拉起)
动态配置迁移能力
默认状态下,迁移能力是开启的(ACTIVE)。如果需要只在某些页面或某些事件发生时才支持迁移,可以动态设置:
// onCreate() 中关闭迁移能力
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
this.context.setMissionContinueState(AbilityConstant.ContinueState.INACTIVE, (result) => {
console.info(`setMissionContinueState: ${JSON.stringify(result)}`);
});
}
// 特定页面的 onPageShow() 中打开迁移能力
onPageShow() {
this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
console.info('setMissionContinueState ACTIVE result: ', JSON.stringify(result));
});
}
重要:迁移完成后,要重新设置为 ACTIVE,保证迁移的连续性。
按需迁移页面栈
默认情况下,系统会自动恢复页面栈。如果不想用默认页面栈,可以设置不迁移:
onContinue(wantParam: Record<string, Object>) {
wantParam[wantConstant.Params.SUPPORT_CONTINUE_PAGE_STACK_KEY] = false;
return AbilityConstant.OnContinueResult.AGREE;
}
onWindowStageRestore(windowStage: window.WindowStage) {
windowStage.loadContent('continue/PageName', (err, data) => {
// ...
});
}
当前仅支持 router 路由的页面栈自动恢复,navigation 路由需要手动处理。
按需退出
默认情况下,迁移成功后源端应用会退出。如果不想退出,可以设置:
onContinue(wantParam: Record<string, Object>) {
wantParam[wantConstant.Params.SUPPORT_CONTINUE_SOURCE_EXIT_KEY] = false;
return AbilityConstant.OnContinueResult.AGREE;
}
常见问题排查
对端不显示接续图标
检查四个条件:
- 蓝牙是否已开启
- 接续功能是否已开启(设置 -> 多设备协同 -> 接续)
- 是否已登录相同的华为账号
- 组网是否成功(命令行检查:
hidumper -s 4700 -a "buscenter -l remote_device_info")
1分钟后图标消失
这是系统的特性,不是 bug。图标在最后一次触屏操作后的1分钟内保持显示,超过1分钟会自动隐藏,减少对用户的干扰。再次操作应用时,图标会重新出现。
新接入的应用不出现图标
检查三个条件:
- 两端都已安装应用
- continuable 标签设置为 true
- 应用没有调用 setMissionContinueState() 将迁移状态设置为 false
避坑指南
restoreWindowStage() 不要放在异步回调里:会导致页面加载失败。
onWindowStageCreate() 的初始化要在 onWindowStageRestore() 里重做:迁移后不执行 onWindowStageCreate(),只执行 onWindowStageRestore()。
数据不要超过 100KB:大数据用分布式对象迁移。
continueType 不要用中文:最大长度127字节,只支持字母、数字、下划线。
迁移后要重新设置迁移状态为 ACTIVE:保证迁移的连续性。
总结
应用接续的核心,就是"搬"——把用户的应用状态从一个设备搬到另一个设备。鸿蒙系统已经把底层的事干完了,你只需要在源端保存数据,在对端恢复数据。
关键步骤:
- 配置 continuable 标签启用接续能力
- 在 onContinue() 中保存数据(可选做版本兼容校验)
- 在 onCreate() / onNewWant() 中恢复数据,调用 restoreWindowStage()
高级能力:
- continueType 关联不同 Ability
- continueBundleName 关联不同 BundleName
- 快速启动减少等待时间
- 动态配置迁移能力
- 按需迁移页面栈和按需退出
记住:接续不是重新打开,而是无缝衔接。用户不应该感觉到"断",任务应该像流水一样自然流动。
更多推荐




所有评论(0)