【鸿蒙实现实现低功耗蓝牙(BLE)连接】

在鸿蒙(HarmonyOS)中,使用ETS(Extended TypeScript/ArkTS)实现低功耗蓝牙(BLE)连接匹配需要以下步骤:

一、准备工作

1.1 添加权限

在 module.json5 中配置权限:

c 复制代码
 json {   "module": {
       "requestPermissions": [
         {
           "name": "ohos.permission.USE_BLUETOOTH"
         },
         {
           "name": "ohos.permission.DISCOVER_BLUETOOTH"
         },
         {
           "name": "ohos.permission.MANAGE_BLUETOOTH"
         },
         {
           "name": "ohos.permission.APPROXIMATELY_LOCATION"
         }
       ]   } }

1.2 导入模块

c 复制代码
typescript
import ble from '@ohos.bluetooth.ble';
import { BusinessError } from '@ohos.base';
import common from '@ohos.app.ability.common';

二、BLE管理器实现

2.1 创建BLE管理类

c 复制代码
typescript
export class BleManager {
  private context: common.UIAbilityContext;
  private isScanning: boolean = false;
  private discoveredDevices: Map<string, ble.ScanResult> = new Map();
  private gattServer: ble.GattClient | null = null;
  
  constructor(context: common.UIAbilityContext) {
    this.context = context;
  }
  
  // 检查蓝牙状态
  async checkBluetoothState(): Promise<boolean> {
    try {
      const state = await ble.getBluetoothState();
      console.log(`当前蓝牙状态: ${state}`);
      return state === ble.BluetoothState.STATE_ON;
    } catch (error) {
      console.error('检查蓝牙状态失败:', error);
      return false;
    }
  }
  
  // 开启蓝牙
  async enableBluetooth(): Promise<boolean> {
    try {
      await ble.enableBluetooth();
      console.log('蓝牙已开启');
      return true;
    } catch (error) {
      console.error('开启蓝牙失败:', error);
      return false;
    }
  }
}

2.2 扫描BLE设备

c 复制代码
typescript
// 在BleManager类中添加方法
public async startScan(
  serviceUuids?: Array<string>,
  timeout: number = 10000
): Promise<void> {
  if (this.isScanning) {
    console.warn('已经在扫描中');
    return;
  }
  
  // 检查蓝牙状态
  const isEnabled = await this.checkBluetoothState();
  if (!isEnabled) {
    const enabled = await this.enableBluetooth();
    if (!enabled) {
      throw new Error('蓝牙开启失败');
    }
  }
  
  this.discoveredDevices.clear();
  
  // 设置扫描参数
  const scanOptions: ble.ScanOptions = {
    interval: 500,
    dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,
    matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE
  };
  
  // 开始扫描
  try {
    await ble.startBLEScan(scanOptions);
    this.isScanning = true;
    console.log('开始扫描BLE设备...');
    
    // 注册扫描结果回调
    ble.on('BLEDeviceFind', (device: ble.ScanResult) => {
      this.handleDeviceFound(device);
    });
    
    // 设置超时停止
    setTimeout(() => {
      this.stopScan();
    }, timeout);
    
  } catch (error) {
    console.error('扫描失败:', error);
    this.isScanning = false;
  }
}

// 处理发现的设备
private handleDeviceFound(device: ble.ScanResult): void {
  const deviceId = device.deviceId;
  
  if (!this.discoveredDevices.has(deviceId)) {
    this.discoveredDevices.set(deviceId, device);
    console.log(`发现设备: ${device.deviceId}, 名称: ${device.deviceName || '未知'}, RSSI: ${device.rssi}`);
    
    // 可以在这里触发UI更新
    // this.emitDeviceFound(device);
  }
}

// 停止扫描
public async stopScan(): Promise<void> {
  if (!this.isScanning) {
    return;
  }
  
  try {
    await ble.stopBLEScan();
    ble.off('BLEDeviceFind'); // 取消回调监听
    this.isScanning = false;
    console.log('扫描已停止');
  } catch (error) {
    console.error('停止扫描失败:', error);
  }
}

2.3 连接BLE设备

