HarmonyOS鸿蒙Next实战开发-设备连接与认证

HarmonyOS鸿蒙Next实战开发-设备连接与认证 在鸿蒙分布式应用开发中,需要实现设备间的自动发现、认证和连接,以构建跨设备协同体验。开发者常遇到以下具体问题:

  • 发现机制分散:蓝牙、Wi-Fi P2P、局域网发现多种技术并存
  • 协议栈不统一:不同设备支持的连接协议有差异
  • 安全机制严格:分布式安全要求导致连接流程复杂

解决方案

环境配置

1. 确保开发环境配置正确

检查DevEco Studio版本

2. 创建鸿蒙项目

选择Application -> Empty Ability

模型选择:Stage

开发语言:ArkTS

API版本:9+

1.1 设备管理封装类

// DeviceManager.ts - 鸿蒙设备管理器
import deviceManager from '@ohos.distributedDeviceManager';
import { BusinessError } from '@ohos.base';
import { common } from '@kit.AbilityKit';

export class HarmonyDeviceManager {
  private deviceDiscovery: deviceManager.DeviceDiscovery | null = null;
  private deviceList: deviceManager.DeviceBasicInfo[] = [];
  private authCallback: deviceManager.AuthCallback | null = null;
  private connectionCallback: deviceManager.DeviceConnectCallback | null = null;
  
  // 初始化设备管理器
  async initDeviceManager(context: common.UIAbilityContext): Promise<void> {
    try {
      console.info('[DeviceManager] Initializing device manager...');
      
      // 创建设备管理器实例
      const manager = deviceManager.createDeviceManager(context.bundleName, {
        bundleName: context.bundleName,
        callback: (action: deviceManager.DeviceStateChangeAction, device: deviceManager.DeviceBasicInfo) => {
          this.handleDeviceStateChange(action, device);
        }
      });
      
      // 设置连接状态回调
      this.setupConnectionCallback();
      
      console.info('[DeviceManager] Initialization completed');
    } catch (error) {
      console.error('[DeviceManager] Initialization failed:', error);
    }
  }
  
  // 开始发现设备
  async startDiscovery(options?: deviceManager.DiscoveryOptions): Promise<void> {
    try {
      const defaultOptions: deviceManager.DiscoveryOptions = {
        discoveryMode: deviceManager.DiscoveryMode.DISCOVERY_MODE_ACTIVE,
        medium: deviceManager.ExchangeMedium.COAP,
        freq: deviceManager.ExchangeFreq.LOW,
        isActiveDiscover: true,
        ...options
      };
      
      this.deviceDiscovery = await deviceManager.startDeviceDiscovery(defaultOptions);
      
      // 监听设备发现事件
      this.deviceDiscovery.on('discoverSuccess', (device: deviceManager.DeviceBasicInfo) => {
        this.onDeviceDiscovered(device);
      });
      
      this.deviceDiscovery.on('discoverFail', (errorCode: number) => {
        console.error(`[DeviceManager] Discovery failed: ${errorCode}`);
      });
      
    } catch (error) {
      console.error('[DeviceManager] Start discovery failed:', error);
    }
  }
  
  // 设备发现回调
  private onDeviceDiscovered(device: deviceManager.DeviceBasicInfo): void {
    // 去重处理
    const existingIndex = this.deviceList.findIndex(d => d.deviceId === device.deviceId);
    
    if (existingIndex === -1) {
      this.deviceList.push(device);
      console.info(`[DeviceManager] New device discovered: ${device.deviceName} (${device.deviceId})`);
      
      // 触发设备更新事件
      this.emitDeviceListUpdated();
    }
  }
  
