HarmonyOS 7 实战 15:应用接续与跨端流转实战
手机看一半,换平板还得重新找进度?
不知道大家有没有这种体验:在手机上看着一篇长文,或者正在编辑一个备忘录,突然想换平板接着看。结果打开平板,发现应用虽然能登录,但刚才看的内容和进度全没了。
这体验简直割裂。
HarmonyOS 最核心的卖点之一就是“分布式”,其中“应用接续”(Migration/Continuation)就是解决这个痛点的终极方案。用户只需要在手机底部轻轻上滑,选择平板图标,应用就“飞”到了平板上,不仅状态还在,进度甚至能精确到秒。
听起来很科幻对吧?很多同学去官网翻了半天 API,代码写完了,结果两台设备死活连不上,或者流转过去直接闪退。
这篇就把应用接续的完整链路拆开,带你避过所有坑。
一、接续不是魔法,先搞懂它的约束条件
写代码之前,必须先明确几件事,不然你 debug 到凌晨都找不到原因。
-
必须登录同一个华为账号(这是基础中的基础,账号不同,软总线直接屏蔽)。
-
两台设备必须开启蓝牙和 WLAN(分布式软总线底层依赖这些通信能力)。
-
设备必须在同一个局域网,或者靠近。
-
bundleName必须完全一致(应用包名不同,系统怎么知道要把状态给谁?)。
而且,应用接续不是自动的。系统只提供“流转的通道”,具体存什么状态、怎么恢复,全都要你自己写。
二、核心 API:onContinue 与 onCreate/onNewWant
应用接续的核心生命周期是 UIAbility 的 onContinue 和 onCreate/onNewWant。
当用户在手机上点击“接续”按钮,系统会调用源设备 Ability 的 onContinue:
typescript
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>): AbilityConstant.OnContinueResult {
// 保存当前状态
const currentProgress = AppStorage.get<number>('readProgress') || 0;
const articleId = AppStorage.get<string>('currentArticleId') || '';
// 把要流转的数据塞进 wantParam
wantParam['progress'] = currentProgress;
wantParam['articleId'] = articleId;
wantParam['timestamp'] = Date.now();
console.info('onContinue 保存状态成功');
return AbilityConstant.OnContinueResult.AGREE; // 返回同意接续
}
}
坑来了:onContinue 必须是同步的,且必须在 1 秒内返回!
你千万不要在这里面做网络请求、读大文件或者耗时计算。它只能用来同步地把内存里的状态塞进 wantParam。如果你写得慢,系统会认为你放弃了接续,直接返回 REJECT。
那如果数据很大怎么办?比如用户编辑了一个几十兆的文档。
答案是:只传关键标识(如文档 ID 和版本号),具体数据让目标设备自己去云端或者本地分布式文件系统拉取。
三、目标设备恢复:onCreate 与 onNewWant 的双重考验
数据传过来了,目标设备(平板)怎么接?
这取决于平板上应用的状态:
-
如果平板上应用没启动,走
onCreate。 -
如果平板上应用已经在后台,走
onNewWant。
所以,恢复逻辑必须写两遍(或者抽成一个公共函数):
typescript
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
if (want.parameters && want.parameters.articleId) {
this.restoreState(want.parameters);
}
}
onNewWant(want, launchParam) {
if (want.parameters && want.parameters.articleId) {
this.restoreState(want.parameters);
}
}
private restoreState(params: Record<string, Object>) {
const articleId = params.articleId as string;
const progress = params.progress as number;
// 把数据存到 AppStorage,页面加载时读取
AppStorage.setOrCreate('restoredArticleId', articleId);
AppStorage.setOrCreate('restoredProgress', progress);
// 如果需要跳转到指定页面
// 注意:不要在这里直接 router.pushUrl,可能页面栈还没准备好
}
}
这里有个让人痛不欲生的坑:冷启动时的页面跳转。
平板上的应用是冷启动,onCreate 执行时,UI 的首页可能还没加载完(甚至还没创建 WindowStage)。你在 onCreate 里调 router.pushUrl,100% 失败或者白屏。
正确的解法是: 用 AppStorage 暂存数据。首页的 aboutToAppear 或 onPageShow 里读取这个数据,再决定是否跳转。
typescript
// Index.ets
aboutToAppear() {
const restoredArticleId = AppStorage.get<string>('restoredArticleId');
if (restoredArticleId) {
// 数据到了,再跳转
router.pushUrl({ url: 'pages/ArticlePage', params: { articleId: restoredArticleId } });
// 清除标记,防止下次热启动重复跳转
AppStorage.setOrCreate('restoredArticleId', undefined);
}
}
四、动态选择设备:别让用户手动挑
很多时候,用户不止一台设备。手机旁边可能有个平板,还有个智慧屏。系统怎么知道流转到哪台?
系统会弹出一个设备选择列表。但如果你想让体验更好,可以用 distributedDeviceManager 主动获取可流转的设备:
typescript
import deviceManager from '@ohos.distributedDeviceManager';
const dm = deviceManager.createDeviceManager('com.example.myapp');
const deviceList = dm.getAvailableDeviceListSync();
// 你可以根据设备类型、距离等条件,自动选中一个设备进行流转
不过,生产环境里建议还是给用户选择权,别自作聪明。用户可以自己决定是流转到平板,还是智慧屏。
另外,流转成功或失败,都要给用户明确的提示,别静静地什么都不做。
五、踩坑合集:那些让你怀疑人生的瞬间
坑一:接续失败了,但没有任何报错。
先检查账号是否一致,再检查网络(必须同一局域网或者蓝牙配对)。最后检查 bundleName 是否一样。这三个错一点,系统直接静默失败,连日志都不给你留。
坑二:传中文乱码。
wantParam 里传字符串没问题,但如果传复杂对象,一定要序列化。推荐用 JSON.stringify 转成字符串再传,接收方再 JSON.parse。别传 ArrayBuffer,那个坑更多。
坑三:恢复状态后,页面闪烁。
如果你在 Index 页面 aboutToAppear 里先渲染了默认的空白状态,等 AppStorage 数据到了再跳转,中间会有个短暂的闪烁。解法是:加一个 @State isLoading = true 的状态,数据没准备好之前,先显示一个 Loading 或者骨架屏。
六、总结
应用接续是 HarmonyOS 分布式能力最具感知度的功能。核心记住三点:
-
onContinue必须同步返回,只传关键状态(ID、进度),不要传大数据。 -
恢复状态时,冷启动要等页面加载完再跳转,用
AppStorage做数据中转。 -
账号、网络、
bundleName是隐形门槛,排查问题时首先查这三样。
更多推荐



所有评论(0)