什么是分布式能力
分布式能力是 HarmonyOS 与 Android/iOS 最根本的架构差异。传统移动系统中,应用只能运行在一台设备上,设备间的协作需要通过蓝牙、Wi-Fi 传文件等笨重方式完成。HarmonyOS NEXT 将多台设备抽象为一个"超级终端",让应用可以像访问本地资源一样访问周边设备的能力(屏幕、相机、键盘、扬声器……)。
分布式能力的核心包括三大方向:
- 分布式数据管理:数据在多设备间自动同步,任何设备上的修改,其他设备实时可见
- 跨设备任务迁移:在手机上打开的页面,无缝迁移到平板或电视继续操作
- 设备虚拟化:将其他设备的硬件能力(如 PC 的大屏、手表的传感器)纳入当前应用使用
软总线(SoftBus)
华为自研的分布式通信基础设施,支持 Wi-Fi、蓝牙、有线网络的透明切换。上层应用无需关心通信链路类型,软总线自动选择最优链路,并保证数据传输的安全加密。
超级终端(Super Device)
由同一华为账号下的多台 HarmonyOS 设备组成的"设备池"。设备间通过碰一碰或扫码建立可信关系,之后自动保持发现和连接。开发者在代码层面感受不到设备边界。
分布式数据服务(DDS)
Distributed Data Service,提供跨设备的键值数据库,类似多设备共享的 Redis。写入数据后,通过软总线自动同步到其他已授权的设备,延迟通常在百毫秒级别。
ContinuationManager
任务迁移管理器,用于将当前 Ability 的运行状态(包括 UI 和数据)打包发送到另一台设备,在目标设备上恢复运行,实现"流转"体验。
分布式数据管理
分布式键值数据库(KVStore)是最常用的数据同步方式,适合存储配置、简单状态等需要跨设备同步的数据:
import distributedKVStore from '@ohos.data.distributedKVStore'
class DistributedDataManager {
private kvManager?: distributedKVStore.KVManager
private kvStore?: distributedKVStore.SingleKVStore
async init(context: Context) {
// 创建 KVManager
const config: distributedKVStore.KVManagerConfig = {
bundleName: 'com.example.myapp',
context: context
}
this.kvManager = distributedKVStore.createKVManager(config)
// 获取 SingleKVStore(最简单的 KV 数据库类型)
const options: distributedKVStore.Options = {
createIfMissing: true,
encrypt: false,
backup: false,
autoSync: true, // 自动同步到其他设备
kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
securityLevel: distributedKVStore.SecurityLevel.S1
}
this.kvStore = await this.kvManager.getKVStore('shared_store', options)
console.log('分布式数据库初始化完成')
}
// 写入数据(自动同步到所有已连接设备)
async set(key: string, value: string | number | boolean) {
await this.kvStore!.put(key, value)
}
// 读取数据
async get(key: string): Promise<distributedKVStore.Value> {
return await this.kvStore!.get(key)
}
// 监听数据变化(其他设备修改后收到通知)
subscribeChanges(callback: (changes: distributedKVStore.ChangeNotification) => void) {
this.kvStore!.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, callback)
}
// 手动触发同步(当 autoSync 为 false 时使用)
async sync(deviceIds: string[]) {
this.kvStore!.sync(deviceIds, distributedKVStore.SyncMode.PULL_ONLY)
}
}
// 使用分布式数据实现多设备白板同步
@Entry
@Component
struct CollaborativeWhiteboard {
@State sharedNote: string = ''
private ddm = new DistributedDataManager()
aboutToAppear() {
this.initDistributedData()
}
async initDistributedData() {
await this.ddm.init(getContext(this))
// 加载已有数据
try {
const value = await this.ddm.get('whiteboard_content')
this.sharedNote = value.toString()
} catch (e) { // key 不存在 }
// 监听其他设备的修改
this.ddm.subscribeChanges((changes) => {
changes.updateEntries.forEach((entry) => {
if (entry.key === 'whiteboard_content') {
this.sharedNote = entry.value.value as string
}
})
})
}
build() {
Column({ space: 16 }) {
Text('协同白板(多设备实时同步)')
.fontSize(18)
.fontWeight(FontWeight.Bold)
TextArea({ text: this.sharedNote, placeholder: '输入内容,实时同步到其他设备...' })
.height(300)
.fontSize(16)
.onChange(async (value: string) => {
this.sharedNote = value
// 每次修改都同步到分布式数据库
await this.ddm.set('whiteboard_content', value)
})
}
.padding(24)
}
}
跨设备任务迁移(Flow/Continuation)
任务迁移让用户可以将手机上的任务"流转"到另一台设备继续。比如:在手机上看到一半的视频,拿起平板后自动从当前进度继续播放:
import { ContinuationManager, ContinuationResult } from '@kit.AbilityKit'
// 在 UIAbility 中实现任务迁移
export default class VideoAbility extends UIAbility {
private token: number = -1
onCreate(want: Want) {
// 注册迁移管理器
this.token = ContinuationManager.register()
}
// 迁移前:保存当前状态("打包行李")
onContinue(wantParam: Record<string, Object>): AbilityConstant.OnContinueResult {
// 从 AppStorage 读取当前播放状态
const currentTime = AppStorage.get<number>('videoCurrentTime') ?? 0
const videoId = AppStorage.get<string>('currentVideoId') ?? ''
// 将状态写入 wantParam,传递到目标设备
wantParam['videoId'] = videoId
wantParam['currentTime'] = currentTime
wantParam['version'] = '1.0'
console.log(`迁移状态:视频 ${videoId},进度 ${currentTime}ms`)
return AbilityConstant.OnContinueResult.AGREE
}
// 目标设备上:恢复状态("开箱继续")
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
const videoId = want.parameters?.['videoId'] as string
const currentTime = want.parameters?.['currentTime'] as number
// 恢复播放状态
AppStorage.setOrCreate('currentVideoId', videoId)
AppStorage.setOrCreate('videoResumeTime', currentTime)
console.log(`从迁移恢复:视频 ${videoId},从 ${currentTime}ms 开始`)
}
}
}
设备发现与连接
在发起分布式操作前,需要先发现周边可用的设备,然后让用户选择目标设备:
import deviceManager from '@ohos.distributedDeviceManager'
@Entry
@Component
struct DeviceSelector {
@State nearbyDevices: deviceManager.DeviceBasicInfo[] = []
private dmInstance?: deviceManager.DeviceManager
aboutToAppear() {
// 创建设备管理实例
this.dmInstance = deviceManager.createDeviceManager('com.example.myapp')
// 监听设备发现
this.dmInstance.on('discoverSuccess', (device) => {
// 发现新设备,添加到列表
if (!this.nearbyDevices.find(d => d.deviceId === device.deviceId)) {
this.nearbyDevices = [...this.nearbyDevices, device]
}
})
// 监听设备上线/下线
this.dmInstance.on('deviceStateChange', (state, device) => {
if (state === deviceManager.DeviceState.OFFLINE) {
this.nearbyDevices = this.nearbyDevices.filter(d => d.deviceId !== device.deviceId)
}
})
// 开始扫描周边设备
this.dmInstance.startDiscovering({})
}
aboutToDisappear() {
this.dmInstance?.stopDiscovering()
this.dmInstance?.release()
}
build() {
Column({ space: 12 }) {
Text('选择目标设备').fontSize(18).fontWeight(FontWeight.Bold)
if (this.nearbyDevices.length === 0) {
LoadingProgress().width(32).height(32)
Text('正在搜索周边设备...').fontColor('#768390')
} else {
ForEach(this.nearbyDevices, (device: deviceManager.DeviceBasicInfo) => {
Row({ space: 12 }) {
Text(this.getDeviceIcon(device.deviceType)).fontSize(24)
Column({ space: 4 }) {
Text(device.deviceName).fontSize(16).fontWeight(FontWeight.Medium)
Text(this.getDeviceTypeName(device.deviceType))
.fontSize(12).fontColor('#768390')
}.alignItems(HorizontalAlign.Start)
Blank()
Button('投送')
.backgroundColor('#CF0A2C')
.onClick(() => this.startMigration(device.deviceId))
}
.width('100%')
.padding(16)
.backgroundColor('#1c2128')
.borderRadius(10)
})
}
}
.padding(24)
}
getDeviceIcon(type: number): string {
const icons: Record<number, string> = {
[deviceManager.DeviceType.PHONE]: '📱',
[deviceManager.DeviceType.TABLET]: '📟',
[deviceManager.DeviceType.TV]: '📺',
[deviceManager.DeviceType.PC]: '💻',
[deviceManager.DeviceType.SMART_WATCH]: '⌚',
}
return icons[type] ?? '📡'
}
getDeviceTypeName(type: number): string {
const names: Record<number, string> = {
[deviceManager.DeviceType.PHONE]: '手机',
[deviceManager.DeviceType.TABLET]: '平板',
[deviceManager.DeviceType.TV]: '智慧屏',
[deviceManager.DeviceType.PC]: '电脑',
[deviceManager.DeviceType.SMART_WATCH]: '手表',
}
return names[type] ?? '未知设备'
}
async startMigration(targetDeviceId: string) {
// 通过 Want 启动目标设备上的 Ability
const want: Want = {
deviceId: targetDeviceId,
bundleName: 'com.example.myapp',
abilityName: 'VideoAbility',
parameters: {
'videoId': AppStorage.get('currentVideoId'),
'currentTime': AppStorage.get('videoCurrentTime')
}
}
await getContext(this).startAbility(want)
}
}
分布式调试技巧
开发分布式功能时,需要两台真机(手机 + 手机/平板),且必须登录同一华为账号,并已建立超级终端关系(碰一碰或设置中手动添加)。模拟器目前不支持分布式功能。调试时可以用两台手机同时连接 DevEco Studio(通过无线调试),在两台设备上分别设置断点进行联调。