Harmony学习之分布式能力入门

Harmony学习之分布式能力入门

一、场景引入

小明正在开发一个智能家居控制应用,他希望用户能在手机上控制客厅的智能灯,同时将音乐从手机流转到智能音箱播放。传统开发需要分别处理设备发现、连接建立、数据同步等复杂逻辑,而HarmonyOS的分布式能力让这些变得简单。

二、核心概念

1. 分布式架构概览

HarmonyOS的分布式能力基于分布式软总线技术,将多个物理设备虚拟化为一个"超级终端"。核心组件包括:

  • 分布式软总线:设备间的通信基座,提供自动发现、连接建立和数据传输能力
  • 分布式数据管理:实现跨设备数据同步,支持键值对和关系型数据库
  • 分布式任务调度:智能分配任务到最适合的设备执行
  • 分布式设备虚拟化:将多设备硬件资源抽象为统一的能力池

2. 分布式软总线工作原理

分布式软总线采用分层架构设计:

  • 物理传输层:支持Wi-Fi、蓝牙、NFC等多种连接方式
  • 设备发现与连接层:基于mDNS协议实现设备自动发现
  • 核心通信机制:支持点对点通信、发布订阅、请求响应等多种模式

设备间通信延迟可控制在10ms以内,吞吐量可达100MB/s以上,支持1000+设备同时连接。

三、关键实现

1. 设备发现与连接

使用DeviceManager发现附近设备:

// entry/src/main/ets/pages/DeviceDiscoveryPage.ets
import deviceManager from '@ohos.distributedHardware.deviceManager';
import common from '@ohos.app.ability.common';

@Component
struct DeviceDiscoveryPage {
  @State deviceList: deviceManager.DeviceInfo[] = [];
  private deviceManager: deviceManager.DeviceManager | null = null;

  // 初始化设备管理
  async initDeviceManager() {
    try {
      this.deviceManager = deviceManager.createDeviceManager('com.example.app');
      
      // 监听设备状态变化
      this.deviceManager.on('deviceStateChange', (data) => {
        console.log('设备状态变化:', data);
        this.updateDeviceList();
      });
      
      // 开始设备发现
      this.startDeviceDiscovery();
    } catch (error) {
      console.error('设备管理初始化失败:', error);
    }
  }

  // 启动设备发现
  async startDeviceDiscovery() {
    if (!this.deviceManager) {
      return;
    }

    const subscribeInfo = {
      subscribeId: 'discovery_subscribe',
      mode: deviceManager.DiscoverMode.DISCOVER_MODE_ACTIVE,
      medium: deviceManager.ExchangeMedium.COMMON,
      freq: deviceManager.ExchangeFreq.LOW,
      isSameAccount: true, // 仅发现同账号设备
      isWakeRemote: false
    };

    await this.deviceManager.startDeviceDiscovery(subscribeInfo);
    this.updateDeviceList();
  }

  // 更新设备列表
  async updateDeviceList() {
    if (!this.deviceManager) {
      return;
    }

    const devices = await this.deviceManager.getTrustedDeviceListSync();
    this.deviceList = devices;
  }

  // 连接到指定设备
  async connectToDevice(deviceId: string) {
    try {
      const device = this.deviceList.find(d => d.deviceId === deviceId);
      if (device) {
        console.log('连接到设备:', device.deviceName);
        // 这里可以执行跨设备操作
      }
    } catch (error) {
      console.error('连接设备失败:', error);
    }
  }

  build() {
    Column() {
      Button('发现设备')
        .onClick(() => this.startDeviceDiscovery())
        .margin(10)
      
      if (this.deviceList.length > 0) {
        List() {
          ForEach(this.deviceList, (item: deviceManager.DeviceInfo) => {
            ListItem() {
              Column() {
                Text(item.deviceName)
                  .fontSize(16)
                Text(`设备ID: ${item.deviceId}`)
                  .fontSize(12)
                  .fontColor(Color.Gray)
              }
              .padding(10)
            }
            .onClick(() => this.connectToDevice(item.deviceId))
          })
        }
        .height(300)
      }
    }
    .onAppear(() => this.initDeviceManager())
  }
}

