描述符:它是什么、Client Characteristic Configuration及示例

作者: IT Sectr 发布日期: 2026-07-15 阅读时间: 8 分钟

描述符 — 是BLE特征的辅助属性,为其值提供元数据或配置。Bluetooth Core Specification 5.4将描述符定义为GATT概要的组成部分:它们描述计量单位、值范围、文本名称并管理通知订阅。最著名的描述符是Client Characteristic Configuration Descriptor (CCCD,0x2902),它允许Central订阅来自特征的通知。据Bluetooth SIG报告,已规范了8个标准描述符,开发者可以为任何额外元数据创建自定义描述符。

主要要点

  • 描述符 — 特征的辅助属性,包含元数据或值配置。
  • CCCD (0x2902) — 最重要的描述符:通过它,Central订阅特征变更的通知。
  • 标准描述符包括文本名称的User Description (0x2901)和数据格式的Presentation Format (0x2904)。
  • 每个特征可以有多个描述符,但每种标准类型不超过一个。
  • 描述符由Core Bluetooth自动创建,但可以为特定元数据自定义

BLE中的描述符是什么?

描述符 — 是GATT协议的属性,附加到特征上并提供关于其值或使用方式的额外信息。在GATT术语中,特征是数据,而描述符是这些数据的元数据。

每个特征可以有零个或更多描述符。描述符在GATT表中定义为单独的属性,并在Bluetooth SIG空间中拥有自己的16位UUID。描述符不能独立存在 — 它们始终绑定到特定的特征。

Bluetooth Core Specification 5.4 (2023),描述符分为两类:标准(由Bluetooth SIG定义)和自定义(由开发者定义)。标准描述符的UUID在0x2900–0x2908范围内,执行严格定义的功能。自定义描述符使用128位UUID,类似于自定义服务和特征。

描述符是BLE连接行为配置的关键机制。没有CCCD (0x2902)无法订阅通知,没有Presentation Format (0x2904) Central将不知道如何解释特征的原始字节。

Client Characteristic Configuration Descriptor (CCCD)

CCCD (UUID 0x2902)是BLE中最重要且最广泛使用的描述符。它管理Central对特征通知(Notify)和确认通知(Indicate)的订阅。未向CCCD写入时,即使特征具有Notify属性,也不会发送通知。

CCCD是一个16位值,其中最低位(0x0001)启用Notify,第二位(0x0002)启用Indicate。Central向CCCD写入所需值,从而订阅通知。如果Central写入0x0000— —订阅被取消。

CCCD的工作机制如下:当Central检测到支持Notify的特征时,它找到其CCCD描述符并写入0x0001。此后,每当Peripheral更新特征值时,该值会通过Handle Value Notification自动发送给已订阅的Central(无需Central请求)。

Apple Core Bluetooth Programming Guide报告,当为特征调用setNotifyValue时,CCD由系统自动管理。开发者无需手动查找和写入CCCD — Core Bluetooth在激活通知时自动完成此操作。

程序化订阅通知

iOS中,订阅通过CBPeripheral对象上的setNotifyValue方法执行。

swift
import CoreBluetooth

// 订阅特征通知
peripheral.setNotifyValue(true, for: characteristic)

// 委托接收更新后的值
func peripheral(
    _ peripheral: CBPeripheral,
    didUpdateValueFor characteristic: CBCharacteristic,
    error: Error?
) {
    // characteristic.value有新数据
    guard let data = characteristic.value else { return }
}

Android上,订阅通知通过BluetoothGatt.setCharacteristicNotification执行。开发者还必须手动将值0x0001写入CCCD。

java
import android.bluetooth.*;

// 启用通知
bluetoothGatt.setCharacteristicNotification(characteristic, true);

// 将0x0001写入CCCD
BluetoothGattDescriptor descriptor = characteristic
    .getDescriptor(
        UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
    );
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);

Bluetooth SIG标准描述符

Bluetooth SIG已定义8个标准描述符,用于常见的特征配置任务。每个描述符都有严格定义的UUID和值格式。

UUID描述符名称用途值类型
0x2900Characteristic Extended Properties特征的附加属性uint16(位掩码)
0x2901Characteristic User Description特征的文本名称UTF-8字符串
0x2902Client Characteristic Configuration管理通知uint16
0x2903Server Characteristic Configuration广播服务器配置uint16
0x2904Characteristic Presentation Format数据呈现格式结构体(7字节)
0x2905Characteristic Aggregate Format合并多个特征UUID列表
0x2906Valid Range允许值范围uint16 × 2 (min, max)
0x2907External Report Reference引用外部报告uint16
0x2908Report Reference引用内部报告uint8 + uint16

Characteristic User Description (0x2901)对UI特别有用:它包含可以在应用界面中显示的人可读特征名称。例如,特征Battery Level可以具有值为“电池充电水平”的User Description描述符。