  // 连接设备
  async connectDevice(deviceId: string, authParam?: deviceManager.AuthParam): Promise<boolean> {
    try {
      console.info(`[DeviceManager] Connecting to device: ${deviceId}`);
      
      const authParam: deviceManager.AuthParam = {
        authType: deviceManager.AuthType.PIN_CODE,
        appIcon: '',
        appThumbnail: '',
        ...authParam
      };
      
      // 发起认证请求
      await deviceManager.authenticateDevice(authParam, {
        onSuccess: (data: { deviceId: string; pinCode?: string }) => {
          console.info(`[DeviceManager] Authentication success: ${data.deviceId}`);
          this.onAuthSuccess(deviceId);
        },
        onError: (error: BusinessError) => {
          console.error(`[DeviceManager] Authentication failed: ${JSON.stringify(error)}`);
        }
      });
      
      return true;
    } catch (error) {
      console.error('[DeviceManager] Connect device failed:', error);
      return false;
    }
  }
  
  // 认证成功处理
  private onAuthSuccess(deviceId: string): void {
    // 建立连接
    deviceManager.connectDevice(
      deviceId,
      deviceManager.ConnectType.TYPE_WIFI_P2P,
      this.connectionCallback!
    ).then(() => {
      console.info(`[DeviceManager] Device ${deviceId} connected successfully`);
    }).catch((error: BusinessError) => {
      console.error(`[DeviceManager] Connect failed: ${JSON.stringify(error)}`);
    });
  }
  
  // 设置连接回调
  private setupConnectionCallback(): void {
    this.connectionCallback = {
      onConnect: (deviceInfo: deviceManager.DeviceBasicInfo) => {
        console.info(`[DeviceManager] Device connected: ${deviceInfo.deviceName}`);
        this.emitDeviceConnected(deviceInfo);
      },
      onDisconnect: (deviceInfo: deviceManager.DeviceBasicInfo) => {
        console.info(`[DeviceManager] Device disconnected: ${deviceInfo.deviceName}`);
        this.emitDeviceDisconnected(deviceInfo);
      }
    };
  }
  
  // 设备状态变更处理
  private handleDeviceStateChange(
    action: deviceManager.DeviceStateChangeAction, 
    device: deviceManager.DeviceBasicInfo
  ): void {
    switch (action) {
      case deviceManager.DeviceStateChangeAction.ONLINE:
        console.info(`[DeviceManager] Device online: ${device.deviceName}`);
        break;
      case deviceManager.DeviceStateChangeAction.OFFLINE:
      case deviceManager.DeviceStateChangeAction.READY_OFFLINE:
        console.info(`[DeviceManager] Device offline: ${device.deviceName}`);
        break;
    }
  }
  
  // 获取设备列表
  getDevices(): deviceManager.DeviceBasicInfo[] {
    return [...this.deviceList];
  }
  
  // 停止发现
  async stopDiscovery(): Promise<void> {
    if (this.deviceDiscovery) {
      await this.deviceDiscovery.stop();
      this.deviceDiscovery = null;
    }
  }
  
  // 清理资源
  release(): void {
    this.stopDiscovery();
    this.deviceList = [];
  }
  
  // 事件发射器(简化版)
  private emitDeviceListUpdated(): void {
    // 实际实现中可使用EventEmitter
  }
  
  private emitDeviceConnected(device: deviceManager.DeviceBasicInfo): void {
    // 实际实现中可使用EventEmitter
  }
  
  private emitDeviceDisconnected(device: deviceManager.DeviceBasicInfo): void {
    // 实际实现中可使用EventEmitter
  }
}

1.2 UI组件封装

// DeviceListComponent.ets - 设备列表组件
@Component
export struct DeviceListComponent {
  @State deviceList: Array<DeviceItem> = [];
  private deviceManager: HarmonyDeviceManager = new HarmonyDeviceManager();
  
  aboutToAppear(): void {
    this.initDeviceDiscovery();
  }
  
  // 初始化设备发现
  async initDeviceDiscovery(): Promise<void> {
    // 请求权限
    await this.requestPermissions();
    
    // 初始化设备管理器
    await this.deviceManager.initDeviceManager(getContext(this) as common.UIAbilityContext);
    
    // 开始发现设备
    await this.deviceManager.startDiscovery();
    
    // 定时刷新设备列表
    setInterval(() => {
      this.deviceList = this.deviceManager.getDevices().map(device => ({
        id: device.deviceId,
        name: device.deviceName || 'Unknown Device',
        type: this.getDeviceType(device.deviceType),
        isConnected: false // 实际应从设备管理器获取连接状态
      }));
    }, 2000);
  }
  
