GATT — was ist das, Generic Attribute Profile und Implementierung in Android

Autor: IT Sectr Veröffentlicht: 2026-07-14 Lesezeit: 10 Min.

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 – ein BLE-Profil, das die Datenübertragungsstruktur über Dienste, Merkmale und Deskriptoren definiert
  • Hierarchie – ein Dienst enthält Merkmale, jedes Merkmal hat einen Wert mit optionalen Deskriptoren
  • UUID – jeder Dienst und jedes Merkmal wird durch eine 16-Bit- (Standard) oder 128-Bit-UUID (benutzerdefiniert) identifiziert
  • Rollen – GATT-Server (stellt Daten bereit) und GATT-Client (liest/schreibt Daten)
  • Android-API – BluetoothGatt, BluetoothGattService, BluetoothGattCharacteristic – Hauptklassen für die Arbeit mit GATT

Was ist GATT?

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.

Die Rolle von GATT im BLE-Stack

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.

GATT-Architektur: Dienste, Merkmale und Deskriptoren

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.

Arten von Operationen mit Merkmalen

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.

kotlin
// 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?
)

GATT und GAP: Unterschiede zwischen den BLE-Profilen

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.

MerkmalGAPGATT
ZweckErkennung und VerbindungDatenaustausch
RollenCentral / PeripheralClient / Server
ProtokollHCI, Link LayerATT (Attribute Protocol)
PhaseVor der VerbindungNach der Verbindung
HauptklasseBluetoothAdapterBluetoothGatt

Rollen in GATT

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.

Wie GATT-Kommunikation in BLE funktioniert

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.

MTU – Maximale Übertragungseinheit

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.

kotlin
// 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)
    }
}

Behandlung von Benachrichtigungen

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.

Implementierung von GATT auf Android

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.

Lebenszyklus der GATT-Verbindung

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.

kotlin
// Ü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) }
    }
}

Standard-GATT-Profile und -Dienste

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.

Entwicklung benutzerdefinierter GATT-Dienste

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.

kotlin
// 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

Was ist GATT in BLE und warum wird es benötigt?

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.

Was ist der Unterschied zwischen GATT und GAP?

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“.

Welche GATT-Dienste und -Merkmale gibt es?

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.

Wie funktioniert GATT auf Android?

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.

Was ist eine UUID in GATT?

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

  • GATT – ein BLE-Profil für strukturierten Datenaustausch über eine Hierarchie von Diensten, Merkmalen und Deskriptoren, basierend auf dem Attribute Protocol (ATT)
  • Datenhierarchie – Dienst (logische Gruppe), Merkmal (spezifischer Wert mit Typ), Deskriptor (Metadaten – Einheiten, Benachrichtigungseinstellungen)
  • GATT-Rollen – Server (stellt Daten bereit, typischerweise BLE-Peripheral) und Client (liest/schreibt, typischerweise Android-Smartphone)
  • Operationen – Read, Write, Notify (ohne Bestätigung, schneller) und Indicate (mit Bestätigung, zuverlässiger); die Wahl hängt vom Szenario ab
  • Android-API – BluetoothGatt, BluetoothGattCallback, BluetoothGattService, BluetoothGattCharacteristic; sequenzielle asynchrone Aufrufe über Rückrufe
  • Standardprofile – Battery Service, Heart Rate, Device Information – gewährleisten Kompatibilität zwischen Geräten verschiedener Hersteller
  • Benutzerdefinierte Dienste – 128-Bit-UUIDs für einzigartige Aufgaben; entworfen nach dem Command/Status-Muster mit korrekten Eigenschaften (Read, Write, Notify, Indicate)

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.

Projekt besprechen

Lesen Sie auch