Descriptor es un atributo auxiliar de una característica BLE que proporciona metadatos o configuración para su valor. La Bluetooth Core Specification 5.4 define los descriptores como una parte integral del perfil GATT: describen unidades de medida, rangos de valores, nombres de texto y gestionan la suscripción a notificaciones. El descriptor más conocido es el Client Characteristic Configuration Descriptor (CCCD, 0x2902), que permite al Central suscribirse a notificaciones de la característica. Según Bluetooth SIG, hay 8 descriptores estándar especificados, y los descriptores personalizados pueden ser creados por el desarrollador para cualquier metadato adicional.
Puntos clave
Descriptor es un atributo del protocolo GATT que se adjunta a una Characteristic y proporciona información adicional sobre su valor o forma de uso. En la terminología GATT, la característica son los datos, y el descriptor son los metadatos de esos datos.
Cada Characteristic puede tener cero o más descriptores. Los descriptores se definen como atributos separados en la tabla GATT y tienen sus propios UUID de 16 bits en el espacio de Bluetooth SIG. Los descriptores no pueden existir de forma independiente — siempre están vinculados a una característica específica.
Según la Bluetooth Core Specification 5.4 (2023), los descriptores se dividen en dos categorías: estándar (definidos por Bluetooth SIG) y personalizados (definidos por el desarrollador). Los descriptores estándar tienen UUID en el rango 0x2900–0x2908 y realizan funciones estrictamente definidas. Los descriptores personalizados usan UUID de 128 bits, similares a los servicios y características personalizados.
Los descriptores son un mecanismo clave para configurar el comportamiento de una conexión BLE. Sin CCCD (0x2902) es imposible suscribirse a notificaciones, sin Presentation Format (0x2904) el Central no sabrá cómo interpretar los bytes brutos de la característica.
CCCD con UUID 0x2902 es el descriptor más importante y ampliamente utilizado en BLE. Gestiona la suscripción del Central a Notify e Indicate de la característica. Sin escribir en CCCD, la característica no enviará notificaciones, incluso si tiene la propiedad Notify.
CCCD es un valor de 16 bits donde el bit menos significativo (0x0001) habilita Notify, y el segundo bit (0x0002) habilita Indicate. El Central escribe el valor deseado en CCCD, suscribiéndose así a las notificaciones. Si el Central escribe 0x0000 — la suscripción se cancela.
El mecanismo de CCCD funciona así: cuando el Central descubre una característica que soporta Notify, encuentra su descriptor CCCD y escribe 0x0001. Después de eso, cada vez que el Peripheral actualiza el valor de la característica, se envía automáticamente al Central suscrito mediante Handle Value Notification (sin solicitud del Central).
Según la Apple Core Bluetooth Programming Guide, CCCD es gestionado automáticamente por el sistema cuando se llama a setNotifyValue para una característica. El desarrollador no necesita buscar y escribir manualmente CCCD — Core Bluetooth lo hace automáticamente al activar las notificaciones.
En iOS, la suscripción se realiza mediante el método setNotifyValue en el objeto CBPeripheral.
import CoreBluetooth
// Suscribirse a notificaciones de la característica
peripheral.setNotifyValue(true, for: characteristic)
// El delegado recibe valores actualizados
func peripheral(
_ peripheral: CBPeripheral,
didUpdateValueFor characteristic: CBCharacteristic,
error: Error?
) {
// characteristic.value tiene nuevos datos
guard let data = characteristic.value else { return }
}
En Android, la suscripción a notificaciones se realiza mediante BluetoothGatt.setCharacteristicNotification. El desarrollador también debe escribir manualmente el valor 0x0001 en CCCD.
import android.bluetooth.*;
// Habilitar notificaciones
bluetoothGatt.setCharacteristicNotification(characteristic, true);
// Escribir 0x0001 en CCCD
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
Bluetooth SIG ha definido 8 descriptores estándar para tareas comunes de configuración de características. Cada descriptor tiene un UUID y formato de valor estrictamente definidos.
| UUID | Nombre del descriptor | Propósito | Tipo de valor |
|---|---|---|---|
| 0x2900 | Characteristic Extended Properties | Propiedades adicionales de la característica | uint16 (máscara de bits) |
| 0x2901 | Characteristic User Description | Nombre textual de la característica | Cadena UTF-8 |
| 0x2902 | Client Characteristic Configuration | Gestión de notificaciones | uint16 |
| 0x2903 | Server Characteristic Configuration | Configuración del servidor para broadcast | uint16 |
| 0x2904 | Characteristic Presentation Format | Formato de presentación de datos | Estructura (7 bytes) |
| 0x2905 | Characteristic Aggregate Format | Combinación de múltiples características | Lista de UUIDs |
| 0x2906 | Valid Range | Rango de valores válidos | uint16 × 2 (min, max) |
| 0x2907 | External Report Reference | Referencia a informe externo | uint16 |
| 0x2908 | Report Reference | Referencia a informe interno | uint8 + uint16 |
Characteristic User Description (0x2901) es especialmente útil para la interfaz de usuario: contiene un nombre legible de la característica que se puede mostrar en la interfaz de la aplicación. Por ejemplo, una característica Battery Level puede tener un descriptor User Description con el valor “Nivel de carga de la batería”.
Characteristic Presentation Format (0x2904) contiene información sobre cómo interpretar el valor de la característica: formato (uint8, uint16, float), exponente, unidad de medida (mediante UUID del registro de Bluetooth SIG), espacio de nombres y descripción. Por ejemplo, la temperatura puede ser int16 con exponente -2 (valor de división 0.01°C) y unidad de medida “grado Celsius”.
El acceso a los descriptores difiere en iOS y Android. Core Bluetooth gestiona automáticamente CCCD cuando se activan las notificaciones, mientras que Android requiere escritura manual del valor en el descriptor. Veamos ambos enfoques.
En iOS, el desarrollador normalmente no interactúa directamente con los descriptores. Core Bluetooth encuentra automáticamente CCCD y escribe el valor requerido cuando se llama a setNotifyValue. Para leer descriptores se usa el método discoverDescriptors.
// Descubrir descriptores
peripheral.discoverDescriptors(for: characteristic)
// Leer el valor de 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)
}
}
}
En Android, el desarrollador debe encontrar el descriptor CCCD de la característica y escribir el valor para activar las notificaciones. Este es un paso adicional en comparación con iOS.
// Leer el valor del descriptor User Description
BluetoothGattDescriptor userDesc = characteristic
.getDescriptor(
UUID.fromString("00002901-0000-1000-8000-00805F9B34FB")
);
if (userDesc != null) {
bluetoothGatt.readDescriptor(userDesc);
}
Los descriptores personalizados se utilizan cuando los descriptores estándar de Bluetooth SIG no son suficientes. Por ejemplo, un fabricante de sensores médicos podría añadir un descriptor con información de calibración del sensor o un descriptor con un registro de errores.
Un descriptor personalizado se crea con un UUID de 128 bits, similar a una característica personalizada. En el lado del Peripheral, el desarrollador lo añade a la característica mediante la API correspondiente. En el lado del Central, el descriptor se descubre automáticamente al llamar a discoverDescriptors.
Al crear un descriptor personalizado, siga estas reglas: la longitud del valor debe coincidir con el tipo de datos esperado, y los derechos de acceso (lectura/escritura) deben especificarse explícitamente. No use UUID del rango de descriptores estándar de Bluetooth SIG (0x2900–0x2908) para fines personalizados.
Characteristic y descriptor son diferentes niveles de atributos GATT. Una característica es un punto de datos, mientras que un descriptor son sus metadatos o configuración. La diferencia se manifiesta en varios aspectos: propósito, UUID y reglas de acceso.
Una característica tiene una declaración obligatoria que siempre está presente en la tabla GATT. Un descriptor es opcional — una característica puede no tener descriptores. Una característica puede leerse, escribirse o enviar notificaciones de forma independiente. Un descriptor siempre está vinculado a una característica y no existe por separado.
Según la Bluetooth Core Specification 5.4, el orden de los atributos en la tabla GATT es el siguiente: declaración del servicio, declaración de la característica, valor de la característica, descriptores de la característica (si los hay), luego el siguiente servicio. Este orden es obligatorio para el correcto funcionamiento de los clientes GATT.
Preguntas frecuentes
CCCD es necesario para la gestión de suscripciones: la propiedad Notify solo indica que la característica puede enviar notificaciones, pero no las activa. El Central debe suscribirse explícitamente escribiendo 0x0001 en CCCD. Esto evita el envío no deseado de datos a un Central no preparado.
La especificación no limita el número de descriptores. En la práctica, cada característica suele tener 1–3 descriptores: CCCD (para características con Notify/Indicate), opcionalmente User Description y Presentation Format. Demasiados descriptores aumentan el tamaño de la tabla GATT.
En la mayoría de los casos, no. Core Bluetooth en iOS y Android añade automáticamente CCCD a las características que tienen propiedades Notify o Indicate. Los descriptores personalizados se crean manualmente solo para metadatos específicos.
No, CCCD tiene un formato (uint16) y propósito estrictamente definidos — la gestión de notificaciones. Escribir otros valores viola la especificación Bluetooth y puede provocar que la suscripción deje de funcionar. Para datos personalizados, use descriptores personalizados con UUID de 128 bits.
La User Description contiene un nombre legible de la característica — por ejemplo, “Temperatura del dispositivo” en lugar del UUID 0x2A6E. La aplicación puede mostrar este nombre en la interfaz, haciendo que la interacción con el dispositivo BLE sea comprensible para el usuario sin cadenas codificadas.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también