  // 请求必要权限
  async requestPermissions(): Promise<void> {
    const permissions: Array<string> = [
      'ohos.permission.DISTRIBUTED_DATASYNC',
      'ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE',
      'ohos.permission.GET_NETWORK_INFO'
    ];
    
    for (const permission of permissions) {
      try {
        const result = await abilityAccessCtrl.requestPermissionsFromUser(
          getContext(this) as common.UIAbilityContext,
          [permission]
        );
        console.info(`[DeviceList] Permission ${permission} granted: ${result.authResults[0] === 0}`);
      } catch (error) {
        console.error(`[DeviceList] Permission request failed: ${error}`);
      }
    }
  }
  
  // 连接设备
  async connectToDevice(deviceId: string): Promise<void> {
    const success = await this.deviceManager.connectDevice(deviceId);
    if (success) {
      promptAction.showToast({ message: '设备连接成功' });
    } else {
      promptAction.showToast({ message: '设备连接失败' });
    }
  }
  
  // 获取设备类型图标
  getDeviceType(deviceType: number): string {
    switch (deviceType) {
      case 0x00: return 'phone'; // 手机
      case 0x01: return 'tablet'; // 平板
      case 0x02: return 'tv'; // 智慧屏
      case 0x03: return 'watch'; // 手表
      default: return 'device';
    }
  }
  
  build() {
    Column() {
      // 标题
      Text('附近设备')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 20 })
      
      // 设备列表
      List({ space: 10 }) {
        ForEach(this.deviceList, (device: DeviceItem) => {
          ListItem() {
            DeviceItemComponent({ device: device, onConnect: (id: string) => {
              this.connectToDevice(id);
            }})
          }
        })
      }
      .layoutWeight(1)
      
      // 操作按钮
      Row() {
        Button('重新扫描')
          .onClick(() => {
            this.deviceManager.stopDiscovery();
            this.deviceManager.startDiscovery();
          })
          .margin({ right: 10 })
        
        Button('停止发现')
          .onClick(() => {
            this.deviceManager.stopDiscovery();
          })
      }
      .justifyContent(FlexAlign.Center)
      .margin({ top: 20, bottom: 20 })
    }
  }
}
// 设备项组件
@Component
struct DeviceItemComponent {
  private device: DeviceItem = { id: '', name: '', type: '', isConnected: false };
  private onConnect?: (deviceId: string) => void;
  
  build() {
    Row() {
      // 设备图标
      Image($r(`app.media.ic_device_${this.device.type}`))
        .width(40)
        .height(40)
        .margin({ right: 15 })
      
      // 设备信息
      Column() {
        Text(this.device.name)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
        
        Text(`设备ID: ${this.device.id.substring(0, 8)}...`)
          .fontSize(12)
          .fontColor(Color.Gray)
      }
      .layoutWeight(1)
      .alignItems(HorizontalAlign.Start)
      
      // 连接按钮
      Button(this.device.isConnected ? '已连接' : '连接')
        .enabled(!this.device.isConnected)
        .onClick(() => {
          if (this.onConnect) {
            this.onConnect(this.device.id);
          }
        })
    }
    .padding(15)
    .backgroundColor(Color.White)
    .borderRadius(8)
    .shadow({ radius: 4, color: Color.Black, offsetX: 0, offsetY: 2 })
  }
}

1.3 权限配置文件

// module.json5
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC",
        "reason": "需要同步数据到其他设备",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE",
        "reason": "需要监听设备状态变化",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.GET_NETWORK_INFO",
        "reason": "需要获取网络信息进行设备发现",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      }
    ],
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "permissions": [
          "ohos.permission.DISTRIBUTED_DATASYNC",
          "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
        ]
      }
    ]
  }
}

步骤1:添加依赖

// oh-package.json5
{
  "dependencies": {
    "@ohos/distributedDeviceManager": "file:../feature/distributed_device_manager"
  }
}

