鸿蒙分布式能力简介

56 阅读5分钟

基于HarmonyOS分布式技术,实现多设备协同、数据共享和任务流转

一、分布式能力概述

本指南涵盖了HarmonyOS分布式能力的核心功能:

  1. ✅ 分布式键值/关系型数据库
  2. ✅ 跨设备应用接续和迁移
  3. ✅ 分布式剪贴板
  4. ✅ 分布式文件系统
  5. ✅ 完整的多设备笔记同步应用
  6. ✅ 数据同步和冲突解决策略

1.1 什么是分布式能力

HarmonyOS的分布式能力允许多个设备作为一个"超级终端"协同工作,提供:

  • 跨设备应用接续:应用在设备间无缝迁移
  • 跨设备数据共享:数据在设备间实时同步
  • 跨设备任务协同:任务在多设备间分布执行

1.2 核心技术

技术功能应用场景
分布式数据管理跨设备数据同步备忘录、通讯录同步
分布式任务调度任务跨设备迁移视频接续播放
分布式文件系统文件跨设备访问文档编辑协同
分布式剪贴板剪贴内容共享复制粘贴跨设备

二、分布式数据管理

2.1 分布式键值数据库

import distributedKVStore from '@ohos.data.distributedKVStore'

class DistributedKVManager {
  private kvManager: distributedKVStore.KVManager | null = null
  private kvStore: distributedKVStore.SingleKVStore | null = null

  // 初始化KV管理器
  async init(context: Context): Promise<void> {
    const config: distributedKVStore.KVManagerConfig = {
      bundleName: context.applicationInfo.name,
      context: context
    }

    this.kvManager = distributedKVStore.createKVManager(config)
  }

  // 创建分布式KV存储
  async createStore(storeId: string): Promise<void> {
    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(storeId, options)
  }

  // 存储数据
  async put(key: string, value: string): Promise<void> {
    await this.kvStore!.put(key, value)
  }

  // 获取数据
  async get(key: string): Promise<string> {
    return await this.kvStore!.get(key) as string
  }

  // 删除数据
  async delete(key: string): Promise<void> {
    await this.kvStore!.delete(key)
  }

  // 订阅数据变化
  subscribeDataChange(callback: (data: distributedKVStore.ChangeNotification) => void): void {
    this.kvStore!.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, callback)
  }
}

// 使用示例
@Entry
@Component
struct DistributedKVExample {
  private kvManager: DistributedKVManager = new DistributedKVManager()
  @State syncData: string = ''

  async aboutToAppear() {
    await this.kvManager.init(getContext(this))
    await this.kvManager.createStore('myStore')

    // 订阅数据变化
    this.kvManager.subscribeDataChange((data) => {
      console.info('Data changed:', JSON.stringify(data))
      this.loadData()
    })

    await this.loadData()
  }

  async loadData() {
    try {
      this.syncData = await this.kvManager.get('sharedKey')
    } catch (e) {
      console.error('Load data failed:', e)
    }
  }

  build() {
    Column({ space: 20 }) {
      Text(`同步数据: ${this.syncData}`)
        .fontSize(18)

      TextInput({ placeholder: '输入数据' })
        .onChange(async (value: string) => {
          await this.kvManager.put('sharedKey', value)
        })

      Text('此数据会自动同步到其他设备')
        .fontSize(14)
        .fontColor(Color.Grey)
    }
    .padding(20)
    .width('100%')
  }
}

2.2 分布式关系型数据库

import relationalStore from '@ohos.data.relationalStore'

const STORE_CONFIG: relationalStore.StoreConfig = {
  name: 'DistributedRDB.db',
  securityLevel: relationalStore.SecurityLevel.S1,
  distributed: true  // 启用分布式
}

class DistributedRDBManager {
  private store: relationalStore.RdbStore | null = null

  // 创建分布式RDB
  async createStore(context: Context): Promise<void> {
    this.store = await relationalStore.getRdbStore(context, STORE_CONFIG)

    // 创建表
    await this.store.executeSql(
      'CREATE TABLE IF NOT EXISTS NOTES (id INTEGER PRIMARY KEY, title TEXT, content TEXT, updateTime INTEGER)'
    )

    // 设置分布式表
    await this.store.setDistributedTables(['NOTES'])
  }

  // 插入数据
  async insertNote(title: string, content: string): Promise<number> {
    const valueBucket: relationalStore.ValuesBucket = {
      title: title,
      content: content,
      updateTime: Date.now()
    }
    return await this.store!.insert('NOTES', valueBucket)
  }

