Descriptor는 BLE 특성(Characteristic)의 보조 속성으로, 해당 값에 대한 메타데이터 또는 구성을 제공합니다. Bluetooth Core Specification 5.4는 디스크립터를 GATT 프로파일의 필수적인 부분으로 정의합니다: 측정 단위, 값 범위, 텍스트 이름을 설명하고 알림 구독을 관리합니다. 가장 잘 알려진 디스크립터는 Client Characteristic Configuration Descriptor(CCCD, 0x2902)로, Central이 특성의 알림을 구독할 수 있게 합니다. Bluetooth SIG에 따르면 8개의 표준 디스크립터가 지정되어 있으며, 개발자는 추가 메타데이터를 위해 사용자 정의 디스크립터를 만들 수 있습니다.
핵심 요점
Descriptor는 GATT 프로토콜의 속성으로, Characteristic에 첨부되어 해당 값이나 사용 방법에 대한 추가 정보를 제공합니다. GATT 용어에서 특성은 데이터이고, 디스크립터는 해당 데이터의 메타데이터입니다.
각 Characteristic은 0개 이상의 디스크립터를 가질 수 있습니다. 디스크립터는 GATT 테이블에서 별도의 속성으로 정의되며 Bluetooth SIG 공간에 고유한 16비트 UUID를 가집니다. 디스크립터는 독립적으로 존재할 수 없으며 항상 특정 특성에 바인딩됩니다.
Bluetooth Core Specification 5.4(2023)에 따르면 디스크립터는 표준(Bluetooth SIG 정의)과 사용자 정의(개발자 정의)의 두 가지 범주로 나뉩니다. 표준 디스크립터는 0x2900–0x2908 범위의 UUID를 가지며 엄격하게 정의된 기능을 수행합니다. 사용자 정의 디스크립터는 사용자 정의 서비스 및 특성과 유사하게 128비트 UUID를 사용합니다.
디스크립터는 BLE 연결의 동작을 구성하는 핵심 메커니즘입니다. CCCD(0x2902)가 없으면 알림을 구독할 수 없고, Presentation Format(0x2904)이 없으면 Central이 특성의 원시 바이트를 해석할 수 없습니다.
CCCD(UUID 0x2902)는 BLE에서 가장 중요하고 널리 사용되는 디스크립터입니다. 특성에서 Notify 및 Indicate에 대한 Central의 구독을 관리합니다. 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가 호출되면 CCCD는 시스템에 의해 자동으로 관리됩니다. 개발자가 수동으로 CCCD를 찾아 쓸 필요가 없습니다. Core Bluetooth가 알림 활성화 시 자동으로 수행합니다.
iOS에서는 CBPeripheral 객체의 setNotifyValue 메서드를 통해 구독합니다.
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을 통해 알림을 구독합니다. 개발자는 수동으로 CCCD에 값 0x0001을 써야 합니다.
import android.bluetooth.*;
// 알림 활성화
bluetoothGatt.setCharacteristicNotification(characteristic, true);
// CCCD에 0x0001 쓰기
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
Bluetooth SIG는 일반적인 특성 구성 작업을 위해 8개의 표준 디스크립터를 정의했습니다. 각 디스크립터는 엄격하게 정의된 UUID와 값 형식을 가집니다.
| UUID | 디스크립터 이름 | 목적 | 값 유형 |
|---|---|---|---|
| 0x2900 | Characteristic Extended Properties | 특성의 추가 속성 | uint16 (비트 마스크) |
| 0x2901 | Characteristic User Description | 특성의 텍스트 이름 | UTF-8 문자열 |
| 0x2902 | Client Characteristic Configuration | 알림 관리 | uint16 |
| 0x2903 | Server Characteristic Configuration | 브로드캐스트용 서버 구성 | uint16 |
| 0x2904 | Characteristic Presentation Format | 데이터 표시 형식 | 구조체 (7바이트) |
| 0x2905 | Characteristic Aggregate Format | 여러 특성 결합 | UUID 목록 |
| 0x2906 | Valid Range | 유효 값 범위 | uint16 × 2 (최소, 최대) |
| 0x2907 | External Report Reference | 외부 보고서 참조 | uint16 |
| 0x2908 | Report Reference | 내부 보고서 참조 | uint8 + uint16 |
Characteristic User Description(0x2901)은 UI에 특히 유용합니다: 애플리케이션 인터페이스에 표시할 수 있는 사람이 읽을 수 있는 특성 이름을 포함합니다. 예를 들어, Battery Level 특성에는 “배터리 충전 수준” 값의 User Description 디스크립터가 있을 수 있습니다.
Characteristic Presentation Format(0x2904)은 특성 값 해석 방법에 대한 정보를 포함합니다: 형식(uint8, uint16, float), 지수, 측정 단위(Bluetooth SIG 레지스트리의 UUID 통해), 네임스페이스 및 설명. 예를 들어, 온도는 지수 -2(분할 값 0.01°C)와 측정 단위 “섭씨”의 int16일 수 있습니다.
디스크립터에 대한 액세스는 iOS와 Android에서 다릅니다. Core Bluetooth는 알림이 활성화될 때 CCCD를 자동으로 관리하는 반면, Android는 디스크립터에 값을 수동으로 써야 합니다. 두 접근 방식을 살펴보겠습니다.
iOS에서 개발자는 일반적으로 디스크립터와 직접 상호작용하지 않습니다. setNotifyValue가 호출되면 Core Bluetooth가 자동으로 CCCD를 찾아 필요한 값을 씁니다. 디스크립터를 읽으려면 discoverDescriptors 메서드를 사용합니다.
// 디스크립터 발견
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 디스크립터를 찾아 알림을 활성화하기 위해 값을 써야 합니다. 이는 iOS에 비해 추가 단계입니다.
// 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를 호출하면 자동으로 발견됩니다.
사용자 정의 디스크립터를 만들 때 다음 규칙을 따르세요: 값의 길이가 예상 데이터 유형과 일치해야 하며, 액세스 권한(읽기/쓰기)이 명시적으로 지정되어야 합니다. 사용자 정의 목적으로 Bluetooth SIG 표준 디스크립터 범위(0x2900–0x2908)의 UUID를 사용하지 마십시오.
특성과 디스크립터는 GATT 속성의 다른 수준입니다. 특성은 데이터 포인트이고, 디스크립터는 그 메타데이터 또는 구성입니다. 차이점은 목적, UUID 및 액세스 규칙 등 여러 측면에서 나타납니다.
특성에는 GATT 테이블에 항상 존재하는 필수 선언이 있습니다. 디스크립터는 선택 사항이며 특성에 디스크립터가 없을 수도 있습니다. 특성은 독립적으로 읽기, 쓰기 또는 알림 전송이 가능합니다. 디스크립터는 항상 특성에 바인딩되며 별도로 존재하지 않습니다.
Bluetooth Core Specification 5.4에 따르면 GATT 테이블의 속성 순서는 다음과 같습니다: 서비스 선언, 특성 선언, 특성 값, 특성 디스크립터(있는 경우), 다음 서비스. 이 순서는 GATT 클라이언트의 올바른 작동을 위해 필수입니다.
자주 묻는 질문
CCCD는 구독 관리에 필요합니다: Notify 속성은 특성이 알림을 보낼 수 있음을 나타낼 뿐 활성화하지는 않습니다. Central은 CCCD에 0x0001을 써서 명시적으로 구독해야 합니다. 이는 준비되지 않은 Central에 원치 않는 데이터가 전송되는 것을 방지합니다.
사양은 디스크립터 수를 제한하지 않습니다. 실제로 각 특성은 일반적으로 1~3개의 디스크립터를 가집니다: CCCD(Notify/Indicate가 있는 특성용), 선택적으로 User Description 및 Presentation Format. 디스크립터가 너무 많으면 GATT 테이블 크기가 증가합니다.
대부분의 경우 아니요. iOS 및 Android의 Core Bluetooth는 Notify 또는 Indicate 속성이 있는 특성에 자동으로 CCCD를 추가합니다. 사용자 정의 디스크립터는 특정 메타데이터에 대해서만 수동으로 생성됩니다.
아니요, CCCD는 엄격하게 정의된 형식(uint16)과 목적(알림 관리)이 있습니다. 다른 값을 쓰면 Bluetooth 사양을 위반하고 구독이 작동을 멈출 수 있습니다. 사용자 정의 데이터에는 128비트 UUID의 사용자 정의 디스크립터를 사용하세요.
User Description에는 특성의 사람이 읽을 수 있는 이름이 포함됩니다. 예를 들어, UUID 0x2A6E 대신 “장치 온도”로 표시할 수 있습니다. 애플리케이션은 이 이름을 인터페이스에 표시하여 하드코딩된 문자열 없이 BLE 장치와의 상호작용을 사용자가 이해할 수 있게 합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.