BluetoothGatt — co to jest, metody i protokół GATT BLE w Android

Autor: IT Sectr Opublikowano: 2026-07-16 Czas czytania: 10 min

BluetoothGatt — klasa Android udostępniająca API do pracy klienta GATT (Generic Attribute Profile) przez połączenie BLE. BluetoothGatt hermetyzuje połączenie z zdalnym serwerem GATT (peryferyjnym urządzeniem BLE) i zarządza wszystkimi operacjami profilu: odkrywanie usług, odczyt i zapis cech, subskrypcja powiadomień i indykacji. Instancję BluetoothGatt uzyskuje się przez BluetoothDevice.connectGatt() z wywołaniem zwrotnym BluetoothGattCallback. Według Android Developers, 2026, BluetoothGatt jest centralną klasą dla dwukierunkowej komunikacji BLE, obsługującą operacje GATT od BLE 4.0 do BLE 5.4.

Najważniejsze

  • BluetoothGatt — klasa Android dla klienta GATT, zarządzająca połączeniem BLE z urządzeniem peryferyjnym
  • connectGatt() — metoda BluetoothDevice do tworzenia BluetoothGatt; przyjmuje kontekst, autoConnect, wywołanie zwrotne i transport
  • discoverServices() — metoda do uzyskania hierarchii GATT: usługi (BluetoothGattService), cechy (BluetoothGattCharacteristic)
  • readCharacteristic/writeCharacteristic — metody odczytu i zapisu z asynchronicznym wynikiem przez BluetoothGattCallback
  • setCharacteristicNotification — metoda subskrypcji powiadomień BLE z obowiązkowym zapisem deskryptora CCCD

Co to jest BluetoothGatt: istota i tworzenie połączenia

BluetoothGatt — to obiekt proxy reprezentujący połączenie GATT między urządzeniem Android (centrala) a peryferią BLE (serwer). Każda instancja BluetoothGatt odpowiada jednemu aktywnemu połączeniu BLE. Za jego pośrednictwem wykonywane są wszystkie operacje profilu GATT: odkrywanie, odczyt, zapis, powiadomienia. BluetoothGatt nie jest tworzony bezpośrednio — jest zwracany przez metodę BluetoothDevice.connectGatt().

Utworzenie BluetoothGatt wymaga czterech parametrów. Context — kontekst aplikacji (Activity lub Application). autoConnect — jeśli false, Android natychmiast inicjuje bezpośrednie połączenie; jeśli true, Android łączy się automatycznie po wykryciu urządzenia (przydatne do połączenia w tle). BluetoothGattCallback — obowiązkowe wywołanie zwrotne dla wszystkich zdarzeń GATT. transport — BluetoothDevice.TRANSPORT_LE (BLE) lub TRANSPORT_BREDR (Classic). Na urządzeniach BLE zawsze używaj TRANSPORT_LE.

Cykl życia BluetoothGatt składa się z pięciu stanów. DISCONNECTED — stan początkowy. CONNECTING — po wywołaniu connectGatt, do potwierdzenia. CONNECTED — po onConnectionStateChange z STATE_CONNECTED. Po podłączeniu wywoływane jest discoverServices() w celu uzyskania hierarchii GATT. Po zakończeniu pracy — disconnect() i close() w celu zwolnienia zasobów systemowych. Bez wywołania close() aplikacja może wyczerpać limit połączeń BLE Androida (zwykle 4–8).

kotlin
// Tworzenie połączenia BluetoothGatt
import android.bluetooth.*

class GattConnector(private val context: Context) {

    private var bluetoothGatt: BluetoothGatt? = null

    fun connect(device: BluetoothDevice): BluetoothGatt? {
        // Zamknij poprzednie połączenie jeśli istnieje
        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. Połączenie nawiązane → Odkrywanie
                            gatt.discoverServices()
                        }
                        BluetoothProfile.STATE_DISCONNECTED -> {
                            // 3. Połączenie utracone
                            close()
                        }
                    }
                }

                override fun onServicesDiscovered(
                    gatt: BluetoothGatt, status: Int
                ) {
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        // 4. Otrzymano hierarchię GATT
                        onGattReady(gatt)
                    }
                }
            },
            BluetoothDevice.TRANSPORT_LE
        )
        return bluetoothGatt
    }

    private fun onGattReady(gatt: BluetoothGatt) {
        // GATT gotowy do operacji odczytu/zapisu
    }

    fun close() {
        bluetoothGatt?.disconnect()
        bluetoothGatt?.close()
        bluetoothGatt = null
    }
}

Klasa GattConnector demonstruje prawidłowe tworzenie BluetoothGatt. Parametr autoConnect=false — bezpośrednie połączenie (dla zeskanowanych urządzeń). Przy onConnectionStateChange ze STATE_CONNECTED natychmiast wywoływane jest discoverServices(). onServicesDiscovered sygnalizuje gotowość GATT. close() sekwencyjnie wywołuje disconnect() i close() — bez close() zasoby systemowe nie są zwalniane, co prowadzi do wycieku połączeń BLE.

Odkrywanie usług i cech przez BluetoothGatt

discoverServices() — pierwsza metoda GATT wywoływana po podłączeniu. Inicjuje asynchroniczne wyszukiwanie wszystkich usług na peryferii BLE. Wynik przychodzi w onServicesDiscovered() z kodem statusu: GATT_SUCCESS (0) — sukces, 133 — GATT_ERROR, 8 — GATT_CONNECTION_TIMEOUT. Po pomyślnym odkryciu BluetoothGatt wypełnia listę usług dostępnych przez getServices().

Każdy BluetoothGattService zawiera listę BluetoothGattCharacteristic. Cecha ma UUID, właściwości (PROPERTY_READ, PROPERTY_WRITE, PROPERTY_NOTIFY) i opcjonalne deskryptory. Właściwości określają, które operacje są dozwolone: jeśli cecha nie ma PROPERTY_READ, wywołanie readCharacteristic zwróci błąd. Do uzyskania deskryptorów cechy używane jest getDescriptors().

kotlin
// Odkrywanie usług i wyszukiwanie cech
class GattServiceExplorer {

    // Znajdź usługę po UUID
    fun findService(gatt: BluetoothGatt, uuid: UUID): BluetoothGattService? {
        return gatt.services?.firstOrNull { it.uuid == uuid }
    }

    // Znajdź cechę w usłudze
    fun findCharacteristic(
        service: BluetoothGattService,
        uuid: UUID
    ): BluetoothGattCharacteristic? {
        return service.characteristics?.firstOrNull { it.uuid == uuid }
    }

    // Pobierz wszystkie obsługiwane operacje cechy
    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
    }

    // Zarejestruj całą hierarchię GATT
    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}")
                }
            }
        }
    }
}

Klasa GattServiceExplorer udostępnia narzędzia do nawigacji po hierarchii GATT. findService i findCharacteristic wyszukują usługi i cechy po UUID. getCharacteristicProperties sprawdza maski bitowe właściwości przez and(). dumpGattTree wypisuje pełną hierarchię do logu — przydatna podczas debugowania urządzeń BLE. Wszystkie operacje na BluetoothGatt muszą być wykonywane po pomyślnym onServicesDiscovered, w przeciwnym razie getServices() zwróci pustą listę.

Odczyt cech BLE: readCharacteristic i readDescriptor

readCharacteristic() — asynchroniczna metoda BluetoothGatt do odczytu wartości cechy z zdalnego urządzenia BLE. Wynik przychodzi w onCharacteristicRead() BluetoothGattCallback. Jeśli na urządzeniu są 2+ pasujących cech (mało prawdopodobne, ale możliwe), readCharacteristic() może odczytać nie tę cechę — bezpieczniej wywoływać readCharacteristic() na instancji BluetoothGattCharacteristic, a nie po UUID.

readDescriptor() — metoda do odczytu wartości deskryptora cechy. Typowym deskryptorem jest CCCD (Client Characteristic Configuration Descriptor, UUID 0x2902), określający, czy powiadomienia są włączone. Wynik w onDescriptorRead(). Odczyt deskryptorów rzadko jest wymagany w praktyce — CCCD jest zarządzany przez setCharacteristicNotification(), ale dla niestandardowych deskryptorów (User Description 0x2901, Presentation Format 0x2904) readDescriptor() jest jedynym sposobem uzyskania metadanych.

MTU a odczyt dużych danych — jeśli wartość cechy przekracza MTU (23 bajty dla BLE 4.0), Android automatycznie fragmentuje i składa dane sekwencją żądań odczytu przez stos BLE. Dla BLE 5.0+ z extended MTU (do 251 bajtów) fragmentacja nie jest wymagana — jeden odczyt zwraca pełne dane. Przed odczytem można wywołać requestMtu() w celu uzgodnienia maksymalnego MTU.

kotlin
// Odczyt cechy i deskryptora przez BluetoothGatt
class GattReader {

    fun readHeartRate(gatt: BluetoothGatt) {
        // UUID usługi Heart Rate = 0x180D
        val service = gatt.getService(UUID.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
            ?: return
        // UUID pomiaru tętna = 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) }
    }

    // Przetwarzanie danych w callbacku onCharacteristicRead:
    fun parseHeartRate(value: ByteArray): Int {
        // BLE Heart Rate: bajty = flagi, drugi = 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
    }
}

Klasa GattReader demonstruje odczyt cechy Heart Rate. Usługa 0x180D zawiera cechę 0x2A37 (Heart Rate Measurement) — standardowy profil BLE Bluetooth SIG. Przed odczytem sprawdzana jest właściwość PROPERTY_READ przez hasProperty. parseHeartRate parsuje format BLE tętna: pierwszy bajt — flagi (format danych), drugi — wartość bpm. Deskryptor CCCD (0x2902) jest odczytywany w celu sprawdzenia statusu powiadomień.

Zapis cech: writeCharacteristic z WriteType

writeCharacteristic() — metoda BluetoothGatt do zapisu danych na peryferię BLE. Na Android API 33+ writeCharacteristic() został zastąpiony przez writeCharacteristic(request), gdzie BluetoothGattCharacteristicWriteRequest to obiekt żądania zawierający cechę, tablicę bajtów i WriteType. Stara metoda writeCharacteristic(characteristic) z setValue() jest przestarzała. WriteType określa zachowanie żądania: WRITE_TYPE_DEFAULT (zależy od właściwości cechy), WRITE_TYPE_NO_RESPONSE (withoutResponse) i WRITE_TYPE_SIGNED (autoryzacja).

Wybór WriteType wpływa na szybkość i niezawodność. WRITE_TYPE_DEFAULT zwykle odpowiada withResponse (jeśli cecha ma PROPERTY_WRITE) lub withoutResponse (jeśli ma PROPERTY_WRITE_NO_RESPONSE). Dla danych strumieniowych (aktualizacje OTA, logi) używaj WRITE_TYPE_NO_RESPONSE — maksymalna przepustowość. Dla poleceń z gwarancją dostarczenia (włączanie, konfiguracja) — WRITE_TYPE_DEFAULT z potwierdzeniem przez onCharacteristicWrite.

kotlin
// Zapis cechy BLE na Android API 33+
class GattWriter {

    // Zapis z potwierdzeniem (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)
        }
    }

    // Zapis bez potwierdzenia (max prędkość)
    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)
        }
    }

    // Callback onCharacteristicWrite (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")
            }
        }
    }
}

Klasa GattWriter obsługuje oba WriteType dla różnych poziomów API. writeWithResponse używa WRITE_TYPE_DEFAULT — urządzenie BLE potwierdza zapis przez onCharacteristicWrite. writeWithoutResponse używa WRITE_TYPE_NO_RESPONSE — dane są wysyłane bez potwierdzenia, maksymalna przepustowość. Na API 33+ używany jest nowy writeCharacteristic(request) z BluetoothGattCharacteristicWriteRequest. Na API < 33 — stary setValue() + writeCharacteristic().

Subskrypcja powiadomień: setCharacteristicNotification i CCCD

setCharacteristicNotification() — metoda BluetoothGatt do subskrypcji powiadomień o zmianie cechy na peryferii. Po aktywacji subskrypcji urządzenie BLE wysyła nowe wartości przez onCharacteristicChanged(). Jednak setCharacteristicNotification() tylko aktywuje lokalne powiadomienie Androida — aby włączyć powiadomienia na samym urządzeniu BLE, należy również zapisać wartość 0x0100 w deskryptorze CCCD (0x2902).

CCCD (Client Characteristic Configuration Descriptor) — deskryptor zarządzający wysyłaniem powiadomień z peryferii BLE. Wartość 0x0000 — powiadomienia wyłączone, 0x0100 — powiadomienia włączone (notifications), 0x0200 — indykacje włączone (indications). Zapis do CCCD jest wykonywany przez writeDescriptor() na BluetoothGatt po wywołaniu setCharacteristicNotification(). Android nie zapisuje CCCD automatycznie — ten obowiązek spoczywa na programiście.

kotlin
// Prawidłowa subskrypcja powiadomień BLE
class GattNotificationManager {

    // 1. Włącz powiadomienia
    fun enableNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
        // Krok 1: lokalna subskrypcja Android
        val success = gatt.setCharacteristicNotification(characteristic, true)
        if (!success) {
            print("Nie udało się zasubskrybować")
            return
        }

        // Krok 2: zapisz CCCD (0x2902) na urządzeniu BLE
        val cccdDescriptor = characteristic.getDescriptor(
            UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
        ) ?: return

        // 0x0100 = powiadomienie, 0x0200 = indykacja
        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. Odkrywanie cechy
    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. Callback powiadomienia
    private val notificationCallback = object : BluetoothGattCallback() {
        override fun onCharacteristicChanged(
            gatt: BluetoothGatt,
            characteristic: BluetoothGattCharacteristic,
            value: ByteArray,
            callbackType: Int
        ) {
            // Nowa wartość z peryferii BLE
            print("Notification: ${value.size} bytes")
        }
    }
}

Klasa GattNotificationManager implementuje prawidłowy dwuetapowy protokół subskrypcji powiadomień BLE. enableNotification najpierw wywołuje setCharacteristicNotification(true) na Android, następnie zapisuje 0x0100 do deskryptora CCCD przez writeDescriptor. disableNotification wykonuje operacje odwrotne. Bez zapisu CCCD urządzenie BLE nie wysyła powiadomień — to najczęstszy błąd programistów BLE na Android.

Przykład klienta GATT w Kotlin z BluetoothGattCallback

Pełny przykład klienta GATT w Kotlin, łączący tworzenie BluetoothGatt, odkrywanie, odczyt i subskrypcję powiadomień w jednym menedżerze z użyciem korutyn do asynchronicznego przetwarzania.

kotlin
// Pełny klient GATT z korutynami w Kotlin
class GattClient(context: Context) {

    private val context = context.applicationContext
    private var gatt: BluetoothGatt? = null

    // Połącz z korutyną
    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
            )
        }

    // Odczyt cechy przez korutynę
    suspend fun readCharacteristicValue(char: BluetoothGattCharacteristic): ByteArray? =
        suspendCoroutine { continuation ->
            gatt?.let { gatt ->
                // Zapisz tag cechy do identyfikacji callbacku
                gatt.setCharacteristic(char, null)  // dla API < 33
                gatt.readCharacteristic(char)
            }
        }

    // Zamknij połączenie
    fun release() {
        gatt?.disconnect()
        gatt?.close()
        gatt = null
    }
}

Klient GATT GattClient używa korutyn (suspendCoroutine) do przekształcenia callbackowego API BluetoothGatt w sekwencyjne wywołania. connect() czeka na onServicesDiscovered, po czym hierarchia GATT jest dostępna. readCharacteristicValue() czeka na onCharacteristicRead. Takie podejście eliminuje zagnieżdżanie callbacków i czyni kod BLE liniowym. release() gwarantuje zwolnienie zasobów — obowiązkowe wywołanie w onDestroy Activity lub ViewModel.onCleared.

Często zadawane pytania

Co to jest BluetoothGatt w Android?

BluetoothGatt — klasa dla klienta GATT Android, zarządzająca połączeniem BLE z urządzeniem peryferyjnym. Tworzona przez BluetoothDevice.connectGatt(), udostępnia metody discoverServices(), readCharacteristic(), writeCharacteristic(), setCharacteristicNotification(). Wyniki wszystkich operacji przychodzą asynchronicznie przez BluetoothGattCallback. Bez BluetoothGatt niemożliwa jest dwukierunkowa komunikacja BLE na Android.

Dlaczego onServicesDiscovered zwraca status 133?

Status 133 (GATT_ERROR) oznacza wewnętrzny błąd stosu BLE Androida. Przyczyny: urządzenie odłączyło się podczas odkrywania, MTU jest mniejsze niż minimalne (23 bajty) lub stos BLE jest przeciążony. Rozwiązanie: powtórz discoverServices() z opóźnieniem 500 ms, sprawdź RSSI urządzenia i upewnij się, że peryferia obsługuje odkrywanie GATT w bieżącym stanie.

Jak prawidłowo zapisać cechę z potwierdzeniem?

Aby zapisać z potwierdzeniem, wywołaj writeCharacteristic() z WRITE_TYPE_DEFAULT (API 33+: BluetoothGattCharacteristicWriteRequest). Po sukcesie urządzenie BLE wysyła potwierdzenie, a Android wywołuje onCharacteristicWrite z GATT_SUCCESS. Jeśli urządzenie nie odpowie w ciągu 30 sekund (limit czasu stosu), callback zwraca status błędu. Do watchdoga używaj Handler z postDelayed.

Jak pracować z BLE na Android 33+?

Na Android 13+ (API 33) zmieniono metody BluetoothGatt: writeCharacteristic() teraz przyjmuje BluetoothGattCharacteristicWriteRequest, readCharacteristic() — BluetoothGattCharacteristicReadRequest. Stare setValue()/writeCharacteristic() są przestarzałe. Zmieniono również BluetoothGattCallback: onCharacteristicRead(), onCharacteristicWrite(), onCharacteristicChanged() otrzymują ByteArray value i callbackType. Używaj Build.VERSION.SDK_INT do rozgałęziania.

Ile połączeń BLE obsługuje Android?

Android obsługuje 4–8 jednoczesnych połączeń BLE-GATT (zależy od producenta i wersji Androida). Pixel/Google: do 7, Samsung: do 5, Xiaomi: do 4. Po przekroczeniu limitu connectGatt zwraca null lub onConnectionStateChange z błędem. Do pracy z dużą liczbą urządzeń używaj połączenia cyklicznego lub Bluetooth Mesh.

Podsumowanie

  • BluetoothGatt — klient GATT Android dla połączenia BLE, tworzony przez BluetoothDevice.connectGatt() z BluetoothGattCallback
  • discoverServices() — obowiązkowy krok po podłączeniu w celu uzyskania usług, cech i deskryptorów urządzenia BLE
  • Odczyt — readCharacteristic() z asynchronicznym wynikiem w onCharacteristicRead(); dla dużych danych wymagane jest uzgodnienie MTU
  • Zapis — writeCharacteristic() z WriteType: DEFAULT (withResponse) lub NO_RESPONSE (bez potwierdzenia)
  • Powiadomienia — dwuetapowa aktywacja: setCharacteristicNotification() + zapis CCCD (0x2902) wartością 0x0100
  • API 33+ — nowe metody writeCharacteristic(request) i readCharacteristic(request) z obiektami żądań
  • Zwalnianie zasobów — obowiązkowe wywołanie disconnect() i close() w celu zapobieżenia wyciekowi połączeń BLE

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również