  // 查询数据
  async queryNotes(): Promise<Array<any>> {
    const predicates = new relationalStore.RdbPredicates('NOTES')
    predicates.orderByDesc('updateTime')

    const resultSet = await this.store!.query(predicates)
    const notes: Array<any> = []

    while (resultSet.goToNextRow()) {
      notes.push({
        id: resultSet.getLong(resultSet.getColumnIndex('id')),
        title: resultSet.getString(resultSet.getColumnIndex('title')),
        content: resultSet.getString(resultSet.getColumnIndex('content')),
        updateTime: resultSet.getLong(resultSet.getColumnIndex('updateTime'))
      })
    }

    resultSet.close()
    return notes
  }

  // 更新数据
  async updateNote(id: number, title: string, content: string): Promise<void> {
    const valueBucket: relationalStore.ValuesBucket = {
      title: title,
      content: content,
      updateTime: Date.now()
    }

    const predicates = new relationalStore.RdbPredicates('NOTES')
    predicates.equalTo('id', id)

    await this.store!.update(valueBucket, predicates)
  }

  // 删除数据
  async deleteNote(id: number): Promise<void> {
    const predicates = new relationalStore.RdbPredicates('NOTES')
    predicates.equalTo('id', id)
    await this.store!.delete(predicates)
  }
}

三、跨设备应用接续

3.1 应用迁移

import UIAbility from '@ohos.app.ability.UIAbility'
import AbilityConstant from '@ohos.app.ability.AbilityConstant'
import distributedMissionManager from '@ohos.distributedMissionManager'

export default class MainAbility extends UIAbility {
  // 应用即将迁移到其他设备
  onContinue(wantParam: Record<string, Object>): AbilityConstant.OnContinueResult {
    console.info('onContinue called')

    // 保存需要迁移的数据
    wantParam['continueData'] = {
      videoUrl: 'https://example.com/video.mp4',
      currentPosition: 120,  // 当前播放位置(秒)
      volume: 50
    }

    // 返回同意迁移
    return AbilityConstant.OnContinueResult.AGREE
  }

  // 应用从其他设备迁移过来
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      // 恢复迁移的数据
      const continueData = want.parameters?.continueData as Record<string, any>

      if (continueData) {
        console.info('Restore data:', JSON.stringify(continueData))
        // 恢复播放状态
        // this.restoreVideoState(continueData)
      }
    }
  }
}

3.2 迁移触发

import UIAbility from '@ohos.app.ability.UIAbility'
import distributedMissionManager from '@ohos.distributedMissionManager'

@Entry
@Component
struct MigrationExample {
  @State deviceList: Array<string> = []

  // 获取可用设备列表
  async getDeviceList() {
    try {
      // 获取在线设备
      const devices = await distributedMissionManager.getRemoteDeviceList()
      this.deviceList = devices.map(device => device.deviceId)
    } catch (e) {
      console.error('Get devices failed:', e)
    }
  }

  // 触发迁移
  async startMigration(targetDeviceId: string) {
    try {
      await distributedMissionManager.continueMission({
        srcDeviceId: '',  // 空表示本设备
        dstDeviceId: targetDeviceId,
        bundleName: 'com.example.myapp',
        wantParam: {}
      })
      console.info('Migration started')
    } catch (e) {
      console.error('Migration failed:', e)
    }
  }

  build() {
    Column({ space: 15 }) {
      Text('选择目标设备').fontSize(20)

      ForEach(this.deviceList, (deviceId: string) => {
        Button(`迁移到设备 ${deviceId.substring(0, 8)}...`)
          .width('100%')
          .onClick(() => {
            this.startMigration(deviceId)
          })
      })

      Button('刷新设备列表')
        .width('100%')
        .onClick(() => {
          this.getDeviceList()
        })
    }
    .padding(20)
    .width('100%')
  }
}

四、分布式剪贴板

4.1 跨设备复制粘贴

import pasteboard from '@ohos.pasteboard'

class DistributedClipboard {
  private systemPasteboard: pasteboard.SystemPasteboard | null = null

  constructor() {
    this.systemPasteboard = pasteboard.getSystemPasteboard()
  }

  // 复制文本(支持跨设备)
  async copyText(text: string): Promise<void> {
    const pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text)

    // 设置为分布式剪贴板(自动同步到其他设备)
    pasteData.setProperty({
      shareOption: pasteboard.ShareOption.CROSS_DEVICE  // 跨设备共享
    })

