BluetoothGatt — Android osztály, amely API-t biztosít a GATT-kliens (Generic Attribute Profile) működéséhez BLE-kapcsolaton keresztül. A BluetoothGatt beágyazza a kapcsolatot a távoli GATT-szerverrel (perifériás BLE-eszköz) és kezeli a profil összes műveletét: szolgáltatások felderítése, jellemzők olvasása és írása, értesítésekre és indikációkra való előfizetés. A BluetoothGatt példány a BluetoothDevice.connectGatt() segítségével, BluetoothGattCallback visszahívással érhető el. A Android Developers, 2026 szerint a BluetoothGatt a központi osztály a kétirányú BLE-kommunikációhoz, támogatva a GATT-műveleteket BLE 4.0-tól BLE 5.4-ig.
Főbb pontok
BluetoothGatt — egy proxy objektum, amely a GATT-kapcsolatot reprezentálja az Android-eszköz (központ) és a BLE-periféria (szerver) között. Minden BluetoothGatt példány egy aktív BLE-kapcsolatnak felel meg. Rajta keresztül minden GATT-profil művelet végrehajtható: felderítés, olvasás, írás, értesítések. A BluetoothGatt nem közvetlenül jön létre — a BluetoothDevice.connectGatt() metódus adja vissza.
A BluetoothGatt létrehozása négy paramétert igényel. Context — alkalmazáskontextus (Activity vagy Application). autoConnect — ha false, az Android azonnal közvetlen kapcsolatot kezdeményez; ha true, az Android automatikusan csatlakozik az eszköz észlelésekor (hasznos háttérkapcsolathoz). BluetoothGattCallback — kötelező visszahívás minden GATT-eseményhez. transport — BluetoothDevice.TRANSPORT_LE (BLE) vagy TRANSPORT_BREDR (Classic). BLE-eszközökön mindig használja a TRANSPORT_LE-t.
BluetoothGatt életciklusa öt állapotból áll. DISCONNECTED — kezdeti állapot. CONNECTING — a connectGatt meghívása után, a megerősítésig. CONNECTED — az onConnectionStateChange után STATE_CONNECTED-dal. Csatlakozás után a discoverServices() hívódik meg a GATT-hierarchia megszerzéséhez. A munka befejezése után — disconnect() és close() a rendszererőforrások felszabadításához. A close() elhagyása esetén az alkalmazás kimerítheti az Android BLE-kapcsolat korlátját (általában 4–8).
// BluetoothGatt kapcsolat létrehozása
import android.bluetooth.*
class GattConnector(private val context: Context) {
private var bluetoothGatt: BluetoothGatt? = null
fun connect(device: BluetoothDevice): BluetoothGatt? {
// Előző kapcsolat bezárása, ha létezik
close()
bluetoothGatt = device.connectGatt(
context,
false, // autoConnect = false ( )
object : BluetoothGattCallback() {
override fun onConnectionStateChange(
gatt: BluetoothGatt, status: Int, newState: Int
) {
when (newState) {
BluetoothProfile.STATE_CONNECTED -> {
// 2. Kapcsolat létrejött → Felderítés
gatt.discoverServices()
}
BluetoothProfile.STATE_DISCONNECTED -> {
// 3. Kapcsolat megszakadt
close()
}
}
}
override fun onServicesDiscovered(
gatt: BluetoothGatt, status: Int
) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// 4. GATT hierarchia megérkezett
onGattReady(gatt)
}
}
},
BluetoothDevice.TRANSPORT_LE
)
return bluetoothGatt
}
private fun onGattReady(gatt: BluetoothGatt) {
// GATT készen áll az olvasási/írási műveletekre
}
fun close() {
bluetoothGatt?.disconnect()
bluetoothGatt?.close()
bluetoothGatt = null
}
}
A GattConnector osztály a BluetoothGatt helyes létrehozását mutatja be. Az autoConnect=false paraméter — közvetlen kapcsolat (a beolvasott eszközökhöz). Az onConnectionStateChange STATE_CONNECTED-del azonnal meghívja a discoverServices()-t. Az onServicesDiscovered a GATT készenlétét jelzi. A close() egymás után meghívja a disconnect() és close() metódusokat — close() nélkül a rendszererőforrások nem szabadulnak fel, ami BLE-kapcsolatok szivárgásához vezet.
discoverServices() — az első GATT-metódus, amely a csatlakozás után hívódik meg. Aszinkron keresést indít az összes szolgáltatásra a BLE-periférián. Az eredmény az onServicesDiscovered() függvényben érkezik státuszkóddal: GATT_SUCCESS (0) — sikeres, 133 — GATT_ERROR, 8 — GATT_CONNECTION_TIMEOUT. Sikeres felderítés után a BluetoothGatt kitölti a getServices() segítségével elérhető szolgáltatások listáját.
Minden BluetoothGattService tartalmaz egy BluetoothGattCharacteristic listát. A jellemző rendelkezik UUID-val, tulajdonságokkal (PROPERTY_READ, PROPERTY_WRITE, PROPERTY_NOTIFY) és opcionális deszkriptorokkal. A tulajdonságok határozzák meg, mely műveletek engedélyezettek: ha egy jellemző nem rendelkezik PROPERTY_READ-dzsal, a readCharacteristic hívás hibát ad vissza. A jellemző deszkriptorainak megszerzéséhez a getDescriptors() használható.
// Szolgáltatásfelderítés és jellemzőkeresés
class GattServiceExplorer {
// Szolgáltatás keresése UUID alapján
fun findService(gatt: BluetoothGatt, uuid: UUID): BluetoothGattService? {
return gatt.services?.firstOrNull { it.uuid == uuid }
}
// Jellemző keresése a szolgáltatásban
fun findCharacteristic(
service: BluetoothGattService,
uuid: UUID
): BluetoothGattCharacteristic? {
return service.characteristics?.firstOrNull { it.uuid == uuid }
}
// Az összes támogatott jellemzőművelet lekérése
fun getCharacteristicProperties(chars: BluetoothGattCharacteristic): List<String> {
val props = mutableListOf<String>()
with(chars.properties) {
if (and(BluetoothGattCharacteristic.PROPERTY_READ) != 0) props.add("READ")
if (and(BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) props.add("WRITE")
if (and(BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0) props.add("WRITE_NO_RESP")
if (and(BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) props.add("NOTIFY")
if (and(BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) props.add("INDICATE")
}
return props
}
// Teljes GATT hierarchia naplózása
fun dumpGattTree(gatt: BluetoothGatt) {
gatt.services?.forEach { service ->
print("Service: ${service.uuid}")
service.characteristics?.forEach { char ->
print(" Characteristic: ${char.uuid}, properties: ${char.properties}")
char.descriptors?.forEach { desc ->
print(" Descriptor: ${desc.uuid}")
}
}
}
}
}
A GattServiceExplorer osztály segédprogramokat biztosít a GATT-hierarchiában való navigáláshoz. A findService és findCharacteristic UUID alapján keres szolgáltatásokat és jellemzőket. A getCharacteristicProperties bitmaszkokat ellenőrzi az and() segítségével. A dumpGattTree kiírja a teljes hierarchiát a naplóba — hasznos a BLE-eszközök hibakeresése során. A BluetoothGatt összes műveletét a sikeres onServicesDiscovered után kell végrehajtani, különben a getServices() üres listát ad vissza.
readCharacteristic() — a BluetoothGatt aszinkron metódusa egy jellemző értékének olvasásához egy távoli BLE-eszközről. Az eredmény a BluetoothGattCallback onCharacteristicRead() függvényében érkezik. Ha az eszközön 2+ egyező jellemző van (nem valószínű, de lehetséges), a readCharacteristic() nem a célt olvashatja — biztonságosabb a readCharacteristic() meghívása a BluetoothGattCharacteristic példányon, nem UUID alapján.
readDescriptor() — metódus a jellemző deszkriptorának értékét olvassa. Tipikus deszkriptor — CCCD (Client Characteristic Configuration Descriptor, UUID 0x2902), amely meghatározza, hogy az értesítések be vannak-e kapcsolva. Eredmény az onDescriptorRead()-ben. A deszkriptorok olvasása ritkán szükséges a gyakorlatban — a CCCD-t a setCharacteristicNotification() kezeli, de egyéni deszkriptorokhoz (User Description 0x2901, Presentation Format 0x2904) a readDescriptor() az egyetlen mód a metaadatok megszerzésére.
MTU és nagy adatok olvasása — ha a jellemző értéke meghaladja az MTU-t (23 bájt BLE 4.0 esetén), az Android automatikusan fragmentálja és összeállítja az adatokat olvasási kérések sorozatával a BLE-veremen keresztül. BLE 5.0+ esetén kiterjesztett MTU-val (251 bájtig) fragmentáció nem szükséges — egy olvasás teljes adatokat ad vissza. Olvasás előtt a requestMtu() meghívható a maximális MTU egyeztetéséhez.
// Jellemző és deszkriptor olvasása BluetoothGatt segítségével
class GattReader {
fun readHeartRate(gatt: BluetoothGatt) {
// Heart Rate szolgáltatás UUID = 0x180D
val service = gatt.getService(UUID.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
?: return
// Heart Rate mérés UUID = 0x2A37
val characteristic = service.getCharacteristic(
UUID.fromString("00002A37-0000-1000-8000-00805F9B34FB")
) ?: return
if (hasProperty(characteristic, BluetoothGattCharacteristic.PROPERTY_READ)) {
gatt.readCharacteristic(characteristic)
}
}
fun readDescriptor(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
// CCCD (0x2902)
val cccd = characteristic.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
)
cccd?.let { gatt.readDescriptor(it) }
}
// Adatok feldolgozása az onCharacteristicRead visszahívásban:
fun parseHeartRate(value: ByteArray): Int {
// BLE Heart Rate: bájtok = flags, második = bpm
return if (value.isNotEmpty()) value[1].toInt() and 0xFF else 0
}
private fun hasProperty(char: BluetoothGattCharacteristic, prop: Int): Boolean {
return char.properties and prop != 0
}
}
A GattReader osztály a Heart Rate jellemző olvasását mutatja be. A 0x180D szolgáltatás tartalmazza a 0x2A37 (Heart Rate Measurement) jellemzőt — a Bluetooth SIG szabványos BLE-profilja. Olvasás előtt a PROPERTY_READ tulajdonság ellenőrzése a hasProperty segítségével történik. A parseHeartRate elemzi a BLE pulzusformátumot: első bájt — flags (adatformátum), második — bpm érték. A CCCD-deszkriptor (0x2902) olvasása az értesítési állapot ellenőrzéséhez történik.
writeCharacteristic() — a BluetoothGatt metódusa adatok írásához a BLE-perifériára. Android API 33+-on a writeCharacteristic() helyébe a writeCharacteristic(request) lépett, ahol a BluetoothGattCharacteristicWriteRequest egy kérelemobjektum, amely tartalmazza a jellemzőt, a bájt tömböt és a WriteType-ot. A régi writeCharacteristic(characteristic) metódus setValue()-val elavult. A WriteType meghatározza a kérés viselkedését: WRITE_TYPE_DEFAULT (a jellemző tulajdonságaitól függ), WRITE_TYPE_NO_RESPONSE (withoutResponse) és WRITE_TYPE_SIGNED (hitelesítés).
A WriteType megválasztása befolyásolja a sebességet és a megbízhatóságot. A WRITE_TYPE_DEFAULT általában a withResponse (ha a jellemző rendelkezik PROPERTY_WRITE-tel) vagy a withoutResponse (ha PROPERTY_WRITE_NO_RESPONSE-tel rendelkezik) kifejezésnek felel meg. Adatfolyamokhoz (OTA-frissítések, naplók) használja a WRITE_TYPE_NO_RESPONSE-t — maximális sávszélesség. Kézbesítési garanciával rendelkező parancsokhoz (aktiválás, konfiguráció) — WRITE_TYPE_DEFAULT megerősítéssel az onCharacteristicWrite segítségével.
// BLE jellemző írása Android API 33+-on
class GattWriter {
// Írás válasszal (withResponse)
fun writeWithResponse(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, data: ByteArray) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// API 33+: writeCharacteristic
val request = BluetoothGattCharacteristicWriteRequest(
characteristic,
data,
BluetoothGattCharacteristicWriteRequest.WRITE_TYPE_DEFAULT,
@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
)
gatt.writeCharacteristic(request)
} else {
// API < 33: (deprecated)
characteristic.setValue(data)
gatt.writeCharacteristic(characteristic)
}
}
// Írás válasz nélkül (maximális sebesség)
fun writeWithoutResponse(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, data: ByteArray) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val request = BluetoothGattCharacteristicWriteRequest(
characteristic,
data,
BluetoothGattCharacteristicWriteRequest.WRITE_TYPE_NO_RESPONSE,
@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
)
gatt.writeCharacteristic(request)
} else {
characteristic.setValue(data)
characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
gatt.writeCharacteristic(characteristic)
}
}
// onCharacteristicWrite visszahívás (API 33+)
private val writeCallback = object : BluetoothGattCallback() {
override fun onCharacteristicWrite(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
value: ByteArray,
status: Int,
callbackType: Int
) {
if (status == BluetoothGatt.GATT_SUCCESS) {
print("Write success: ${value.size} bytes")
}
}
}
}
A GattWriter osztály mindkét WriteType-ot támogatja különböző API-szintekhez. A writeWithResponse WRITE_TYPE_DEFAULT-ot használ — a BLE-eszköz megerősíti az írást az onCharacteristicWrite segítségével. A writeWithoutResponse WRITE_TYPE_NO_RESPONSE-ot használ — az adatok megerősítés nélkül kerülnek elküldésre, maximális sávszélesség. API 33+-on az új writeCharacteristic(request) használatos BluetoothGattCharacteristicWriteRequest-tel. API < 33 esetén — a régi setValue() + writeCharacteristic().
setCharacteristicNotification() — a BluetoothGatt metódusa a jellemző változásaira vonatkozó értesítésekre való előfizetésre a periférián. Az előfizetés aktiválása után a BLE-eszköz új értékeket küld az onCharacteristicChanged() segítségével. Azonban a setCharacteristicNotification() csak az Android helyi értesítését aktiválja — a BLE-eszközön lévő értesítések bekapcsolásához a 0x0100 értéket is be kell írni a CCCD-deszkriptorba (0x2902).
CCCD (Client Characteristic Configuration Descriptor) — deszkriptor, amely a BLE-perifériáról történő értesítésküldést kezeli. A 0x0000 érték — az értesítések ki vannak kapcsolva, 0x0100 — az értesítések be vannak kapcsolva (notifications), 0x0200 — az indikációk be vannak kapcsolva (indications). A CCCD-be írás a writeDescriptor() segítségével történik a BluetoothGatt-on a setCharacteristicNotification() meghívása után. Az Android nem írja automatikusan a CCCD-t — ez a felelősség a fejlesztőé.
// Helyes BLE értesítési előfizetés
class GattNotificationManager {
// 1. Értesítések bekapcsolása
fun enableNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
// 1. lépés: helyi Android előfizetés
val success = gatt.setCharacteristicNotification(characteristic, true)
if (!success) {
print("Sikertelen előfizetés")
return
}
// 2. lépés: CCCD (0x2902) írása a BLE eszközön
val cccdDescriptor = characteristic.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
) ?: return
// 0x0100 = értesítés, 0x0200 = indikáció
val cccdValue = if (characteristic.properties
and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) {
BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE // [0x01, 0x00]
} else {
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE // [0x02, 0x00]
}
cccdDescriptor.setValue(cccdValue)
gatt.writeDescriptor(cccdDescriptor)
}
// 2. Jellemző felderítése
fun disableNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
gatt.setCharacteristicNotification(characteristic, false)
val cccdDescriptor = characteristic.getDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
) ?: return
cccdDescriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)
gatt.writeDescriptor(cccdDescriptor)
}
// 3. Értesítési visszahívás
private val notificationCallback = object : BluetoothGattCallback() {
override fun onCharacteristicChanged(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
value: ByteArray,
callbackType: Int
) {
// Új érték a BLE perifériáról
print("Notification: ${value.size} bytes")
}
}
}
A GattNotificationManager osztály megvalósítja a helyes kétlépcsős protokollt a BLE-értesítésekre való előfizetéshez. Az enableNotification először meghívja a setCharacteristicNotification(true)-t Androidon, majd beírja a 0x0100-t a CCCD-deszkriptorba a writeDescriptor segítségével. A disableNotification az ellentétes műveleteket hajtja végre. CCCD írása nélkül a BLE-eszköz nem küld értesítéseket — ez a leggyakoribb hiba a BLE-fejlesztők körében Androidon.
Teljes példa GATT-kliensre Kotlinban, amely egyesíti a BluetoothGatt létrehozását, felderítést, olvasást és értesítésekre való előfizetést egyetlen menedzserben, korutinok segítségével az aszinkron feldolgozáshoz.
// Teljes GATT kliens korutinokkal Kotlinban
class GattClient(context: Context) {
private val context = context.applicationContext
private var gatt: BluetoothGatt? = null
// Kapcsolódás korutinnal
suspend fun connect(device: BluetoothDevice): Boolean =
suspendCoroutine { continuation ->
gatt = device.connectGatt(
context, false,
object : BluetoothGattCallback() {
override fun onConnectionStateChange(
gatt: BluetoothGatt, status: Int, newState: Int
) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices()
} else {
continuation.resume(false)
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
continuation.resume(status == BluetoothGatt.GATT_SUCCESS)
}
},
BluetoothDevice.TRANSPORT_LE
)
}
// Jellemző olvasása korutin segítségével
suspend fun readCharacteristicValue(char: BluetoothGattCharacteristic): ByteArray? =
suspendCoroutine { continuation ->
gatt?.let { gatt ->
// Jellemző címke mentése a visszahívás azonosításához
gatt.setCharacteristic(char, null) // API-hoz < 33
gatt.readCharacteristic(char)
}
}
// Kapcsolat bezárása
fun release() {
gatt?.disconnect()
gatt?.close()
gatt = null
}
}
A GattClient GATT-kliens korutinokat (suspendCoroutine) használ a callback-alapú BluetoothGatt API szekvenciális hívásokká alakításához. A connect() megvárja az onServicesDiscovered-t, majd a GATT-hierarchia elérhetővé válik. A readCharacteristicValue() megvárja az onCharacteristicRead-et. Ez a megközelítés kiküszöböli a beágyazott callback-eket és lineárissá teszi a BLE-kódot. A release() garantálja az erőforrások felszabadítását — kötelező hívás az Activity onDestroy-jában vagy ViewModel.onCleared-jében.
Gyakran ismételt kérdések
BluetoothGatt — osztály az Android GATT-klienshez, amely a BLE-kapcsolatot kezeli a perifériás eszközzel. A BluetoothDevice.connectGatt() segítségével jön létre, metódusokat biztosít: discoverServices(), readCharacteristic(), writeCharacteristic(), setCharacteristicNotification(). Az összes művelet eredménye aszinkron módon érkezik a BluetoothGattCallback segítségével. BluetoothGatt nélkül a kétirányú BLE-kommunikáció Androidon lehetetlen.
A 133-as státusz (GATT_ERROR) az Android BLE-verem belső hibáját jelenti. Okok: az eszköz lecsatlakozott a felderítés során, az MTU kisebb a minimumnál (23 bájt), vagy a BLE-verem túlterhelt. Megoldás: ismételje meg a discoverServices()-t 500 ms késleltetéssel, ellenőrizze az eszköz RSSI-jét, és győződjön meg arról, hogy a periféria támogatja a GATT-felderítést az aktuális állapotban.
A megerősítéssel történő íráshoz hívja meg a writeCharacteristic()-t WRITE_TYPE_DEFAULT-tal (API 33+: BluetoothGattCharacteristicWriteRequest). Siker esetén a BLE-eszköz megerősítést küld, és az Android meghívja az onCharacteristicWrite-et GATT_SUCCESS-szal. Ha az eszköz nem válaszol 30 másodpercen belül (verem időtúllépés), a visszahívás hibastátuszt ad vissza. Watchdoghoz használjon Handler-t postDelayed-del.
Az Android 13+-on (API 33) megváltoztak a BluetoothGatt metódusai: a writeCharacteristic() most BluetoothGattCharacteristicWriteRequest-et fogad, a readCharacteristic() — BluetoothGattCharacteristicReadRequest-et. A régi setValue()/writeCharacteristic() elavult. A BluetoothGattCallback is megváltozott: az onCharacteristicRead(), onCharacteristicWrite(), onCharacteristicChanged() ByteArray value-t és callbackType-ot kap. Az elágazáshoz használja a Build.VERSION.SDK_INT-t.
Az Android 4–8 egyidejű BLE-GATT kapcsolatot támogat (gyártótól és Android-verziótól függően). Pixel/Google: 7-ig, Samsung: 5-ig, Xiaomi: 4-ig. A korlát túllépésekor a connectGatt null-t ad vissza, vagy az onConnectionStateChange hibával hívódik meg. Nagyszámú eszközzel való munkához használjon ciklikus kapcsolatot vagy Bluetooth Mesh-t.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is