2. 跨设备启动应用

使用分布式能力启动远程设备上的应用:

// entry/src/main/ets/pages/RemoteStartPage.ets
import featureAbility from '@ohos.ability.featureAbility';
import common from '@ohos.app.ability.common';

@Component
struct RemoteStartPage {
  @State targetDeviceId: string = '';

  // 跨设备启动Ability
  async startRemoteAbility() {
    if (!this.targetDeviceId) {
      console.error('请先选择目标设备');
      return;
    }

    try {
      const intent = {
        deviceId: this.targetDeviceId,
        bundleName: 'com.example.remoteapp',
        abilityName: 'MainAbility',
        parameters: {
          message: 'Hello from another device',
          timestamp: Date.now()
        }
      };

      await featureAbility.startAbility(intent);
      console.log('远程应用启动成功');
    } catch (error) {
      console.error('启动远程应用失败:', error);
    }
  }

  build() {
    Column() {
      TextInput({ placeholder: '输入目标设备ID' })
        .onChange((value) => this.targetDeviceId = value)
        .width('80%')
        .margin(10)
      
      Button('启动远程应用')
        .onClick(() => this.startRemoteAbility())
        .width('80%')
        .height(50)
        .margin(10)
    }
  }
}

3. 分布式数据同步

使用分布式数据对象实现跨设备数据同步:

// entry/src/main/ets/pages/DataSyncPage.ets
import distributedData from '@ohos.data.distributedData';
import common from '@ohos.app.ability.common';

@Component
struct DataSyncPage {
  @State message: string = '';
  @State receivedMessages: string[] = [];
  private dataObject: distributedData.DataObject | null = null;

  // 初始化分布式数据对象
  async initDataObject() {
    try {
      const context = getContext(this) as common.UIAbilityContext;
      
      // 创建分布式数据对象
      this.dataObject = distributedData.createDataObject({
        bundleName: context.abilityInfo.bundleName,
        objectName: 'chatMessage',
        initialValue: {
          messages: []
        }
      });

      // 监听数据变化
      this.dataObject.on('dataChange', (newValue) => {
        console.log('数据变化:', newValue);
        this.receivedMessages = newValue.messages || [];
      });
    } catch (error) {
      console.error('初始化数据对象失败:', error);
    }
  }

  // 发送消息
  async sendMessage() {
    if (!this.message.trim() || !this.dataObject) {
      return;
    }

    try {
      await this.dataObject.update((oldValue) => {
        const messages = oldValue.messages || [];
        return {
          messages: [...messages, {
            content: this.message,
            timestamp: Date.now(),
            sender: '当前设备'
          }]
        };
      });

      this.message = '';
    } catch (error) {
      console.error('发送消息失败:', error);
    }
  }

  build() {
    Column() {
      // 消息输入区
      Row() {
        TextInput({ placeholder: '输入消息...', text: this.message })
          .onChange((value) => this.message = value)
          .width('70%')
          .height(40)
          .margin(5)
        
        Button('发送')
          .onClick(() => this.sendMessage())
          .width('25%')
          .height(40)
          .margin(5)
      }
      .padding(10)

      // 消息列表
      List() {
        ForEach(this.receivedMessages, (item, index) => {
          ListItem() {
            Column() {
              Text(item.content)
                .fontSize(16)
              Text(`来自: ${item.sender}, 时间: ${new Date(item.timestamp).toLocaleTimeString()}`)
                .fontSize(12)
                .fontColor(Color.Gray)
            }
            .padding(10)
            .width('100%')
          }
        })
      }
      .height(400)
    }
    .onAppear(() => this.initDataObject())
  }
}

4. 权限配置

在module.json5中配置分布式权限:

// entry/src/main/module.json5
{
  "module": {
    "name": "entry",
    "type": "entry",
    "requestPermissions": [
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC",
        "reason": "用于跨设备数据同步",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO",
        "reason": "用于获取分布式设备信息",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ],
    "distributedCapabilities": [
      {
        "name": "com.example.app.distributed",
        "description": "分布式能力配置"
      }
    ]
  }
}