    await this.systemPasteboard!.setData(pasteData)
    console.info('Text copied to distributed clipboard')
  }

  // 粘贴文本
  async pasteText(): Promise<string> {
    const pasteData = await this.systemPasteboard!.getData()
    return pasteData.getPrimaryText()
  }

  // 监听剪贴板变化
  subscribeChange(callback: () => void): void {
    this.systemPasteboard!.on('update', callback)
  }

  // 取消监听
  unsubscribeChange(): void {
    this.systemPasteboard!.off('update')
  }
}

// 使用示例
@Entry
@Component
struct ClipboardExample {
  private clipboard: DistributedClipboard = new DistributedClipboard()
  @State pastedText: string = ''

  aboutToAppear() {
    // 监听剪贴板变化
    this.clipboard.subscribeChange(async () => {
      this.pastedText = await this.clipboard.pasteText()
      console.info('Clipboard updated:', this.pastedText)
    })
  }

  build() {
    Column({ space: 20 }) {
      TextInput({ placeholder: '输入要复制的文本' })
        .onChange(async (value: string) => {
          await this.clipboard.copyText(value)
        })

      Text('粘贴的内容(跨设备)')
        .fontSize(16)
        .fontWeight(FontWeight.Bold)

      Text(this.pastedText)
        .width('100%')
        .padding(15)
        .backgroundColor(Color.Pink)
        .borderRadius(8)

      Button('粘贴')
        .onClick(async () => {
          this.pastedText = await this.clipboard.pasteText()
        })

      Text('在其他设备复制文本,这里会自动显示')
        .fontSize(14)
        .fontColor(Color.Grey)
    }
    .padding(20)
    .width('100%')
  }
}

五、分布式文件系统

5.1 跨设备文件访问

import fileShare from '@ohos.fileShare'
import fs from '@ohos.file.fs'

class DistributedFileSystem {
  // 创建分布式文件
  async createDistributedFile(fileName: string, content: string): Promise<string> {
    const context = getContext(this)
    const filesDir = context.filesDir

    // 创建文件
    const filePath = `${filesDir}/${fileName}`
    const file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
    fs.writeSync(file.fd, content)
    fs.closeSync(file)

    // 将文件设置为分布式文件
    const uris = await fileShare.grantUriPermission(filePath, 'com.example.targetapp')

    return filePath
  }

  // 读取文件
  async readFile(filePath: string): Promise<string> {
    const file = fs.openSync(filePath, fs.OpenMode.READ_ONLY)
    const buffer = new ArrayBuffer(4096)
    const readLen = fs.readSync(file.fd, buffer)
    fs.closeSync(file)

    const decoder = new util.TextDecoder('utf-8')
    return decoder.decode(new Uint8Array(buffer, 0, readLen))
  }

  // 列出分布式文件
  async listDistributedFiles(): Promise<Array<string>> {
    const context = getContext(this)
    const filesDir = context.filesDir

    return fs.listFileSync(filesDir)
  }
}

六、实战案例:多设备笔记同步应用

import distributedKVStore from '@ohos.data.distributedKVStore'

@Observed
class Note {
  id: string
  title: string
  content: string
  updateTime: number

  constructor(title: string, content: string) {
    this.id = Date.now().toString()
    this.title = title
    this.content = content
    this.updateTime = Date.now()
  }
}

class DistributedNoteManager {
  private kvStore: distributedKVStore.SingleKVStore | null = null
  private changeCallback: ((notes: Note[]) => void) | null = null

  async init(context: Context): Promise<void> {
    const kvManager = distributedKVStore.createKVManager({
      bundleName: context.applicationInfo.name,
      context: context
    })

    const options: distributedKVStore.Options = {
      createIfMissing: true,
      encrypt: false,
      backup: false,
      autoSync: true,
      kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
      securityLevel: distributedKVStore.SecurityLevel.S1
    }

    this.kvStore = await kvManager.getKVStore('NoteStore', options)

    // 订阅数据变化
    this.kvStore.on('dataChange', distributedKVStore.SubscribeType.SUBSCRIBE_TYPE_ALL, () => {
      this.notifyChange()
    })
  }

  async saveNote(note: Note): Promise<void> {
    await this.kvStore!.put(note.id, JSON.stringify(note))
  }

  async loadNotes(): Promise<Note[]> {
    const entries = await this.kvStore!.getEntries('')
    return entries.map(entry => JSON.parse(entry.value.value as string) as Note)
      .sort((a, b) => b.updateTime - a.updateTime)
  }

