BLE-інтеграція: стабільна робота з пристроями

BLE-інтеграція: стабільна робота з пристроями Ми часто бачимо проекти, де BLE-підключення реалізоване як «увімкнув сканування — підключився — радіємо». У реальності це кінцевий автомат з дюжиною станів, кожен з яких може завершитися помилкою: адаптер вимкнено, пристрій поза зоною, сервіс не знайд

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
BLE-інтеграція: стабільна робота з пристроями
Складний
~3-5 днів

Наші компетенції:

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

BLE-інтеграція: стабільна робота з пристроями

Ми часто бачимо проекти, де BLE-підключення реалізоване як «увімкнув сканування — підключився — радіємо». У реальності це кінцевий автомат з дюжиною станів, кожен з яких може завершитися помилкою: адаптер вимкнено, пристрій поза зоною, сервіс не знайдено, характеристика не підтримує запис. Наша команда — спеціалісти з 5+ річним досвідом розробки BLE-рішень для iOS та Android. Ми гарантуємо, що ваше застосування стабільно обробляє всі граничні випадки. Наша реалізація зменшує кількість обривів з'єднання в 5 разів порівняно з непрофесійною інтеграцією.

Чому BLE-інтеграція потребує професійного підходу?

BLE працює за моделлю GATT (Generic Attribute Profile). Периферійний пристрій надає Services — логічні групи функцій. Кожен Service містить Characteristics — конкретні значення для читання, запису або підписки (notify/indicate). Помилка на будь-якому з цих рівнів — і застосування не отримає дані. Ми бачили проекти, де розробники забували підписуватися на дескриптор CCCD — в результаті характеристика не надсилала сповіщення.

Кінцевий автомат підключення

Мінімальний набір станів, які потрібно обробляти явно:

IDLE → SCANNING → DISCOVERED → CONNECTING → CONNECTED → DISCOVERING_SERVICES → SERVICES_READY → SUBSCRIBING → READY 

І помилки на кожному переході: таймаут сканування, розрив з'єднання в CONNECTING, gattStatus != GATT_SUCCESS при discovery, втрата з'єднання в READY. Тестуємо всі сценарії за допомогою симуляторів та реальних пристроїв.

Стан iOS (CoreBluetooth) Android (BluetoothGatt)
IDLE .poweredOn BluetoothAdapter.state_on
SCANNING scanForPeripherals startScan
DISCOVERED didDiscover onScanResult
CONNECTING connect connectGatt
CONNECTED didConnect onConnectionStateChange (STATE_CONNECTED)
DISCOVERING_SERVICES discoverServices discoverServices
SERVICES_READY didDiscoverServices onServicesDiscovered
SUBSCRIBING setNotifyValue writeDescriptor (CCCD)
READY didUpdateValue onCharacteristicChanged

Що робити, якщо з'єднання розірвалося?

Найчастіша помилка — ігнорування didDisconnectPeripheral (iOS) або onConnectionStateChange з не-GATT_SUCCESS (Android). Без автоматичного реконекту користувач змушений перезапускати застосування. Ми реалізуємо логіку з експоненційним backoff: при розриві чекаємо 1 с, 2 с, 4 с, 8 с, потім скидаємо. На iOS для роботи у фоні використовуємо CBCentralManagerOptionRestoreIdentifierKey — system wakes up the app when device reappears.

iOS: CoreBluetooth

