分布式能力
跨设备协同与迁移
概述
分布式能力是 HarmonyOS 的核心特性之一,它允许应用在多个设备之间协同工作。通过分布式任务迁移、分布式数据同步和分布式文件系统,用户可以在手机上开始一项任务,无缝切换到平板或电脑上继续完成。这种”1+8+N”的全场景体验是 HarmonyOS 区别于其他操作系统的关键优势。
为什么需要分布式能力?想象一下,你在手机上编辑文档,回到家后想在平板上继续编辑。传统方式需要手动传输文件或依赖云同步,而 HarmonyOS 的分布式能力让这个过程完全无缝:应用状态自动迁移,数据自动同步,用户几乎感知不到设备切换。
基础概念
分布式任务迁移:将正在运行的任务(Ability)从一台设备迁移到另一台设备。迁移时,应用的状态和数据会被打包传递,目标设备上的应用从断点处继续运行。
分布式数据同步:通过分布式数据服务,多个设备上的数据可以自动同步。当一台设备上的数据发生变化时,其他设备会收到通知并更新。
分布式文件系统:多台设备上的文件可以互相访问。用户在手机上保存的文件,可以直接在平板上打开,无需手动传输。
设备发现与连接:通过 DeviceManager 发现局域网内的其他 HarmonyOS 设备,并建立连接。
Continuation:任务迁移的具体实现机制,包括 SaveData(保存数据)和 RestoreData(恢复数据)两个阶段。
快速上手
设备发现
import deviceManager from '@ohos.distributedDeviceManager'
@Entry
@Component
struct DeviceDiscoveryDemo {
@State devices: string[] = []
async discoverDevices() {
try {
// 创建设备管理器
const dmInstance = deviceManager.createDeviceManager('com.example.myapp')
// 发现设备
dmInstance.on('deviceFound', (data) => {
// 发现新设备
const deviceName = data.device.deviceName
const deviceId = data.device.deviceId
this.devices = [...this.devices, `${deviceName} (${deviceId})`]
})
// 开始发现
dmInstance.startDiscovering()
// 30 秒后停止发现
setTimeout(() => {
dmInstance.stopDiscovering()
}, 30000)
} catch (error) {
console.error(`设备发现失败: ${error}`)
}
}
build() {
Column() {
Text('设备发现').fontSize(20).fontWeight(FontWeight.Bold)
Button('搜索设备').onClick(() => this.discoverDevices())
List() {
ForEach(this.devices, (device: string) => {
ListItem() {
Text(device).fontSize(16).padding(12)
}
})
}
}
.padding(16)
}
}
详细用法
任务迁移
实现任务迁移需要在 Ability 中处理保存和恢复逻辑:
// EntryAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
// 保存数据:迁移前调用
onContinue(wantParam: Record<string, Object>): AbilityConstant.OnContinueResult {
// 保存应用状态到 wantParam
wantParam['currentTab'] = '2';
wantParam['scrollPosition'] = '150';
wantParam['draftText'] = '正在编辑的内容...';
console.info('数据已保存,准备迁移');
return AbilityConstant.OnContinueResult.AGREE_OK;
}
// 恢复数据:目标设备上调用
onCreate(want, launchParam) {
if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
// 从 want 中恢复数据
const currentTab = want.parameters?.['currentTab'];
const scrollPosition = want.parameters?.['scrollPosition'];
const draftText = want.parameters?.['draftText'];
console.info(`恢复数据: tab=${currentTab}, scroll=${scrollPosition}`);
}
}
onWindowStageCreate(windowStage: window.WindowStage) {
windowStage.loadContent('pages/Index');
}
}
在页面中触发迁移:
import continuationManager from '@ohos.app.ability.continuationManager'
import deviceManager from '@ohos.distributedDeviceManager'
@Entry
@Component
struct MigrationDemo {
@State currentTab: string = '0'
@State draftText: string = ''
// 发起迁移
async migrateToDevice() {
try {
// 注册迁移管理器
const token = continuationManager.register()
// 显示设备选择器
continuationManager.on('deviceSelected', (data) => {
// 用户选择了目标设备
const deviceId = data.deviceId
console.info(`迁移到设备: ${deviceId}`)
})
continuationManager.on('deviceUnselected', (data) => {
console.info('用户取消了设备选择')
})
} catch (error) {
console.error(`迁移失败: ${error}`)
}
}
build() {
Column() {
Text('分布式任务迁移').fontSize(20).fontWeight(FontWeight.Bold)
Text(`当前标签: ${this.currentTab}`)
TextInput({ text: this.draftText, placeholder: '输入内容' })
.onChange((value) => { this.draftText = value })
Button('迁移到其他设备').onClick(() => this.migrateToDevice())
}
.padding(16)
}
}
分布式数据同步
import distributedKVStore from '@ohos.data.distributedKVStore';
// 创建分布式 KV 存储
class DistributedDataSync {
private kvStore: distributedKVStore.SingleKVStore | null = null;
async init() {
try {
const kvManager = distributedKVStore.createKVManager({
bundleName: 'com.example.myapp',
});
// 创建或打开 KV 存储
this.kvStore = await kvManager.getKVStore('syncData', {
createIfMissing: true,
encrypt: false,
backup: false,
autoSync: true, // 自动同步
kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
securityLevel: distributedKVStore.SecurityLevel.S1,
});
// 监听数据变化
this.kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => {
console.info('数据已同步更新');
data.updateEntries.forEach((entry) => {
console.info(`更新: ${entry.key} = ${entry.value.value}`);
});
});
} catch (error) {
console.error(`初始化分布式存储失败: ${error}`);
}
}
// 写入数据(会自动同步到其他设备)
async put(key: string, value: string) {
await this.kvStore?.put(key, value);
}
// 读取数据
async get(key: string): Promise<string> {
const entry = await this.kvStore?.get(key);
return entry?.value ?? '';
}
// 删除数据
async delete(key: string) {
await this.kvStore?.delete(key);
}
}
分布式文件访问
import fileio from '@ohos.fileio';
import distributedFS from '@ohos.file.distributedFS';
// 在分布式文件系统中创建和访问文件
async function distributedFileDemo() {
try {
// 获取分布式文件路径
const context = getContext(this);
const distributedDir = context.distributedFilesDir;
// 在分布式目录中创建文件
const filePath = `${distributedDir}/shared_note.txt`;
const file = fileio.openSync(filePath, 0o102 | 0o2); // 创建并读写
fileio.writeSync(file.fd, '这是跨设备共享的笔记内容');
fileio.closeSync(file);
console.info(`文件已创建: ${filePath}`);
// 其他设备可以通过相同的路径访问此文件
} catch (error) {
console.error(`分布式文件操作失败: ${error}`);
}
}
常见场景
跨设备笔记应用
import distributedKVStore from '@ohos.data.distributedKVStore'
@Entry
@Component
struct DistributedNoteDemo {
@State notes: Note[] = []
private kvStore: distributedKVStore.SingleKVStore | null = null
async aboutToAppear() {
// 初始化分布式存储
await this.initKVStore()
// 加载已有笔记
await this.loadNotes()
}
async initKVStore() {
const kvManager = distributedKVStore.createKVManager({
bundleName: 'com.example.notes'
})
this.kvStore = await kvManager.getKVStore('notes', {
createIfMissing: true,
autoSync: true,
kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
securityLevel: distributedKVStore.SecurityLevel.S1
})
// 监听其他设备的同步更新
this.kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, () => {
this.loadNotes() // 数据变化时重新加载
})
}
async loadNotes() {
// 从分布式存储中加载笔记
const entries = await this.kvStore?.getEntries('note_')
this.notes = entries?.map(entry => JSON.parse(entry.value.value as string)) ?? []
}
async addNote(title: string, content: string) {
const note: Note = {
id: Date.now().toString(),
title,
content,
updatedAt: new Date().toISOString()
}
// 保存到分布式存储,自动同步到其他设备
await this.kvStore?.put(`note_${note.id}`, JSON.stringify(note))
await this.loadNotes()
}
build() {
Column() {
Text('跨设备笔记').fontSize(20).fontWeight(FontWeight.Bold)
List() {
ForEach(this.notes, (note: Note) => {
ListItem() {
Column() {
Text(note.title).fontSize(16).fontWeight(FontWeight.Bold)
Text(note.content).fontSize(14).maxLines(2)
Text(note.updatedAt).fontSize(12).fontColor('#999999')
}
.padding(12)
}
})
}
}
.padding(16)
}
}
interface Note {
id: string
title: string
content: string
updatedAt: string
}
注意事项
同一账号:分布式能力要求设备登录同一个华为账号,且在同一局域网下。
应用签名:使用分布式能力的应用需要使用发布签名,调试签名可能无法正常工作。
网络环境:分布式功能依赖局域网,网络不稳定可能导致同步延迟或失败。
数据冲突:当多台设备同时修改同一数据时,可能产生冲突。分布式 KV 存储使用”最后写入胜出”策略,后写入的值会覆盖先前的值。
隐私与安全:迁移的数据可能包含敏感信息,确保只迁移必要的数据,并在传输过程中加密。
进阶用法
自定义迁移策略
// 在 Ability 中自定义迁移行为
export default class EntryAbility extends UIAbility {
onContinue(wantParam: Record<string, Object>): AbilityConstant.OnContinueResult {
// 检查是否可以迁移
const isReady = this.checkMigrationReadiness();
if (!isReady) {
return AbilityConstant.OnContinueResult.MISMATCH;
}
// 只迁移必要的数据
wantParam['essentialData'] = JSON.stringify({
userId: '123',
currentPage: 'home',
});
return AbilityConstant.OnContinueResult.AGREE_OK;
}
private checkMigrationReadiness(): boolean {
// 检查是否有未保存的数据
// 检查网络是否可用
return true;
}
}
设备能力查询
import deviceInfo from '@ohos.deviceInfo';
// 查询设备类型和能力
function getDeviceCapability() {
const deviceType = deviceInfo.deviceType; // phone, tablet, tv 等
const screenDensity = deviceInfo.screenDensity;
console.info(`设备类型: ${deviceType}`);
console.info(`屏幕密度: ${screenDensity}`);
// 根据设备能力调整 UI 和功能
if (deviceType === 'phone') {
// 手机端:简化界面
} else if (deviceType === 'tablet') {
// 平板端:展示更多内容
}
}