c 复制代码
typescript
// 连接设备
public async connectDevice(deviceId: string): Promise<boolean> {
  try {
    // 先停止扫描
    await this.stopScan();
    
    // 创建GATT客户端
    this.gattServer = await ble.createGattClientDevice(this.context, deviceId);
    
    // 连接设备
    const isConnected = await this.gattServer.connect();
    
    if (isConnected) {
      console.log(`设备 ${deviceId} 连接成功`);
      
      // 发现服务
      await this.discoverServices();
      
      return true;
    } else {
      console.error('连接失败');
      return false;
    }
  } catch (error) {
    console.error('连接异常:', error);
    return false;
  }
}

// 发现服务
private async discoverServices(): Promise<void> {
  if (!this.gattServer) {
    return;
  }
  
  try {
    const services = await this.gattServer.getServices();
    console.log(`发现 ${services.length} 个服务`);
    
    // 遍历所有服务
    for (const service of services) {
      console.log(`服务 UUID: ${service.serviceUuid}`);
      
      // 获取特征
      const characteristics = await this.gattServer.getCharacteristics(service.serviceUuid);
      console.log(`服务 ${service.serviceUuid} 有 ${characteristics.length} 个特征`);
      
      // 这里可以处理特定的服务UUID,例如:
      // if (service.serviceUuid === '0000180F-0000-1000-8000-00805F9B34FB') {
      //   // 电池服务
      // }
    }
  } catch (error) {
    console.error('发现服务失败:', error);
  }
}

2.4 读写特征值

c 复制代码
typescript
// 读取特征值
public async readCharacteristic(
  serviceUuid: string,
  characteristicUuid: string
): Promise<Uint8Array | null> {
  if (!this.gattServer) {
    console.error('未连接设备');
    return null;
  }
  
  try {
    const value = await this.gattServer.readCharacteristicValue(
      serviceUuid,
      characteristicUuid
    );
    console.log(`读取特征值成功: ${characteristicUuid}`);
    return value;
  } catch (error) {
    console.error(`读取特征值失败: ${error}`);
    return null;
  }
}

// 写入特征值
public async writeCharacteristic(
  serviceUuid: string,
  characteristicUuid: string,
  value: Uint8Array
): Promise<boolean> {
  if (!this.gattServer) {
    console.error('未连接设备');
    return false;
  }
  
  try {
    await this.gattServer.writeCharacteristicValue(
      serviceUuid,
      characteristicUuid,
      value
    );
    console.log(`写入特征值成功: ${characteristicUuid}`);
    return true;
  } catch (error) {
    console.error(`写入特征值失败: ${error}`);
    return false;
  }
}

// 开启通知
public async enableNotification(
  serviceUuid: string,
  characteristicUuid: string
): Promise<boolean> {
  if (!this.gattServer) {
    return false;
  }
  
  try {
    // 先设置特征值变化监听
    this.gattServer.on('characteristicChange', (characteristic) => {
      if (characteristic.characteristicUuid === characteristicUuid) {
        console.log(`收到特征值变化: ${characteristicUuid}`);
        this.handleCharacteristicChange(characteristic);
      }
    });
    
    // 启用通知
    await this.gattServer.setNotifyCharacteristicChanged(
      serviceUuid,
      characteristicUuid,
      true
    );
    
    console.log(`已开启通知: ${characteristicUuid}`);
    return true;
  } catch (error) {
    console.error(`开启通知失败: ${error}`);
    return false;
  }
}

private handleCharacteristicChange(characteristic: ble.Characteristic): void {
  // 处理接收到的数据
  const value = characteristic.value;
  // 解析数据,根据协议进行匹配
}

2.5 断开连接

c 复制代码
typescript
// 断开连接
public async disconnect(): Promise<void> {
  if (this.gattServer) {
    try {
      // 停止所有通知
      await this.gattServer.setNotifyCharacteristicChanged(
        'any-service',
        'any-characteristic',
        false
      );
      
      // 断开连接
      await this.gattServer.disconnect();
      this.gattServer = null;
      console.log('已断开连接');
    } catch (error) {
      console.error('断开连接失败:', error);
    }
  }
}

三、UI界面示例

