前言

在智能设备生态中,蓝牙低功耗(BLE)技术因其出色的节能特性和广泛的适用性,已成为智能手表、健康监测设备、智能家居传感器等众多低功耗设备连接的首选方案。HarmonyOS NEXT 充分发挥了 BLE 的优势,为开发者提供了强大的工具和接口,实现设备间高效、低功耗的通信。

本文将基于实际开发实践,系统梳理 HarmonyOS NEXT 中 BLE 开发的核心流程、常见痛点及解决方案。


一、开发前准备:权限与基础配置

1.1 权限声明

在 HarmonyOS NEXT 中进行 BLE 开发,首先需要在 module.json5 中声明必要的权限。权限配置不全或未动态申请,是导致 BLE 功能异常的常见原因

json

// module.json5
"requestPermissions": [
  {
    "name": "ohos.permission.ACCESS_BLUETOOTH",
    "reason": "$string:bluetooth_permission_reason",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "inuse"
    }
  },
  {
    "name": "ohos.permission.ACCESS_FINE_LOCATION",
    "reason": "$string:location_permission_reason",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "inuse"
    }
  }
]

除了在配置文件中声明,还必须在代码中进行动态权限申请,这点容易被忽略。

1.2 检查蓝牙状态

在执行任何 BLE 操作前,应先检查设备蓝牙是否已开启。ble.isBleEnabled() 是前置条件检查的关键方法。


二、广播与扫描:设备发现的实现

2.1 广播机制

BLE 设备通过广播向周围宣告自身存在。在 HarmonyOS NEXT 中,广播的实现涉及设置广播参数、构造广播数据以及启动广播三个步骤。

设置广播参数

typescript

let setting: ble.AdvertiseSetting = {
  interval: 160,    // 广播间隔
  txPower: 0,        // 发射功率
  connectable: true  // 是否可连接
};

构造广播数据
广播数据可包含服务 UUID、设备名称、制造商数据等信息。需要注意的是,UUID 必须是标准的 128 位格式(如 0000ffe0-0000-1000-8000-00805f9b34fb),不能随意使用 16 位简写,否则可能导致 addService 失败并报错 2900099

2.2 扫描机制

扫描是发现周边 BLE 设备的核心手段。在 HarmonyOS NEXT 中,扫描流程如下:

核心代码示例

typescript

// 1. 订阅扫描结果
ble.on('BLEDeviceFind', (data: Array<ble.ScanResult>) => {
  // 处理发现的设备
});

// 2. 设置扫描过滤器(可选)
let scanFilter: ble.ScanFilter = {
  manufactureId: 4567,
  // 其他过滤条件
};

// 3. 设置扫描参数
let scanOptions: ble.ScanOptions = {
  interval: 0,
  dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,
  matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE
};

// 4. 启动扫描
ble.startBLEScan([scanFilter], scanOptions);

2.3 ⚠️ 关键坑点:设备 ID 动态变化

在 HarmonyOS 中,出于信息安全考虑,BLE 扫描获取的 deviceId 是随机 MAC 地址,会随设备开关机等情况发生改变。

具体表现

  • H5 端获取的设备 ID 与鸿蒙原生端扫描到的 ID 可能不一致

  • 直接使用 H5 传递的 deviceId 连接会失败

  • 同一设备在不同时间扫描,deviceId 可能变化

解决方案:不要依赖预先获取的 deviceId 进行连接,而应通过设备名称或其他稳定特征进行比对,动态获取当前有效的 deviceId 再发起连接。


三、连接与通信:GATT 交互实践

3.1 建立连接

连接 BLE 设备的核心是使用 ble.createGattClientDevice(deviceId) 创建 GATT 客户端实例,然后调用 connect() 方法发起连接。

关键步骤

  1. 获取 GATT Client 实例

  2. 订阅连接状态变化事件

  3. 发起连接

typescript

public startConnect(peerDevice: string) {
  this.gattClient = ble.createGattClientDevice(peerDevice);
  
  // 订阅连接状态
  this.gattClient.on('BLEConnectionStateChange', (state) => {
    // 处理连接状态变化
  });
  
  // 发起连接
  this.gattClient.connect();
}