步骤2:配置设备能力

// module.json5
{
  "module": {
    "name": "entry",
    "type": "entry",
    "deviceTypes": ["phone", "tablet", "tv", "wearable"],
    "distributedNotificationEnabled": true,
    "distributedPermissions": {
      "com.example.myapp": {
        "data": {
          "access": ["read", "write"],
          "uri": "dataability:///com.example.myapp.DataAbility"
        }
      }
    }
  }
}

步骤3:实现设备发现服务

// DeviceDiscoveryService.ts
export class DeviceDiscoveryService {
  private static instance: DeviceDiscoveryService;
  private discoveryCallbacks: Array<(devices: DeviceBasicInfo[]) => void> = [];
  
  static getInstance(): DeviceDiscoveryService {
    if (!DeviceDiscoveryService.instance) {
      DeviceDiscoveryService.instance = new DeviceDiscoveryService();
    }
    return DeviceDiscoveryService.instance;
  }
  
  // 统一发现接口
  async discoverNearbyDevices(options: DiscoveryOptions = {}): Promise<DeviceBasicInfo[]> {
    const devices: DeviceBasicInfo[] = [];
    
    // 多协议并行发现
    await Promise.all([
      this.discoverViaBluetooth(devices, options),
      this.discoverViaWiFi(devices, options),
      this.discoverViaCoap(devices, options)
    ]);
    
    // 去重和排序
    return this.deduplicateAndSortDevices(devices);
  }
  
  private async discoverViaBluetooth(
    devices: DeviceBasicInfo[], 
    options: DiscoveryOptions
  ): Promise<void> {
    // 蓝牙发现实现
  }
  
  private async discoverViaWiFi(
    devices: DeviceBasicInfo[], 
    options: DiscoveryOptions
  ): Promise<void> {
    // Wi-Fi发现实现
  }
  
  private async discoverViaCoap(
    devices: DeviceBasicInfo[], 
    options: DiscoveryOptions
  ): Promise<void> {
    // CoAP发现实现
  }
}

步骤5:实现连接管理

// ConnectionManager.ts
export class ConnectionManager {
  private connections: Map<string, DeviceConnection> = new Map();
  
  // 建立连接
  async establishConnection(
    deviceId: string, 
    options: ConnectionOptions
  ): Promise<DeviceConnection> {
    const connection: DeviceConnection = {
      deviceId,
      status: 'connecting',
      timestamp: Date.now(),
      retryCount: 0
    };
    
    this.connections.set(deviceId, connection);
    
    try {
      // 1. 设备认证
      await this.authenticateDevice(deviceId, options.authType);
      
      // 2. 建立传输通道
      const channel = await this.createChannel(deviceId, options.channelType);
      
      // 3. 启动心跳检测
      this.startHeartbeat(deviceId);
      
      connection.status = 'connected';
      connection.channel = channel;
      
      console.info(`[ConnectionManager] Device ${deviceId} connected successfully`);
      return connection;
      
    } catch (error) {
      connection.status = 'failed';
      connection.error = error as Error;
      
      // 重试逻辑
      if (connection.retryCount < options.maxRetries || 3) {
        connection.retryCount++;
        return this.establishConnection(deviceId, options);
      }
      
      throw error;
    }
  }
}

测试环境:2台华为P60,HarmonyOS 4.0 测试场景:设备发现与连接

可复用组件清单

  1. HarmonyDeviceManager​ - 核心设备管理类
  2. DeviceListComponent​ - 设备列表UI组件
  3. ConnectionManager​ - 连接状态管理
  4. DeviceDiscoveryService​ - 统一发现服务
  5. PermissionHelper​ - 权限管理工具
  6. 示例配置文件​ - 权限、能力配置模板

最佳实践总结

  1. 统一入口:封装所有设备操作到一个管理器
  2. 事件驱动:使用观察者模式监听设备状态变化
  3. 错误处理:统一的错误处理重试机制
  4. 权限管理:按需请求,优雅降级
  5. 状态管理:使用状态机管理连接生命周期
  6. 多协议支持:自动选择最优发现协议
  7. 资源释放:合理释放不使用的资源

