前置知识: HarmonyOS

分布式能力

3 minAdvanced2026/6/14

跨设备协同与迁移

概述

分布式能力是 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') {
    // 平板端:展示更多内容
  }
}