3.2 发现服务与特征值

连接成功后,需要发现服务并获取特征值,才能进行数据读写和订阅。

3.3 数据读写与订阅

写入特征值时,需要注意数据大小的限制。蓝牙 4.0 单次传输数据有限制,建议每次写入不超过 20 字节

typescript

// 发送数据
const buffer = new ArrayBuffer(1);
const dataView = new DataView(buffer);
dataView.setUint8(0, 0x00);

ble.writeCharacteristicValue({
  deviceId: deviceId,
  serviceId: serviceUuid,
  characteristicId: characteristicUuid,
  value: buffer
});

订阅特征值通知

typescript

// 启用 notify
ble.notifyCharacteristicValueChange({
  deviceId: deviceId,
  serviceId: serviceUuid,
  characteristicId: characteristicUuid,
  state: true
});

// 监听数据变化
ble.on('characteristicValueChange', (data) => {
  // 处理接收到的数据
});

3.4 ⚠️ 关键坑点:错误码 2900099

调用 gattServer.addService() 时常见报错 2900099,这是一个通用失败码,表示未满足接口调用的前置依赖条件。

常见原因及排查顺序

  1. 权限问题:蓝牙权限未声明或未动态申请

  2. 蓝牙未开启ble.isBleEnabled() 返回 false

  3. 调用时序问题addService 需在 stateChange 回调确认状态正常后再执行

  4. UUID 格式错误:必须使用标准 128 位 UUID

  5. 模拟器问题:部分 OpenHarmony 模拟器默认关闭蓝牙模拟功能


四、快速回连:提升用户体验的关键

实现快速回连可以显著提升用户体验,避免每次都要重新扫描。

4.1 核心机制

HarmonyOS 中,配对成功后,蓝牙虚拟 MAC 地址会被固化,即使设备开关机也不会改变。

4.2 两种实现方案

方案一:配对方案(推荐)

与对端设备第一次连接后,发起蓝牙配对。后续调用 connection.getPairedDevices() 即可从已配对列表中获取设备地址,直接发起连接,无需重新扫描。

方案二:地址固化方案(需特殊权限)

使用 access.addPersistentDeviceId() 接口持久化存储虚拟随机地址。此方案需要使用 ohos.permission.PERSISTENT_BLUETOOTH_PEERS_MAC 权限,需 ACL 权限申请通过后方可使用。

代码示例(连接意外断开后自动重连):

typescript

this.gattClient?.on('BLEConnectionStateChange', (state) => {
  if (state.state === constant.ProfileConnectionState.STATE_DISCONNECTED) {
    // 意外断开时自动重连
    this.gattClient?.connect();
  }
});

4.3 后台保活

如果应用需要长期在后台运行并保持蓝牙连接,需要申请长时任务(Long Running Task) 来保活蓝牙相关业务,避免被系统挂起。


五、综合建议与避坑指南

常见问题 解决方案
扫描不到设备 检查蓝牙权限、位置权限是否已授予;确认设备正在广播
连接失败 确认 deviceId 有效(非过期随机地址);检查设备是否可连接
写入数据失败 单次写入不超过 20 字节;确认特征值支持 write 属性
订阅收不到数据 先启用 notify,再监听 characteristicValueChange;确认特征值支持 notify/indicate
设备 ID 变化 通过设备名称比对获取最新 deviceId;配对后可固化地址
后台连接断开 申请长时任务保活

结语

HarmonyOS NEXT 的 BLE 开发整体思路与其他平台类似,但有一些独特的坑点和特性需要开发者特别留意:

  1. deviceId 随机变化是最大的"陷阱",理解这一点能避免很多连接问题

  2. 权限管理更加严格,配置和动态申请缺一不可

  3. 配对机制是优化回连体验的关键路径

建议开发者在动手写代码前,先理清应用的角色定位(Client 还是 Server),然后按照"权限申请 → 扫描 → 连接 → 服务发现 → 数据交互"的流程逐步实现。遇到问题时,优先检查权限和 deviceId 是否有效。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