Administrator
发布于 2026-09-01 / 70 阅读
0
0

鸿蒙蓝牙与 NFC 实战:BLE 连接、GATT 通信与标签读写

系列文章《鸿蒙开发从入门到专家》第 25 篇 · 高级

应用开发做到一定深度,必然要碰硬件。鸿蒙的生态不止手机,还有耳机、手表、车机、智能家居。设备之间怎么通信?最常见的就是蓝牙低功耗(BLE)和 NFC。这两块技术细节多、坑也多,本文把核心链路串一遍。

一、BLE 开发整体流程

BLE(Bluetooth Low Energy)适合低功耗、小数据量的场景,比如手环同步、体温计读取、Beacon 定位。一个完整的 BLE 中心设备流程包括:

  1. 申请权限并打开蓝牙。

  2. 扫描周边从设备。

  3. 连接目标设备。

  4. 发现服务(Service)和特征(Characteristic)。

  5. 读写特征或订阅通知(Notify/Indicate)。

  6. 断开连接。

鸿蒙通过 @kit.ConnectivityKit 中的 bluetooth 模块提供 BLE API。

二、扫描与连接

import { bluetooth } from '@kit.ConnectivityKit';

// 开启蓝牙
bluetooth.enableBluetooth();

// 扫描设备
bluetooth.BLE.startBLEScan([
  {
    serviceUuid: '0000180d-0000-1000-8000-00805f9b34fb', // 心率服务
  }
], {
  interval: 0,
  dutyMode: bluetooth.ScanDuty.SCAN_DUTY_LOW_POWER,
});

// 监听扫描结果
bluetooth.BLE.on('BLEDeviceFind', (data) => {
  for (const device of data.data) {
    console.info(`发现设备:${device.deviceName},RSSI:${device.rssi}`);
  }
});

扫描到设备后,用 deviceId 发起连接:

const gattClient = bluetooth.BLE.createGattClientDevice(deviceId);
await gattClient.connect();

连接成功后就可以发现服务了。

三、GATT 通信:读、写、订阅

GATT 是 BLE 的通信协议。每个设备提供若干 Service,每个 Service 下包含若干 Characteristic。Characteristic 是实际读写的最小单元。

// 发现服务
const services = await gattClient.getServices();
for (const service of services) {
  console.info(`Service UUID: ${service.serviceUuid}`);
  for (const char of service.characteristics) {
    console.info(`  Characteristic UUID: ${char.characteristicUuid}`);
  }
}

// 读取特征值
const value = await gattClient.readCharacteristicValue({
  serviceUuid: '0000180d-0000-1000-8000-00805f9b34fb',
  characteristicUuid: '00002a37-0000-1000-8000-00805f9b34fb',
});

// 订阅特征通知
await gattClient.setCharacteristicChangeNotification({
  serviceUuid: '0000180d-0000-1000-8000-00805f9b34fb',
  characteristicUuid: '00002a37-0000-1000-8000-00805f9b34fb',
  enable: true,
});

gattClient.on('BLECharacteristicChange', (data) => {
  const heartRate = parseHeartRate(data.data);
  console.info(`心率:${heartRate}`);
});

解析心率特征时要注意:第一个字节的最低位是心率格式标志。0 表示 UINT8,1 表示 UINT16。这种细节直接影响读数正确性。

四、NFC 标签读写

NFC 适合近距离、一次性交互,比如刷门禁、读商品信息、碰一碰配网。鸿蒙通过 @kit.ConnectivityKit 的 nfc 模块或 tag 相关 API 操作标签。

NFC 开发有两个关键点:

  • 前台分发:应用在前台时优先处理发现的 NFC 标签。

  • 标签类型:常见的有 NDEF、MifareClassic、ISO-DEP 等,不同类型读写方式不同。

读 NDEF 标签的大致流程:

import { tag } from '@kit.ConnectivityKit';

// 在 Ability 的 onCreate 或页面 onReady 中注册前台分发
nfc.getNfcController().on('tagDiscovered', (info) => {
  const ndef = tag.getNdef(info.tagInfo);
  if (ndef) {
    ndef.connect();
    const message = ndef.getNdefMessage();
    for (const record of message.records) {
      console.info(`NDEF 记录:${record.payload}`);
    }
    ndef.close();
  }
});

写标签时把文本或 URI 封装成 NDEF 记录:

const record = tag.NdefRecord.createTextRecord('Hello HarmonyOS');
const msg = tag.NdefMessage.createNdefMessage([record]);
ndef.connect();
ndef.writeNdefMessage(msg);
ndef.close();

五、权限与用户体验

蓝牙和 NFC 都属于敏感权限。module.json5 中需要声明:

{
  "name": "ohos.permission.ACCESS_BLUETOOTH",
  "reason": "$string:bluetooth_reason"
},
{
  "name": "ohos.permission.DISCOVER_BLUETOOTH",
  "reason": "$string:bluetooth_reason"
},
{
  "name": "ohos.permission.NFC",
  "reason": "$string:nfc_reason"
}

蓝牙扫描会消耗电量,建议扫描到目标设备后立即停止扫描。另外,Android 和 iOS 都有后台扫描限制,鸿蒙也不例外,后台 BLE 扫描需要申请特殊权限或走后台任务机制。

六、实战:蓝牙温度计数据同步

以一个 BLE 温度计为例:

  1. 扫描时按服务 UUID 过滤,只保留温度计设备。

  2. 连接后读取电池服务(0x180F)确认电量。

  3. 订阅温度测量特征(0x2A1C),实时拿到温度值。

  4. 数据解析后写入本地 RDB,并刷新 UI。

  5. 用户退出页面时断开连接并释放 GattClient。

小结

BLE 和 NFC 都是近场通信,但适用场景不同:

  • BLE:持续连接、数据流、双向交互。

  • NFC:一次性触碰、快速配对、标签读写。

两者都需要仔细处理权限、生命周期和异常断开。协议细节(GATT 特征格式、NDEF 记录类型)是调试时最容易卡住的地方。

下一篇我们聊聊传感器:加速度计、陀螺仪和传感器融合。


评论