Організація 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 днів залежно від складності бінарного протоколу та кількості платформ. Вартість розраховується індивідуально після аналізу вимог.
Інтеграція з залізом: BLE, NFC, IoT та HomeKit у мобільних додатках
Коли задача — зв’язати смартфон з фізичним пристроєм, половина проблем знаходиться не в коді, а в прошивці заліза, характеристиках BLE-сервісів та затримках протоколу. Ми, як мобільні розробники, працюємо на стику з firmware-командою, і без розуміння стеку знизу вгору результат непередбачуваний. Ось чому ми завжди починаємо з HCI-логу та специфікації GATT — Apple Developer: Core Bluetooth Framework — це єдиний спосіб уникнути реверс-інжинірингу в польових умовах.
Чому BLE-інтеграція — найчастіша точка відмови?
Bluetooth Low Energy — основний протокол для носимих, медичних пристроїв, розумних замків та промислових датчиків. Core Bluetooth на iOS та BluetoothGatt на Android реалізують одну специфікацію, але поводяться по-різному в крайніх випадках. Статистика наших проектів: більше 70% звернень у підтримку по BLE пов’язані саме з низькорівневими помилками GATT, а не з логікою додатку.
| Сценарій |
iOS (Core Bluetooth) |
Android (BluetoothGatt) |
| Управління підключенням |
CBCentralManager потребує сильного посилання протягом всієї сесії; втрата об’єкта → розрив з’єднання |
disconnect() та close() викликаються окремо; close() без disconnect() → пристрій позначається зайнятим |
| Типова помилка |
Немає попередження при втраті посилання — з’єднання мовчки розривається |
Помилка 133 (GATT_ERROR) — виникає при переповненні черги GATT або некоректному закритті попередньої сесії |
| Сканування |
NSBluetoothAlwaysUsageDescription обов’язковий у Info.plist (з iOS 13); без нього сканування не стартує |
BLUETOOTH_SCAN потребує neverForLocation (Android 12+), інакше користувач бачить запит геолокації |
Що робити з помилкою 133 в Android?
Помилка 133 — найчастіша в Android BLE-розробці. Це не «щось пішло не так», а конкретний індикатор переповнення черги GATT або некоректного закриття попереднього з’єднання. Ми лікуємо її двома прийомами: використовуємо чергу операцій над GATT (write, read, notification subscribe строго послідовно через операційну чергу) та завжди викликаємо disconnect() перед close(). Наша черга GATT-операцій у 3 рази знижує кількість помилок ATT_INSUFFICIENT_RESOURCES порівняно з конкурентними запитами. MTU за замовчуванням — 23 байти. Запит на збільшення (MTU exchange) обов’язковий для передачі даних об’ємом понад 20 байт. На iOS MTU запитується автоматично при підключенні, на Android потрібно явно викликати requestMtu(). Без цього ви не зможете передати, наприклад, зображення або лог через характеристику.
NFC: CoreNFC та Android NFC API
iOS підтримує NFC-читання через CoreNFC з версії iOS 11, запис — з iOS 13. Важливе обмеження: сесія сканування активна лише поки живий об’єкт NFCNDEFReaderSession і показує системний UI. Фонове сканування доступне лише для додатків з entitlement com.apple.developer.nfc.readersession.formats і лише для ISO 14443 (банківські картки, паспорти) — і цей entitlement видається не всім. На Android все простіше: NfcAdapter.enableForegroundDispatch() ловить теги у foreground без системного UI. Фоновий запуск додатку по NFC-тегу реалізується через intent-filter з ACTION_NDEF_DISCOVERED. Порівняння платформ по NFC:
| Функція |
iOS (CoreNFC) |
Android (NfcAdapter) |
| Фонове читання |
Тільки з entitlement та ISO 14443 |
Через intent-filter ACTION_NDEF_DISCOVERED |
| Запис |
З iOS 13 (NDEF) |
З коробки (API 10+) |
| Сесія |
Триває до 5 хвилин з системним UI |
Необмежено у foreground, background по тегу |
| Запуск додатку |
Тільки foreground |
Автоматично при виявленні тегу |
HomeKit та Matter
HomeKit — екосистема Apple для розумного дому. Для інтеграції пристрій повинен мати MFi-сертифікацію (або працювати через Software Authentication для Matter). Мобільний додаток використовує HomeKit framework: HMHomeManager → HMHome → HMRoom → HMAccessory → HMService → HMCharacteristic. Matter (раніше CHIP) — крос-платформний стандарт, який підтримують Apple, Google, Amazon та Samsung. На iOS Matter-пристрої додаються через MTRDeviceController, на Android — через Google Home SDK або Matter SDK безпосередньо. Перевага Matter: один пристрій працює з HomeKit, Google Home та Alexa без перепрошивки, а конфігурація налаштовується в 4 рази швидше порівняно з власним HAP-протоколом.
| Параметр |
HomeKit |
Matter |
| Сертифікація |
MFi — апаратний чіп |
Software Authentication (ключі) |
| Підтримка платформ |
Тільки Apple |
Apple, Google, Amazon, Samsung |
| Додавання пристрою |
HMHomeManager |
MTRDeviceController / Google Home SDK |
| Протокол |
HAP (IP, BLE) |
IP-based (Wi-Fi, Thread) |
Для Flutter та React Native використовуємо flutter_blue_plus та react-native-ble-plx відповідно — обидва активно підтримуються і покривають 90% сценаріїв, але для роботи з GATT-нотифікаціями у background на Android все одно потрібен foreground service. Переконайтеся, що deep linking (Universal Links на iOS, App Links на Android) налаштовані для коректного пробудження додатку при скануванні NFC-тегу або отриманні push-повідомлення від IoT-пристрою. Вимоги ATT (App Tracking Transparency) для інтеграції з залізом зазвичай не застосовуються, але якщо додаток збирає анонімну аналітику — додайте запит. Отримайте консультацію нашого інженера — він розбере вашу специфікацію за 2 дні.
Як ми інтегруємо BLE та NFC?
-
Аналітика — отримуємо від firmware-команди повну специфікацію BLE GATT (список сервісів, характеристик, формати даних) або HCI-лог. Без цього розробка перетворюється на реверс-інжиніринг через nRF Connect або Wireshark over HCI.
-
Проектування — визначаємо архітектуру підключень: чергу GATT-операцій, фонові сервіси для Android, перепідключення при втраті зв’язку. Враховуємо MTU-узгодження та обробку помилок ATT_INSUFFICIENT_RESOURCES.
-
Реалізація — кодимо на Swift/Kotlin з урахуванням особливостей платформ (Universal Links, App Links, push-повідомлення через APNs/FCM для тригерів). Для захисту Android-коду використовуємо ProGuard / R8 (shrink).
-
Тестування — на реальних пристроях з першого дня. Емулятор BLE в симуляторах не відтворює edge cases перепідключення, втрати сигналу, зміни MTU. Використовуємо автоматизацію на базі XCTest та Espresso.
-
Деплой — завантаження в App Store Connect / Google Play Console з правильним code signing та provisioning profile. Для iOS — TestFlight, для Android — Firebase App Distribution.
Що входить в роботу (deliverables)
- Вихідний код мобільного додатку з інтеграцією BLE, NFC або IoT (Swift / Kotlin / Flutter / React Native)
- Документація по протоколу GATT (карта сервісів та характеристик)
- Навантажувальне тестування на 10+ реальних пристроях (помилка 133, перепідключення, MTU-узгодження)
- Аналіз та усунення edge cases (помилка ATT_INSUFFICIENT_RESOURCES, втрата з’єднання на фоні, конфлікт з background fetch)
- Інструкція зі збірки та деплою (code signing, TestFlight, Firebase App Distribution)
- Місяць підтримки після релізу
Строки та орієнтовна вартість
Проста інтеграція з одним BLE-периферійним пристроєм (показання + команди керування) — від 2 до 4 тижнів. Типова вартість такої задачі розраховується індивідуально, включаючи налагодження GATT-профілю та обробку edge cases. Повноцінний IoT-додаток з декількома типами пристроїв, firmware OTA-оновленнями та HomeKit-підтримкою — від 2 місяців. Вартість розраховується індивідуально під ваш проект.
Ми займаємося мобільною розробкою кілька років — досвід 45+ проектів з BLE/NFC/HomeKit. Наші інженери сертифіковані Apple та Google, а кожен етап роботи фіксується в issue tracker з прив’язкою до комітів. Ми гарантуємо прозорість процесу та дотримання строків. Використовуємо підхід «інженер клієнту»: без маркетингових пауз, з прямим доступом до розробника.
Закажіть оцінку — отримайте консультацію інженера з розбором вашої специфікації. Замовте інтеграцію під ключ: ми проаналізуємо HCI-лог, перевіримо GATT-характеристики та запропонуємо архітектуру за 2 дні.