【鸿蒙实现实现低功耗蓝牙(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. 后台运行:考虑应用退到后台时的处理策略
相关推荐
行者961 小时前
OpenHarmony上Flutter粒子效果组件的深度适配与实践
flutter·交互·harmonyos·鸿蒙
小溪彼岸1 小时前
uni-app小白从0开发一款鸿蒙Next应用到上线
uni-app·harmonyos
asing1 小时前
🤯 为什么我的收银台在鸿蒙系统“第一次返回”死活拦不住?一次差点背锅的排查实录
前端·harmonyos
Van_captain2 小时前
rn_for_openharmony常用组件_Breadcrumb面包屑
javascript·开源·harmonyos
御承扬3 小时前
鸿蒙原生系列之动画效果(帧动画)
c++·harmonyos·动画效果·ndk ui·鸿蒙原生
行者964 小时前
Flutter与OpenHarmony深度集成:数据导出组件的实战优化与性能提升
flutter·harmonyos·鸿蒙
小雨下雨的雨4 小时前
Flutter 框架跨平台鸿蒙开发 —— Row & Column 布局之轴线控制艺术
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨4 小时前
Flutter 框架跨平台鸿蒙开发 —— Center 控件之完美居中之道
flutter·ui·华为·harmonyos·鸿蒙
小雨下雨的雨5 小时前
Flutter 框架跨平台鸿蒙开发 —— Icon 控件之图标交互美学
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨5 小时前
Flutter 框架跨平台鸿蒙开发 —— Placeholder 控件之布局雏形美学
flutter·ui·华为·harmonyos·鸿蒙系统