Characteristic 是 Bluetooth Low Energy 中的基本数据单元,Central 通过它在外围设备上接收或写入信息。每个 Characteristic 属于特定的 GATT 服务,具有唯一的 UUID 和一组属性(read、write、notify、indicate),这些属性定义了可能的操作。根据 Bluetooth Core Specification 5.4 (2023),Bluetooth SIG 已为医疗、健身和工业设备规范了 500 多个标准特性。开发人员创建自定义特性来传输任何用户数据——从传感器读数到设备控制命令。
要点
Characteristic 是 GATT 协议的一个属性,包含值(value)和元数据。在 BLE 架构中,数据不在设备之间直接传输,而是通过读取和写入服务特性的值来传输。如果服务是一个文件夹,那么 Characteristic 就是该文件夹中的一个文件。
每个 Characteristic 由三个组件组成:声明(declaration)、值(value)和描述符(descriptors)。声明包含特性的 UUID 及其属性。值是在 Central 和 Peripheral 之间传输的实际数据。描述符提供额外的配置。
根据Bluetooth Core Specification 5.4 (2023),BLE 中的所有数据交换都是通过对特性的操作进行的。即使是标准配置文件,如 Heart Rate Profile 或 Battery Service,也是建立在具有预定义 UUID 的特性集之上。这确保了不同制造商设备的兼容性,无需预先配置。
开发人员需要理解:每个 Characteristic 可以支持不同的属性组合。一个特性可能只读,另一个只写,第三个用于通知。正确选择属性决定了使用场景和设备的功耗。
属性(properties)定义了对特性允许哪些操作。它是一个字节掩码,每个位启用或禁用特定操作。以下列出了主要属性。
| 属性 | 位 | 描述 | 典型用途 |
|---|---|---|---|
| Read | 0x02 | Central 可以读取当前值 | 状态、电池电量、配置 |
| Write | 0x08 | Central 可以写入新值 | 控制命令、设置 |
| Notify | 0x10 | Peripheral 发送值无需确认 | 流式数据(脉搏、温度) |
| Indicate | 0x20 | Peripheral 发送值需要确认 | 关键数据(警报、状态) |
| Write Without Response | 0x04 | 无需等待服务器确认即可写入 | 高速命令传输 |
权限(permissions)是 GATT 服务器级别的访问级别。与在特性声明中声明的属性不同,权限在每次操作时都会被检查。它们可能包括加密和身份验证要求。
Bluetooth SIG 已规范了 500 多个标准特性,涵盖了大多数常见的 BLE 使用场景。使用标准 UUID 可确保任何接收设备无需预先配置即可正确解释数据。
以下是最常用的标准特性:
| UUID | 名称 | 数据类型 | 服务 |
|---|---|---|---|
| 0x2A19 | Battery Level | uint8 (0–100%) | Battery Service |
| 0x2A37 | Heart Rate Measurement | uint8 + 标志 | Heart Rate |
| 0x2A6E | Temperature | int16 (0.01°C) | Environmental Sensing |
| 0x2A6F | Humidity | uint16 (0.01%) | Environmental Sensing |
| 0x2A00 | Device Name | UTF-8 string | Generic Access |
| 0x2A01 | Appearance | uint16 | Generic Access |
如果现有的标准特性涵盖了您的任务——请使用它。这简化了蓝牙认证并提高了与生态系统的兼容性。仅为 SIG 注册表中不存在的独特数据创建自定义特性。
特性的创建在 Peripheral 端进行——即提供数据的设备。让我们看看在 iOS(Swift)和 Android(Java)上的实现。
Core Bluetooth 提供 CBMutableCharacteristic 类,用于通过指定 UUID、属性和初始值来创建特性。
import CoreBluetooth
let characteristicUUID = CBUUID("2A19") // 电池电量特性
let characteristic = CBMutableCharacteristic(
type: characteristicUUID,
properties: [.read, .notify],
value: nil,
permissions: [.readable]
)
// 在更改时更新值
let batteryData = Data([batteryLevel]) // uint8
peripheralManager.updateValue(
batteryData,
for: characteristic,
onSubscribedCentrals: nil
)
在 Android 上,通过 BluetoothGattCharacteristic 指定 UUID、属性和权限来创建特性。
import android.bluetooth.*;
UUID charUuid = UUID.fromString("00002A19-0000-1000-8000-00805F9B34FB");
BluetoothGattCharacteristic characteristic =
new BluetoothGattCharacteristic(
charUuid,
BluetoothGattCharacteristic.PROPERTY_READ
| BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ
);
// 设置值
characteristic.setValue(batteryLevel, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
gattServer.notifyCharacteristicChanged(device, characteristic, false);
对 Characteristic 的操作分为三种类型:读取(read)、写入(write)和通知(notify/indicate)。操作的选择取决于场景:按需数据被读取,命令被写入,流式数据通过通知订阅。
Read——Central 发送读取特性值的请求。Peripheral 以当前值响应。该操作是同步的,需要双方的显式请求。用于很少更改的数据:固件版本、序列号、设置。
Write——Central 向 Peripheral 发送数据。有两种模式:Write with Response(来自 Peripheral 的确认)和 Write Without Response(无需确认)。Write with Response 保证交付——Peripheral 在写入后发送确认。Write Without Response 更快,但不保证交付。
Notify 和 Indicate——Peripheral 启动向 Central 发送数据。在 Notify 中,数据无需确认发送——如果 Central 未能接收数据包,它将丢失。在 Indicate 中,Central 发送确认(在 PDU 级别),从而保证交付。Indicate 较慢但更可靠。要订阅通知,Central 将值 0x0001 写入 CCCD(客户端特性配置描述符)。
MTU(最大传输单元)定义了单个 BLE 数据包的最大大小。默认情况下,MTU 为 23 字节,其中 3 字节为标头——有效载荷(ATT payload)为 20 字节。这对于大多数传感器数据来说已足够,但不足以传输文件或大型配置。
Bluetooth Core Specification 5.4 支持MTU 协商(MTU negotiation)——Central 和 Peripheral 可以协商更大的数据包大小,最高可达 517 字节。过程如下:Central 发送 MTU Exchange 请求,提议其 MTU;Peripheral 以其 MTU 响应;使用两者中较小的值。
// iOS 在连接时请求 MTU
// iOS 中的最大 MTU 为 185 字节
func peripheral(
_ peripheral: CBPeripheral,
didDiscoverServices error: Error?
) {
// 为特定外围设备请求 MTU
peripheral.maximumWriteValueLength(for: .withResponse)
}
根据Bluetooth SIG (2023),将 MTU 从 23 字节增加到 185 字节可将数据传输开销减少高达 80%,这是由于数据包数量减少。对于传输高频读数的应用(例如 ECG 或加速度计),增加 MTU 对数据流的稳定性至关重要。
常见问题
BLE 规范不限制服务中的特性数量。在实践中,限制由 GATT 服务器的可用内存和性能要求决定。对于嵌入式设备,建议每个服务不超过 10–15 个特性。
Notify 无需确认即可发送数据——数据包可能在未通知发送方的情况下丢失。Indicate 需要在协议级别确认(ACK),从而保证交付。Indicate 较慢但更可靠。对于关键数据(警报、命令),请使用 Indicate。
是的,特性可以具有属性组合。例如,设置特性可以支持 Read(读取当前值)和 Write(更改设置)。根据您的使用场景组合属性。
使用MTU 协商将数据包大小增加到 185–517 字节。如果数据仍然太大——在应用层实现分片:将数据分成多个带完整性控制的连续请求。
如果您的任务被标准特性覆盖——请使用来自 Bluetooth SIG 注册表的 UUID。这简化了认证并确保了与生态系统的兼容性。仅为第三方制造商的独特数据创建自定义 UUID。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。