import CoreBluetooth class BLEManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate { var centralManager: CBCentralManager! var targetPeripheral: CBPeripheral? override init() { super.init() centralManager = CBCentralManager(delegate: self, queue: DispatchQueue(label: "ble.queue")) } func centralManagerDidUpdateState(_ central: CBCentralManager) { guard central.state == .poweredOn else { // обрабатываем .poweredOff, .unauthorized, .unsupported return } startScanning() } func startScanning() { let serviceUUID = CBUUID(string: "180D") centralManager.scanForPeripherals(withServices: [serviceUUID], options: [ CBCentralManagerScanOptionAllowDuplicatesKey: false ]) } func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { guard RSSI.intValue > -80 else { return } // фильтр по сигналу centralManager.stopScan() targetPeripheral = peripheral centralManager.connect(peripheral, options: nil) } func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { peripheral.delegate = self peripheral.discoverServices([CBUUID(string: "180D")]) } func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { guard error == nil, let services = peripheral.services else { return } for service in services { peripheral.discoverCharacteristics([CBUUID(string: "2A37")], for: service) } } func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { guard let characteristics = service.characteristics else { return } for char in characteristics where char.properties.contains(.notify) { peripheral.setNotifyValue(true, for: char) } } func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { guard let data = characteristic.value else { return } // парсим data согласно GATT-спецификации характеристики } } 

Android: BluetoothGatt

val gattCallback = object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) { if (status != BluetoothGatt.GATT_SUCCESS) { // status содержит код ошибки, например 133 (GATT_ERROR) - нужен реконнект gatt.close() return } if (newState == BluetoothProfile.STATE_CONNECTED) { gatt.discoverServices() } } override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) { val characteristic = gatt .getService(UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb")) ?.getCharacteristic(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb")) ?: return gatt.setCharacteristicNotification(characteristic, true) val descriptor = characteristic.getDescriptor( UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") // Client Characteristic Configuration ) descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE gatt.writeDescriptor(descriptor) } override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) { val data = characteristic.value // парсим } } device.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE) 

Проблеми, які ми вирішуємо в кожному проекті

Проблема Рішення
didDisconnectPeripheral без попередження Автореконект з backoff, restoration identifier (iOS)
Статус 133 GATT_ERROR на Android gatt.close(), refresh() через рефлексію, повтор через 2 с
Сканування вбиває батарею allowDuplicates: false — вмикаємо тільки при вимірюванні RSSI
State restoration не працює Налаштовуємо CBCentralManagerOptionRestoreIdentifierKey у схемі
Android 12+ дозволи Запитуємо BLUETOOTH_SCAN та BLUETOOTH_CONNECT динамічно

Що входить в роботу з інтеграції BLE

  • Документація по GATT-схемі пристрою (сервіси, характеристики, формати даних)
  • Реалізація сканування, підключення, підписки, реконекту
  • Обробка всіх штатних та аварійних станів
  • Оптимізація MTU: запит 512 байт замість 23 для прискорення передачі
  • Інтеграція з тестовим пристроєм (наданим замовником або нашим)
  • Unit-тести та сценарії навантажувального тестування (до 10 одночасних BLE-периферій)
  • Підтримка після здачі: гарантія 3 місяці на стабільність з'єднання
  • Ціна: від 500$ за базовий модуль

Як ми працюємо: від аналізу до деплою

  1. Аналітика — вивчаємо документацію пристрою, узгоджуємо GATT-схему та формат даних.
  2. Проектування — створюємо кінцевий автомат, визначаємо політику реконекту.
  3. Реалізація — пишемо код на Swift/Kotlin з використанням сучасних фреймворків.
  4. Тестування — перевіряємо на симуляторах, реальних пристроях, з емуляцією перешкод.
  5. Деплой — публікуємо в TestFlight / Firebase Distribution, допомагаємо з App Review (перевірка розділу 4.2 та 5.1 App Store Review Guidelines).

Продуктивність і батарея

MTU за замовчуванням — 23 байти. Запитуємо через gatt.requestMtu(512) / peripheral.maximumWriteValueLength(for: .withResponse). Оптимізація MTU прискорює передачу даних до 22 разів порівняно зі стандартним розміром пакета. На одному з проектів для фітнес-трекера ми скоротили час передачі даних з 8 с до 1.2 с завдяки оптимізації MTU та реконекту. Економія енергії до 60% на пристроях з обмеженим каналом. Економічна ефективність інтеграції BLE під ключ очевидна — ви отримуєте готове рішення без необхідності вникати в тонкощі GATT.

Детальніше про MTU

За замовчуванням BLE використовує MTU 23 байти, з яких 3 — службові. Ми запитуємо 512 байт, що в 22 рази більше. Для передачі даних об'ємом 1 Кбайт це скорочує кількість пакетів з 50 до 3. На пристроях з обмеженим каналом (наприклад, фітнес-браслети) це економить до 60% енергії.

Терміни та умови

Базова інтеграція (один notify-сервіс) — 3-5 днів, від 500$. Складні сценарії (OTA, мультипериферія, background mode) — 1-2 тижні. Вартість базової інтеграції — від 500$. Зв'яжіться з нами для безкоштовної оцінки вашого проекту. Замовте інтеграцію BLE сьогодні — ми запропонуємо варіанти реалізації.

Рекомендуємо прочитати офіційну документацію CoreBluetooth та Android BluetoothGatt для більш детального розуміння API. Докладніше про GATT читайте в Wikipedia.