更多关于HarmonyOS鸿蒙Next实战开发-设备连接与认证的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

鸿蒙Next设备连接与认证主要基于分布式软总线技术。设备通过近场发现、认证、组网实现互联。认证方式包括PIN码、二维码、NFC等,确保安全可信。开发者可使用分布式设备管理、分布式数据管理等API实现跨设备协同。

更多关于HarmonyOS鸿蒙Next实战开发-设备连接与认证的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


这篇实战分享非常全面,清晰地阐述了HarmonyOS Next分布式设备连接与认证的核心流程和常见问题的解决方案。针对你提供的代码和方案,我补充几点关键的技术细节和优化建议:

1. 设备发现 (@ohos.distributedDeviceManager) 的正确使用 你封装的 HarmonyDeviceManager 类基本遵循了API规范。需要特别注意:

  • 发现模式与频率:代码中设置的 discoveryModefreq 是合理的默认值。对于需要实时性高的场景(如遥控器),可考虑使用 HIGH 频率和 DISCOVERY_MODE_ACTIVE
  • 设备信息更新onDeviceDiscovered 方法中的去重逻辑是必要的。此外,设备信息(如名称、状态)可能动态变化,建议在 handleDeviceStateChange 回调中更新 deviceList,而不仅仅是日志记录。

2. 认证流程 (authenticateDevice) 的安全强化 你实现了PIN码认证流程。在Next版本中,分布式安全框架更为严格,建议:

  • 认证参数 (AuthParam):除了 authType,应确保 appIconappThumbnail 使用正确的资源路径,以便在目标设备上显示可信的认证界面。留空可能导致认证失败或用户体验不佳。
  • 错误处理authenticateDeviceonError 回调应区分不同类型的错误(如用户取消、网络超时、设备不支持),并给出相应的重试或降级策略。

3. 连接建立 (connectDevice) 的协议选择 代码中固定使用了 TYPE_WIFI_P2P。在实际部署中,应根据设备能力动态选择:

  • 协议协商:在认证成功后,可先通过 deviceManager.getDeviceInfo 查询目标设备支持的连接类型(如Wi-Fi P2P、BLE、CoAP),再选择最合适的 ConnectType
  • 回退机制:如果首选连接失败,应有回退到次选协议的逻辑。

4. 权限 (module.json5) 与配置的完整性 你列出的权限是核心所需。对于需要跨设备数据传输的应用,还需注意:

  • 分布式数据管理:如果连接后涉及数据同步(如使用 @ohos.data.distributedData),需要在 module.json5abilities 中声明对应的 dataSync 权限,并正确配置 distributedPermissions 字段,定义数据共享的域和访问权限。
  • 设备类型兼容性deviceTypes 字段的配置需与实际测试设备匹配。对于“wearable”(穿戴设备),其可用的连接协议可能受限。

5. 生命周期管理与资源释放 你已在 release 方法中处理了停止发现和清空列表,这很好。还需注意:

  • 连接监听器的注销:当UI组件(如 DeviceListComponent)销毁时,除了停止发现,还应确保注销从 createDeviceManager 传入的 callback,避免内存泄漏。这通常在Ability的 onDestroy 阶段调用管理器的 release 方法。
  • 连接状态同步:UI中设备项的 isConnected 状态应直接与 ConnectionManager(或 deviceManager 的状态回调)同步,而不是硬编码为 false。可以通过在 onConnect/onDisconnect 回调中更新设备列表状态来实现。

总结 你提供的方案是一个优秀的起点,涵盖了从发现、认证到连接的主要步骤。要投入生产环境,重点需要围绕 动态协议选择、健壮的错误处理与重试、严格的生命周期管理 以及 完整的分布式数据权限配置 进行加固。HarmonyOS Next的分布式能力设计旨在让开发者聚焦业务逻辑,但正确理解并处理好这些底层交互的细节是构建稳定、流畅跨设备体验的关键。

回到顶部