Реалізація обміну даними з BLE-периферією

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

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

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

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

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

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

Етапи розробки

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

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Реалізація обміну даними з BLE-периферією

Після того як з'єднання встановлено і сервіси виявлені, починається основна робота: читання значень, запис команд, підписка на сповіщення. Ця частина BLE-стека потребує розуміння GATT-атрибутів, MTU та особливостей конкретних платформ при роботі з бінарними даними.

Типи операцій з характеристиками

Характеристика має флаги 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 — для команд, де важлива гарантія доставки.

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 {
        // частота серцевих скорочень в 1 байті
        heartRate = Int(data[1])
    } else {
        // частота серцевих скорочень в 2 байтах (little-endian)
        heartRate = Int(data[1]) | (Int(data[2]) << 8)
    }
}

Робота з бінарними даними через Data + байтові зміщення. Якщо пристрій нестандартний і документація скудна — Wireshark + BLE sniffer (Ellisys, Nordic nRF Sniffer) допомагають розібрати протокол.

Запис команди

func sendCommand(_ command: UInt8, value: UInt16) {
    var bytes: [UInt8] = [command, UInt8(value & 0xFF), UInt8(value >> 8)]
    let data = Data(bytes)

    let writeType: CBCharacteristicWriteType = characteristic.properties.contains(.writeWithoutResponse)
        ? .withoutResponse
        : .withResponse

    peripheral.writeValue(data, for: characteristic, type: writeType)
}

При .withResponse — чекаємо callback didWriteValueFor. При .withoutResponse на iOS 11+ потрібно перевіряти peripheral.canSendWriteWithoutResponse перед відправкою, інакше дані втрачаються при переповненні буфера.

Android: BluetoothGatt в деталях

Notify + дескриптор CCCD

Підписка на notify потребує двох кроків: включити notify локально та записати в CCCD (Client Characteristic Configuration Descriptor) на пристрої:

fun enableNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
    // Крок 1: включаємо локально
    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 BLE: не можна виконувати декілька GATT-операцій одночасно. Тільки одна операція у польоті. Наступну відправляємо тільки після отримання callback попередньої.

Порушення цього правила призводить до помилки 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()
    }
}

MTU та великі дані

За замовчуванням MTU = 23 байти (20 байт корисного навантаження після GATT заголовка). Для передачі прошивки або великих конфігів це катастрофічно мало.

Запитуємо збільшений MTU одразу після встановлення з'єднання:

// iOS
peripheral.maximumWriteValueLength(for: .withoutResponse) // повертає поточний max
// MTU negotiation автоматична через iOS 9+, можна впливати опосередковано
// Android
gatt.requestMtu(512) // в onMtuChanged отримаємо реальний узгоджений розмір

На практиці більшість BLE-чипів підтримує MTU 247–512 байт. Це перетворює передачу 10KB даних зі 500 пакетів на 20–40.

Термін реалізації: 3–5 днів — повнофункціональний обмін даними з чергою операцій, MTU negotiation та обробка помилок на обох платформах. Вартість розраховується індивідуально.