  async deleteNote(id: string): Promise<void> {
    await this.kvStore!.delete(id)
  }

  onDataChange(callback: (notes: Note[]) => void) {
    this.changeCallback = callback
  }

  private async notifyChange() {
    if (this.changeCallback) {
      const notes = await this.loadNotes()
      this.changeCallback(notes)
    }
  }
}

@Entry
@Component
struct DistributedNoteApp {
  private noteManager: DistributedNoteManager = new DistributedNoteManager()
  @State notes: Note[] = []
  @State showAddDialog: boolean = false
  @State newTitle: string = ''
  @State newContent: string = ''

  async aboutToAppear() {
    await this.noteManager.init(getContext(this))
    this.notes = await this.noteManager.loadNotes()

    this.noteManager.onDataChange((notes) => {
      this.notes = notes
    })
  }

  @Builder AddNoteDialog() {
    Column({ space: 20 }) {
      Text('新建笔记')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      TextInput({ placeholder: '标题' })
        .onChange((value) => {
          this.newTitle = value
        })

      TextArea({ placeholder: '内容' })
        .height(200)
        .onChange((value) => {
          this.newContent = value
        })

      Row({ space: 15 }) {
        Button('取消')
          .onClick(() => {
            this.showAddDialog = false
          })

        Button('保存')
          .onClick(async () => {
            if (this.newTitle.trim()) {
              const note = new Note(this.newTitle, this.newContent)
              await this.noteManager.saveNote(note)
              this.notes = await this.noteManager.loadNotes()

              this.newTitle = ''
              this.newContent = ''
              this.showAddDialog = false
            }
          })
      }
    }
    .padding(20)
    .backgroundColor(Color.White)
    .borderRadius(16)
  }

  build() {
    Column() {
      // 标题栏
      Row() {
        Text('分布式笔记')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .layoutWeight(1)

        Button('+')
          .fontSize(24)
          .onClick(() => {
            this.showAddDialog = true
          })
      }
      .width('100%')
      .padding(15)

      // 笔记列表
      List({ space: 10 }) {
        ForEach(this.notes, (note: Note) => {
          ListItem() {
            Column({ space: 8 }) {
              Row() {
                Text(note.title)
                  .fontSize(18)
                  .fontWeight(FontWeight.Bold)
                  .layoutWeight(1)

                Button('删除')
                  .fontSize(14)
                  .onClick(async () => {
                    await this.noteManager.deleteNote(note.id)
                    this.notes = await this.noteManager.loadNotes()
                  })
              }
              .width('100%')

              Text(note.content)
                .fontSize(14)
                .maxLines(3)
                .textOverflow({ overflow: TextOverflow.Ellipsis })

              Text(new Date(note.updateTime).toLocaleString())
                .fontSize(12)
                .fontColor(Color.Grey)
            }
            .width('100%')
            .padding(15)
            .backgroundColor(Color.White)
            .borderRadius(8)
          }
        })
      }
      .layoutWeight(1)
      .padding({ left: 15, right: 15 })

      Text('笔记会自动同步到所有设备')
        .fontSize(14)
        .fontColor(Color.Grey)
        .margin(15)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
    .bindSheet(this.showAddDialog, this.AddNoteDialog(), {
      height: 500
    })
  }
}

七、开发最佳实践

7.1 数据同步策略

// 增量同步而非全量同步
class IncrementalSync {
  private lastSyncTime: number = 0

  async syncData(kvStore: distributedKVStore.SingleKVStore): Promise<void> {
    // 只同步上次同步之后的数据
    const entries = await kvStore.getEntries('')

    const updatedEntries = entries.filter(entry => {
      const data = JSON.parse(entry.value.value as string)
      return data.updateTime > this.lastSyncTime
    })

    // 处理增量数据
    console.info(`Syncing ${updatedEntries.length} updated items`)

    this.lastSyncTime = Date.now()
  }
}

7.2 冲突解决

// 基于时间戳的冲突解决
class ConflictResolver {
  resolveConflict(local: any, remote: any): any {
    // 保留最新的数据
    return local.updateTime > remote.updateTime ? local : remote
  }
}

7.3 错误处理

async function safeDistributedOperation<T>(
  operation: () => Promise<T>,
  fallback: T
): Promise<T> {
  try {
    return await operation()
  } catch (error) {
    console.error('Distributed operation failed:', error)
    // 降级到本地模式
    return fallback
  }
}

八、参考资源


分布式能力让多设备协同成为可能,为用户带来流畅的跨设备体验。