Characteristic Presentation Format (0x2904)包含关于如何解释特征值的信息:格式(uint8, uint16, float)、指数、计量单位(通过来自Bluetooth SIG注册表的UUID)、名称空间和描述。例如,温度可以是int16,指数为-2(分度值0.01°C),计量单位为“摄氏度”。

如何在iOS和Android中使用描述符

访问描述符在iOS和Android上不同。Core Bluetooth在启用通知时自动管理CCCD,而Android需要手动将值写入描述符。让我们看看这两种方法。

iOS:自动管理CCCD

iOS中,开发者通常不直接与描述符交互。Core Bluetooth自动查找CCCD并在调用setNotifyValue时写入所需值。要读取描述符,使用discoverDescriptors方法。

swift
// 发现描述符
peripheral.discoverDescriptors(for: characteristic)

// 读取User Description值
func peripheral(
    _ peripheral: CBPeripheral,
    didDiscoverDescriptorsFor characteristic: CBCharacteristic,
    error: Error?
) {
    for descriptor in characteristic.descriptors ?? [] {
        if descriptor.uuid == CBUUID("2901") {
            peripheral.readValue(for: descriptor)
        }
    }
}

Android:手动管理CCCD

Android上,开发者必须自行找到特征的CCCD描述符并写入值以启用通知。与iOS相比,这是一个额外步骤。

java
// 读取User Description描述符值
BluetoothGattDescriptor userDesc = characteristic
    .getDescriptor(
        UUID.fromString("00002901-0000-1000-8000-00805F9B34FB")
    );

if (userDesc != null) {
    bluetoothGatt.readDescriptor(userDesc);
}

创建自定义描述符

自定义描述符在标准Bluetooth SIG描述符不足时使用。例如,医疗传感器制造商可以添加具有传感器校准信息的描述符或带有错误日志的描述符。

自定义描述符使用128位UUID创建,类似于自定义特征。在Peripheral端,开发者通过相应API将其添加到特征。在Central端,描述符在调用discoverDescriptors时自动发现。

创建自定义描述符时请遵守规则:值的长度必须与预期数据类型匹配,访问权限(read/write)必须明确指定。不要将标准Bluetooth SIG描述符UUID范围(0x2900–0x2908)中的UUID用于自定义目的。

描述符与特征的区别

特征和描述符 — 是GATT属性的不同层级。特征是数据点,描述符是其元数据或配置。差异体现在几个方面:用途、UUID和访问规则。

特征有必要声明(declaration),始终位于GATT表中。描述符是可选的 — 特征可以没有描述符。特征可以独立读取、写入或发送通知。描述符始终绑定到特征,不能单独存在。

Bluetooth Core Specification 5.4,在GATT表中属性的顺序如下:服务声明、特征声明、特征值、特征描述符(如果有),然后是下一个服务。这种顺序对于GATT客户端的正确运作是必不可少的。

常见问题

如果特征已具有Notify属性,为什么还需要CCCD?

CCCD用于管理订阅:Notify属性只表示特征可以发送通知,但不会启用它们。Central必须通过向CCCD写入0x0001来明确订阅。这防止了不必要的数据发送到未准备好的Central。

一个特征可以有多少个描述符?

规范没有限制描述符的数量。实际上,每个特征通常有1–3个描述符:CCCD(用于具有Notify/Indicate的特征)、可选的User Description和Presentation Format。过多的描述符会增大GATT表的尺寸。

是否需要在Peripheral端手动创建描述符?

在大多数情况下不需要。iOS和Android上的Core Bluetooth会自动将CCCD添加到具有Notify或Indicate属性的特征。自定义描述符仅为特定元数据手动创建。

可以向CCCD写入自定义数据吗?

不能,CCCD有严格定义的格式(uint16)和用途 — 管理通知。写入其他值会违反Bluetooth规范,可能导致订阅不能工作。对于自定义数据,请使用具有128位UUID的自定义描述符。

Characteristic User Description对应用程序有什么用?

User Description包含人可读的特征名称 — 例如,“机笼温度”代暿UUID 0x2A6E。应用程序可以在界面中显示这个名称,使用户无需硬编码字符串即可理解与BLE设备的交互。

总结

  • 描述符 — 附加到特征的辅助GATT属性,用于存储元数据或配置。
  • CCCD (0x2902) — 关键描述符,管理Central对特征通知和确认通知的订阅。
  • Bluetooth SIG规范了8个标准描述符 (0x2900–0x2908),用于典型任务 — 描述、格式化和配置。
  • iOS中,CCCD自动管理,在Android上需要手动写入值0x0001以启用通知。
  • 自定义描述符使用128位UUID创建,用于标准描述符未覆盖的独特元数据。
  • 描述符不能独立存在 — 它们始终绑定到特征,并在GATT表中随之出现。
  • 正确使用描述符可确伝·BLE连接的正确配置和数据对应用程序的可理解性。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读