四、实战案例:跨设备音乐控制

下面实现一个完整的跨设备音乐控制应用:

// entry/src/main/ets/pages/MusicControlPage.ets
import distributedData from '@ohos.data.distributedData';
import deviceManager from '@ohos.distributedHardware.deviceManager';
import common from '@ohos.app.ability.common';

interface MusicState {
  isPlaying: boolean;
  currentTrack: string;
  progress: number;
  duration: number;
}

@Component
struct MusicControlPage {
  @State musicState: MusicState = {
    isPlaying: false,
    currentTrack: '未知歌曲',
    progress: 0,
    duration: 0
  };
  @State deviceList: deviceManager.DeviceInfo[] = [];
  @State selectedDeviceId: string = '';
  private dataObject: distributedData.DataObject | null = null;
  private deviceManager: deviceManager.DeviceManager | null = null;

  // 初始化
  async onInit() {
    await this.initDeviceManager();
    await this.initDataObject();
  }

  // 初始化设备管理
  async initDeviceManager() {
    try {
      this.deviceManager = deviceManager.createDeviceManager('com.example.music');
      
      this.deviceManager.on('deviceStateChange', () => {
        this.updateDeviceList();
      });
      
      await this.startDeviceDiscovery();
    } catch (error) {
      console.error('设备管理初始化失败:', error);
    }
  }

  // 初始化数据对象
  async initDataObject() {
    try {
      const context = getContext(this) as common.UIAbilityContext;
      
      this.dataObject = distributedData.createDataObject({
        bundleName: context.abilityInfo.bundleName,
        objectName: 'musicControl',
        initialValue: {
          musicState: this.musicState
        }
      });

      // 监听音乐状态变化
      this.dataObject.on('dataChange', (newValue) => {
        this.musicState = newValue.musicState || this.musicState;
      });
    } catch (error) {
      console.error('初始化数据对象失败:', error);
    }
  }

  // 开始设备发现
  async startDeviceDiscovery() {
    if (!this.deviceManager) {
      return;
    }

    const subscribeInfo = {
      subscribeId: 'music_discovery',
      mode: deviceManager.DiscoverMode.DISCOVER_MODE_ACTIVE,
      medium: deviceManager.ExchangeMedium.COMMON,
      freq: deviceManager.ExchangeFreq.LOW,
      isSameAccount: true,
      isWakeRemote: false
    };

    await this.deviceManager.startDeviceDiscovery(subscribeInfo);
    this.updateDeviceList();
  }

  // 更新设备列表
  async updateDeviceList() {
    if (!this.deviceManager) {
      return;
    }

    const devices = await this.deviceManager.getTrustedDeviceListSync();
    this.deviceList = devices;
  }

  // 播放/暂停音乐
  async togglePlay() {
    if (!this.dataObject) {
      return;
    }

    await this.dataObject.update((oldValue) => {
      const newState = {
        ...oldValue.musicState,
        isPlaying: !oldValue.musicState.isPlaying
      };
      return {
        musicState: newState
      };
    });
  }

  // 切换歌曲
  async changeTrack(trackName: string) {
    if (!this.dataObject) {
      return;
    }

    await this.dataObject.update((oldValue) => {
      const newState = {
        ...oldValue.musicState,
        currentTrack: trackName,
        progress: 0
      };
      return {
        musicState: newState
      };
    });
  }

  // 流转到其他设备
  async transferToDevice(deviceId: string) {
    if (!this.dataObject) {
      return;
    }

    const device = this.deviceList.find(d => d.deviceId === deviceId);
    if (device) {
      console.log('流转音乐到设备:', device.deviceName);
      this.selectedDeviceId = deviceId;
      
      // 这里可以执行跨设备迁移逻辑
    }
  }

