GATT (Generic Attribute Profile) ist ein Bluetooth-Low-Energy-Profil (BLE), das die Datenstruktur und die Regeln für den Informationsaustausch zwischen BLE-Geräten definiert. GATT ist auf dem Attribute Protocol (ATT) aufgebaut und organisiert Daten in einer Hierarchie: Dienste (Services), Merkmale (Characteristics) und Deskriptoren (Descriptors). Laut Bluetooth SIG (2025) wird das GATT-Profil in 98 % aller BLE-Anwendungen verwendet – von Fitness-Trackern über intelligente Schlösser bis hin zu medizinischen Sensoren.
Wichtigste Punkte
GATT (Generic Attribute Profile) ist ein Bluetooth-Low-Energy-Profil (BLE), das definiert, wie zwei BLE-Geräte Daten über das Attribute Protocol (ATT) austauschen. GATT standardisiert die Datenstruktur: Alle Daten sind in einer Hierarchie aus „Dienst → Merkmal → Deskriptor“ organisiert. Das Profil wurde zusammen mit BLE in der Bluetooth-4.0-Spezifikation (2010) eingeführt und ist seitdem der primäre Datenübertragungsmechanismus für energieeffiziente Bluetooth-Geräte. Im Gegensatz zum klassischen Bluetooth, bei dem Daten über eine serielle Schnittstelle (SPP) übertragen werden, bietet GATT einen strukturierten Zugriff auf Daten durch Lese-, Schreib- und Benachrichtigungsoperationen.
Der BLE-Stack besteht aus mehreren Schichten: Physical Layer (Funk), Link Layer (Verbindungsverwaltung), L2CAP (logische Kanalsteuerung), ATT (Attribute Protocol – Zugriff auf Attribute) und GATT (auf ATT basierendes Profil). GATT ist die oberste Schicht, mit der Anwendungsentwickler arbeiten. Das darunterliegende ATT bietet grundlegende Operationen: Lesen, Schreiben, Benachrichtigen und Anzeigen von Attributen. GATT fügt Semantik hinzu: Es definiert, was ein Dienst und ein Merkmal sind, wie sie gruppiert werden und welche Regeln beim Lesen und Schreiben gelten. Laut der Bluetooth Core Specification 5.4 (2023) unterstützt GATT bis zu 65.535 Attribute (Dienste + Merkmale + Deskriptoren) auf einem einzigen Gerät.
Die GATT-Hierarchie besteht aus drei Ebenen. Ein Dienst ist eine logische Gruppe von Merkmalen, die eine Aufgabe löst (z. B. „Batteriedienst“ oder „Herzfrequenzdienst“). Ein Merkmal ist eine Dateneinheit mit einem bekannten Typ: aktueller Batteriestand, Sensorwert, Schalterzustand. Jedes Merkmal hat einen Wert und einen oder mehrere Deskriptoren, die Metadaten beschreiben: Maßeinheiten, Benachrichtigungseinstellungen, Wertebereich. Eine UUID (Universally Unique Identifier) identifiziert eindeutig jeden Dienst und jedes Merkmal.
GATT unterstützt vier Arten von Operationen zur Interaktion mit Merkmalen. Read – der Client fordert den aktuellen Wert eines Merkmals vom Server an. Write – der Client sendet einen neuen Wert an den Server. Notify – der Server sendet einen Wert ohne Bestätigung an den Client (schneller, aber weniger zuverlässig). Indicate – der Server sendet einen Wert mit Empfangsbestätigung (zuverlässiger, aber langsamer). Der Entwickler wählt den Typ basierend auf dem Szenario: Für Herzfrequenzsensorwerte ist Notify ausreichend; zum Schreiben der Konfiguration eines intelligenten Schlosses ist Write mit Bestätigung erforderlich.
// GATT-Datenstruktur in Android-Code
data class BleService(
val uuid: UUID,
val characteristics: List<BleCharacteristic>
)
data class BleCharacteristic(
val uuid: UUID,
val properties: Int, // READ, WRITE, NOTIFY, INDICATE
val descriptors: List<BleDescriptor>,
var value: ByteArray?
)
Die BLE-Spezifikation definiert zwei Hauptprofile: GAP (Generic Access Profile) und GATT (Generic Attribute Profile). GAP ist für die Geräteerkennung, Verbindungsherstellung und Sichtbarkeitsverwaltung verantwortlich – es ist die „Netzwerkschicht“ von BLE. GATT ist für den Datenaustausch nach der Verbindungsherstellung verantwortlich – die „Anwendungsschicht“. Der Entwickler verwendet GAP zum Scannen und Verbinden mit einem Gerät und GATT zum Lesen, Schreiben und Empfangen von Benachrichtigungen vom verbundenen Gerät.
| Merkmal | GAP | GATT |
|---|---|---|
| Zweck | Erkennung und Verbindung | Datenaustausch |
| Rollen | Central / Peripheral | Client / Server |
| Protokoll | HCI, Link Layer | ATT (Attribute Protocol) |
| Phase | Vor der Verbindung | Nach der Verbindung |
| Hauptklasse | BluetoothAdapter | BluetoothGatt |
GATT definiert zwei Rollen: GATT-Server und GATT-Client. Der Server ist ein Gerät, das Daten bereitstellt (z. B. ein Fitness-Tracker, der Herzfrequenzdaten sendet). Der Client ist ein Gerät, das Daten anfordert (z. B. ein Smartphone, das die Daten liest). In den meisten Szenarien fungiert die Android-App als GATT-Client und das BLE-Peripheral als GATT-Server. Android kann jedoch auch ein GATT-Server sein – beispielsweise wenn eine App ein BLE-Gerät für andere Geräte emuliert. Die Rolle wird in der Einrichtungsphase der GATT-Verbindung festgelegt und ändert sich während der Sitzung nicht.
Der GATT-Kommunikationsprozess beginnt nach dem Herstellen der BLE-Verbindung zwischen den Geräten. Zuerst entdeckt der GATT-Client die Dienste auf dem GATT-Server durch Service Discovery – Android führt dies automatisch beim Verbinden über BluetoothGatt.discoverServices() durch. Nach der Erkennung erhält der Client eine Liste der verfügbaren Dienste, Merkmale und Deskriptoren. Anschließend kann der Client Merkmalswerte lesen (Read), neue Werte schreiben (Write) oder Benachrichtigungen abonnieren (Set Notify/Indicate). Der GATT-Server kann jederzeit nach dem Herstellen der Verbindung Notify/Indicate an den Client senden.
Standardmäßig beträgt die Größe eines einzelnen GATT-Pakets (MTU) in BLE 23 Byte, davon 3 Byte ATT-Header und 20 Byte Nutzdaten. Wenn die Anwendung mehr Daten übertragen muss (z. B. OTA-Firmware-Update), kann die MTU über requestMtu() in Android auf bis zu 517 Byte erhöht werden. Eine erhöhte MTU reduziert die Anzahl der Pakete, die zum Übertragen eines Datenblocks erforderlich sind – statt 50 kleiner Pakete können 2 große gesendet werden, was den Stromverbrauch senkt und die Übertragung beschleunigt. Die maximale MTU hängt von der BLE-Version und den Chip-Fähigkeiten ab – Bluetooth 5.0 unterstützt bis zu 517 Byte, ältere Versionen bis zu 247 Byte.
// Merkmalbenachrichtigungen abonnieren
fun enableNotifications(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
gatt.setCharacteristicNotification(characteristic, true)
// CCCD (Client Characteristic Configuration Descriptor) aktivieren
val cccdUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
val descriptor = characteristic.getDescriptor(cccdUuid)
descriptor?.let {
it.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
gatt.writeDescriptor(it)
}
}
Um Benachrichtigungen vom GATT-Server auf Android zu empfangen, müssen Sie den Rückruf BluetoothGattCallback.onCharacteristicChanged() implementieren. In dieser Methode erhält die App den aktualisierten Merkmalswert jedes Mal, wenn der Server Notify oder Indicate sendet. Für die Echtzeit-Datenverarbeitung verwenden Sie einen Puffer und Kotlin-Koroutinen – dies verhindert das Blockieren des UI-Threads bei intensiven Benachrichtigungen (z. B. mehr als 100 Herzfrequenzmessungen pro Sekunde). Bei Indicationen müssen Sie auf der Serverseite gatt.sendResponse() aufrufen – auf dem Android-Client wird dies automatisch behandelt.
Auf Android wird die Arbeit mit GATT über die Klassen des Pakets android.bluetooth implementiert: BluetoothGatt (Verbindung), BluetoothGattService (Dienst), BluetoothGattCharacteristic (Merkmal) und BluetoothGattDescriptor (Deskriptor). Die Verbindung zu einem BLE-Gerät beginnt mit dem Aufruf von BluetoothDevice.connectGatt() – diese Methode gibt ein BluetoothGatt zurück, über das alle weiteren Operationen ausgeführt werden. Alle GATT-Rückrufe kommen in BluetoothGattCallback an – dies ist eine asynchrone Schnittstelle, die im selben Thread aufgerufen wird, in dem BluetoothGatt erstellt wurde. Wichtig: Alle GATT-Operationen müssen sequenziell ausgeführt werden – der gleichzeitige Aufruf mehrerer Operationen auf demselben BluetoothGatt führt zu Fehlern.
Die ordnungsgemäße Verwaltung des GATT-Verbindungslebenszyklus ist entscheidend für die Stabilität der BLE-App. Nach dem Aufruf von connectGatt() wartet die App auf den Rückruf onConnectionStateChange() mit dem Status STATE_CONNECTED. Dann startet das System automatisch Service Discovery, nach dessen Abschluss onServicesDiscovered() aufgerufen wird. Erst danach können Sie lesen, schreiben und abonnieren. Rufen Sie beim Beenden immer gatt.close() in onDestroy() oder onPause() auf – nicht geschlossene GATT-Verbindungen verbrauchen Batterie und können die erneute Verbindung zum selben Gerät auf Android blockieren.
// Über GATT mit BLE-Gerät verbinden
private val gattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(
gatt: BluetoothGatt, status: Int, newState: Int
) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices()
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
val service = gatt.getService(UUID.fromString("180D"))
val characteristic = service?.getCharacteristic(
UUID.fromString("2A37")
)
characteristic?.let { enableNotifications(gatt, it) }
}
}
Bluetooth SIG definiert Dutzende von Standard-GATT-Profilen und -Diensten mit festen 16-Bit-UUIDs. Die häufigsten: Battery Service (UUID 180F, Merkmal Battery Level 2A19), Heart Rate-Dienst (UUID 180D, Merkmal Heart Rate Measurement 2A37), Device Information-Dienst (UUID 180A, Merkmale Manufacturer Name und Serial Number). Die Verwendung von Standarddiensten garantiert Kompatibilität zwischen Geräten verschiedener Hersteller – jedes Fitnessarmband mit einem Heart Rate-Dienst sollte mit jeder Android-App funktionieren, die ihn unterstützt.
Wenn Standarddienste die Aufgabe nicht abdecken, kann der Entwickler benutzerdefinierte GATT-Dienste mit 128-Bit-UUIDs erstellen. Beim Entwerfen eines benutzerdefinierten Dienstes müssen Sie: eine logische Gruppe von Merkmalen definieren (z. B. „Schlosssteuerungsdienst“), jedem Merkmal die richtigen Eigenschaften (Read, Write, Notify) zuweisen, zulässige Werte und Maßeinheiten über den Deskriptor Characteristic Presentation Format definieren. Für komplexe Protokolle wird empfohlen, ein Command-Merkmal mit Write-Eigenschaft und ein Status-Merkmal mit Notify aufzunehmen – dies folgt dem Command/Status-Muster, das in industriellen BLE-Anwendungen verwendet wird.
// Benutzerdefinierten GATT-Dienst erstellen (Android als GATT-Server)
private fun createCustomService(): BluetoothGattService {
val serviceUuid = UUID.fromString("12345678-1234-5678-1234-56789abcdef0")
val service = BluetoothGattService(
serviceUuid, BluetoothGattService.SERVICE_TYPE_PRIMARY
)
val charUuid = UUID.fromString("12345678-1234-5678-1234-56789abcdef1")
val characteristic = BluetoothGattCharacteristic(
charUuid,
BluetoothGattCharacteristic.PROPERTY_READ or
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ
)
service.addCharacteristic(characteristic)
return service
}
Häufig gestellte Fragen
GATT (Generic Attribute Profile) ist ein Bluetooth-Low-Energy-Profil, das die Datenaustauschstruktur zwischen Geräten definiert. Es wird benötigt, um den Zugriff auf Informationen zu standardisieren: Alle BLE-Geräte organisieren Daten in Diensten und Merkmalen, sodass jeder Client Sensorwerte lesen, Geräte steuern und Benachrichtigungen empfangen kann.
GAP ist für die Erkennung und Verbindung von BLE-Geräten verantwortlich (Scannen, Werbung, Verbindungsaufbau). GATT ist für den Datenaustausch nach der Verbindung verantwortlich (Lesen, Schreiben, Benachrichtigungen). GAP arbeitet vor der Verbindung, GATT danach. Beide Profile sind für BLE obligatorisch, erfüllen aber unterschiedliche Funktionen: GAP ist die „Netzwerkschicht“, GATT die „Anwendungsschicht“.
Zu den Standarddiensten gehören Battery Service (180F, Batteriestand), Heart Rate (180D, Puls), Device Information (180A, Gerätedaten). Jeder Dienst enthält mehrere Merkmale mit 16-Bit-UUIDs. Entwickler können benutzerdefinierte Dienste mit 128-Bit-UUIDs für spezifische Aufgaben erstellen – wie die Steuerung eines intelligenten Schlosses oder die Datenübertragung eines Fitness-Trackers.
Auf Android wird GATT über BluetoothGatt (Verbindung), BluetoothGattService (Dienst), BluetoothGattCharacteristic (Merkmal) und BluetoothGattDescriptor (Deskriptor) implementiert. Die Verbindung erfolgt über connectGatt(), wonach Ereignisse über BluetoothGattCallback eingehen: onConnectionStateChange, onServicesDiscovered, onCharacteristicChanged (für Benachrichtigungen). Alle GATT-Operationen müssen sequenziell ausgeführt werden.
UUID (Universally Unique Identifier) ist eine 16-Bit- oder 128-Bit-Kennung, die einen Dienst oder ein Merkmal in GATT eindeutig identifiziert. Standard-Bluetooth-SIG-Dienste verwenden 16-Bit-UUIDs (z. B. 180D für Heart Rate). Benutzerdefinierte Entwicklerdienste verwenden 128-Bit-UUIDs (z. B. 12345678-1234-5678-1234-56789abcdef0). Die UUID ermöglicht es dem Client, die benötigten Daten auf dem GATT-Server zu finden.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch