Організація GATT-обміну з BLE-периферією
Уявіть: ви розробляєте додаток для взаємодії з медичним датчиком пульсу через BLE. Після підключення ви намагаєтеся підписатися на сповіщення про серцевий ритм, але дані не приходять. На Android ви бачите помилку status 133, а на iOS запис характеристики повертає помилку. Ми стикалися з цим у більш ніж 20 проєктах з інтеграції BLE-пристроїв: медичні датчики, фітнес-трекери, промислові контролери. Одна з частих задач — підписка на сповіщення про серцевий ритм або передача великих обсягів даних, наприклад, прошивки розміром 100 КБ. При стандартному MTU в 23 байти на відправку 100 КБ йде близько 5000 пакетів, що займає хвилини. Запит збільшеного MTU до 512 байт скорочує кількість пакетів до ~200 і час передачі до кількох секунд. Ми виробили системний підхід до організації надійного обміну даними з BLE-пристроями: від правильної підписки на сповіщення до черги операцій та MTU-negotiation.
Типи операцій з характеристиками GATT
Кожна GATT-характеристика має набір прапорців properties, які визначають, які операції з нею можливі. Ось таблиця для швидкої довідки:
| Прапорець | iOS (CBCharacteristicProperties) | Android | Операція |
|---|---|---|---|
| Read | .read |
PROPERTY_READ |
Одноразове читання |
| Write | .write |
PROPERTY_WRITE |
Запис з підтвердженням |
| Write Without Response | .writeWithoutResponse |
PROPERTY_WRITE_NO_RESPONSE |
Швидкий запис |
| Notify | .notify |
PROPERTY_NOTIFY |
Сповіщення без підтвердження |
| Indicate | .indicate |
PROPERTY_INDICATE |
Сповіщення з підтвердженням |
Write Without Response швидший — немає ACK від пристрою. Підходить для потокової передачі (аудіо, показники датчиків). Write — для команд, де важлива гарантія доставки.
MTU: як збільшити пропускну здатність BLE-каналу
За замовчуванням MTU (Maximum Transmission Unit) BLE становить 23 байти, з яких корисних — тільки 20. Для передачі 10 КБ даних це означає 500 пакетів. Якщо запросити збільшений MTU (наприклад, 512), кількість пакетів скорочується до ~20 — економія часу до 90%. Ось як це робиться на кожній платформі:
| Платформа | MTU за замовчуванням | Автоматичне узгодження | Ручний запит |
|---|---|---|---|
| iOS | 23 | Так (з iOS 9+) | Непрямо через максимальну довжину запису |
| Android | 23 | Ні | gatt.requestMtu(512) + колбек onMtuChanged |
На практиці більшість BLE-чипів підтримують MTU 247–512 байт. При передачі прошивки або великих конфігурацій це критично.
Як підписатися на сповіщення BLE і не пропустити дані?
Підписка на сповіщення — стандартний спосіб отримувати дані від BLE-пристрою в реальному часі. На iOS достатньо викликати setNotifyValue(true, for:). Але на Android процес складніший: потрібно не тільки ввімкнути сповіщення локально, а й явно записати в дескриптор CCCD (Client Characteristic Configuration Descriptor) значення ENABLE_NOTIFICATION_VALUE. Багато розробників пропускають цей крок — і сповіщення не приходять.
iOS: Notify-підписка та парсинг
// Вмикаємо notify peripheral.setNotifyValue(true, for: characteristic) // Отримуємо дані func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { guard error == nil, let data = characteristic.value else { return } // Приклад: датчик відправляє 3 байти [flags, heartRate, energyExpended] guard data.count >= 2 else { return } let flags = data[0] let heartRate: Int if flags & 0x01 == 0 { // heart rate в 1 байті heartRate = Int(data[1]) } else { // heart rate в 2 байтах (little-endian) heartRate = Int(data[1]) | (Int(data[2]) << 8) } } Робота з бінарними даними через Data + байтові зсуви. Якщо пристрій нестандартний і документація мізерна — Wireshark + BLE sniffer допомагають розібрати протокол.
Android: Notify + CCCD дескриптор
Підписка на notify вимагає двох кроків: увімкнути notify локально і записати в CCCD на пристрої:
fun enableNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) { // Крок 1: вмикаємо locally gatt.setCharacteristicNotification(characteristic, true) // Крок 2: пишемо дескриптор на пристрій val cccd = characteristic.getDescriptor( UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") ) ?: return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { gatt.writeDescriptor(cccd, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) } else { @Suppress("DEPRECATION") cccd.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE @Suppress("DEPRECATION") gatt.writeDescriptor(cccd) } } Крок 2 часто пропускають — і сповіщення не приходять. Це найпоширеніша помилка при роботі з notify.
Чому на Android виникає помилка status 133 і як її уникнути?
Одна критична деталь Android BLE: не можна виконувати кілька GATT-операцій одночасно. Тільки одна операція в польоті. Наступну відправляємо тільки після отримання колбека попередньої. Порушення цього правила призводить до помилки status 133 або втрати даних на більшості Android-пристроїв.
Рішення — черга:
class BleOperationQueue { private val queue: LinkedList<BleOperation> = LinkedList() private var operationInProgress = false fun enqueue(operation: BleOperation) { queue.add(operation) if (!operationInProgress) { executeNext() } } fun onOperationCompleted() { operationInProgress = false executeNext() } private fun executeNext() { val op = queue.poll() ?: return operationInProgress = true op.execute() } } Процес впровадження BLE-обміну
Впровадження надійного BLE-обміну ми розбиваємо на етапи:
- Аналіз протоколу пристрою або специфікації GATT-сервісів.
- Проєктування черги операцій та схеми парсингу даних.
- Реалізація на цільових платформах (iOS/Android) з урахуванням MTU, підключення, перепідключення.
- Тестування на реальних пристроях із різними версіями ОС.
- Інтеграція в додаток замовника та передача документації.
Що входить у роботу
У рамках послуги ми надаємо:
- Аналіз та документування поточного протоколу BLE-пристрою.
- Вихідний код модуля обміну даними на Swift/Kotlin з підтримкою черги операцій та MTU.
- Інтеграційне тестування на 3+ реальних пристроях.
- Коротку документацію по API модуля.
- Консультації протягом місяця після здачі.
Ми гарантуємо стабільну роботу підписки на сповіщення, коректний запис команд та обробку помилок на обох платформах. Зв'яжіться з нами для попередньої оцінки вашого проекту. Отримайте консультацію наших інженерів, якщо ви шукаєте готове рішення для інтеграції BLE-пристрою або зіткнулися з помилками обміну даними.
Терміни та вартість
Термін реалізації під ключ — від 3 до 10 днів залежно від складності бінарного протоколу та кількості платформ. Вартість розраховується індивідуально після аналізу вимог.