  build() {
    Column() {
      // 设备列表
      if (this.deviceList.length > 0) {
        Text('可用设备:')
          .fontSize(16)
          .margin(10)
        
        List() {
          ForEach(this.deviceList, (item: deviceManager.DeviceInfo) => {
            ListItem() {
              Text(item.deviceName)
                .fontSize(14)
            }
            .onClick(() => this.transferToDevice(item.deviceId))
          })
        }
        .height(100)
        .margin(10)
      }

      // 音乐控制面板
      Column() {
        Text(this.musicState.currentTrack)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .margin(10)
        
        Text(`${this.musicState.isPlaying ? '播放中' : '已暂停'}`)
          .fontSize(14)
          .fontColor(this.musicState.isPlaying ? Color.Green : Color.Gray)
          .margin(5)
        
        Row() {
          Button(this.musicState.isPlaying ? '暂停' : '播放')
            .onClick(() => this.togglePlay())
            .width(80)
            .height(40)
            .margin(5)
          
          Button('下一首')
            .onClick(() => this.changeTrack('下一首歌曲'))
            .width(80)
            .height(40)
            .margin(5)
        }
        .margin(10)
      }
      .border({ width: 1, color: Color.Gray })
      .borderRadius(10)
      .padding(15)
      .margin(10)
    }
    .onAppear(() => this.onInit())
  }
}

五、最佳实践

1. 网络状态检测

在分布式应用中,网络状态至关重要:

// entry/src/main/ets/utils/NetworkUtil.ets
import network from '@ohos.network.net';
import common from '@ohos.app.ability.common';

export class NetworkUtil {
  // 检查网络连接状态
  static async checkNetworkStatus(): Promise<boolean> {
    try {
      const netManager = network.getDefault();
      const netCapabilities = await netManager.getNetCapabilities();
      return netCapabilities.hasCap(network.NetCap.NET_CAPABILITY_INTERNET);
    } catch (error) {
      console.error('检查网络状态失败:', error);
      return false;
    }
  }

  // 监听网络变化
  static registerNetworkListener(callback: (isConnected: boolean) => void) {
    const netManager = network.getDefault();
    netManager.on('netStatusChange', (data) => {
      callback(data.isConnected);
    });
  }
}

2. 错误处理与重试机制

分布式操作需要健壮的错误处理:

// entry/src/main/ets/utils/RetryUtil.ets
export class RetryUtil {
  // 带重试的异步操作
  static async withRetry<T>(
    operation: () => Promise<T>,
    maxRetries: number = 3,
    delay: number = 1000
  ): Promise<T> {
    let lastError: Error | null = null;
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await operation();
      } catch (error) {
        lastError = error;
        console.warn(`操作失败,第${attempt}次重试:`, error);
        
        if (attempt < maxRetries) {
          await new Promise(resolve => setTimeout(resolve, delay * attempt));
        }
      }
    }
    
    throw lastError || new Error('操作失败');
  }
}

3. 数据冲突解决策略

在分布式环境中,数据冲突不可避免:

// entry/src/main/ets/utils/ConflictResolver.ets
import distributedData from '@ohos.data.distributedData';

export class ConflictResolver {
  // 基于时间戳的冲突解决
  static timestampResolver(oldValue: any, newValue: any): any {
    const oldTimestamp = oldValue?.timestamp || 0;
    const newTimestamp = newValue?.timestamp || 0;
    
    return newTimestamp > oldTimestamp ? newValue : oldValue;
  }

  // 自定义业务逻辑冲突解决
  static customResolver(oldValue: any, newValue: any): any {
    // 根据业务规则解决冲突
    if (oldValue?.priority > newValue?.priority) {
      return oldValue;
    }
    return newValue;
  }
}

六、总结与行动建议

通过本篇文章,我们学习了HarmonyOS分布式能力的核心概念和基本用法。在实际开发中,建议:

  1. 权限管理要规范:严格按照权限管理规范申请分布式权限
  2. 网络状态要检测:在分布式操作前检查网络连接状态
  3. 错误处理要健壮:实现重试机制和错误降级策略
  4. 数据冲突要解决:根据业务场景选择合适的冲突解决策略
  5. 性能优化要考虑:避免频繁的跨设备数据同步,合理使用本地缓存

建议读者在掌握基础功能后,继续学习分布式数据管理和分布式任务调度等进阶内容,构建更强大的跨设备应用。

posted @ 2025-12-23 23:20  J_____P  阅读(0)  评论(0)    收藏  举报