c 复制代码
typescript
// DeviceList.ets
@Entry
@Component
struct DeviceList {
  private bleManager: BleManager = new BleManager(getContext(this) as common.UIAbilityContext);
  @State deviceList: Array<ble.ScanResult> = [];
  @State isScanning: boolean = false;
  
  build() {
    Column() {
      // 扫描按钮
      Button(this.isScanning ? '停止扫描' : '开始扫描')
        .onClick(() => {
          if (this.isScanning) {
            this.stopScan();
          } else {
            this.startScan();
          }
        })
        .margin(10)
      
      // 设备列表
      List({ space: 10 }) {
        ForEach(this.deviceList, (device: ble.ScanResult) => {
          ListItem() {
            DeviceItem({
              device: device,
              onConnect: (deviceId: string) => {
                this.connectDevice(deviceId);
              }
            })
          }
        })
      }
      .layoutWeight(1)
    }
  }
  
  async startScan() {
    this.isScanning = true;
    
    // 监听设备发现
    ble.on('BLEDeviceFind', (device: ble.ScanResult) => {
      // 更新设备列表
      this.updateDeviceList(device);
    });
    
    await this.bleManager.startScan(['0000180F-0000-1000-8000-00805F9B34FB']);
  }
  
  async stopScan() {
    await this.bleManager.stopScan();
    this.isScanning = false;
  }
  
  updateDeviceList(device: ble.ScanResult) {
    // 避免重复添加
    const exists = this.deviceList.some(d => d.deviceId === device.deviceId);
    if (!exists) {
      this.deviceList = [...this.deviceList, device];
    }
  }
  
  async connectDevice(deviceId: string) {
    const connected = await this.bleManager.connectDevice(deviceId);
    if (connected) {
      // 连接成功,跳转到控制页面
      // router.push(...)
    }
  }
}

四、匹配逻辑实现

4.1 基于特征值的匹配

c 复制代码
typescript
// 实现特定的匹配协议
export class BleMatcher {
  // 发送匹配请求
  static async sendMatchRequest(
    bleManager: BleManager,
    matchData: Uint8Array
  ): Promise<boolean> {
    // 写入特定的特征值进行匹配
    const success = await bleManager.writeCharacteristic(
      'YOUR_SERVICE_UUID',
      'YOUR_CHARACTERISTIC_UUID',
      matchData
    );
    
    return success;
  }
  
  // 解析匹配响应
  static parseMatchResponse(data: Uint8Array): MatchResult {
    // 根据协议解析数据
    // 返回匹配结果
    return {
      success: data[0] === 0x01,
      matchCode: data.slice(1, 5),
      timestamp: new Date()
    };
  }
}

五、注意事项

  1. 权限管理:确保用户已授权所有必要的蓝牙权限
  2. 连接超时:设置合理的连接超时时间
  3. 错误处理:妥善处理各种异常情况
  4. 资源释放:在页面销毁时断开连接
  5. 后台运行:考虑应用退到后台时的处理策略
相关推荐
FrameNotWork6 小时前
HarmonyOS 教学实战(三):列表分页、下拉刷新与性能优化(让列表真正“丝滑”)
华为·性能优化·harmonyos
柠果7 小时前
HarmonyOS震动反馈开发——提升用户体验的触觉交互
harmonyos
柠果7 小时前
HarmonyOS数据持久化最佳实践——Preferences首选项存储详解
harmonyos
柠果7 小时前
HarmonyOS纯音测听实现——专业听力检测功能开发
harmonyos
柠果7 小时前
HarmonyOS深色模式适配实战——主题切换与WCAG对比度标准
harmonyos
柠果7 小时前
HarmonyOS权限管理实战——麦克风、震动等敏感权限申请
harmonyos
爱吃大芒果7 小时前
Flutter 列表优化:ListView 性能调优与复杂列表实现
开发语言·hive·hadoop·flutter·华为
乾元8 小时前
网络遥测(Telemetry/gNMI)的结构化建模与特征化体系—— 从“采集指标”到“可被 AI 推理的状态向量”
运维·服务器·网络·人工智能·网络协议·华为·ansible
C雨后彩虹8 小时前
事件推送问题
java·数据结构·算法·华为·面试