CBCentralManager в iOS — що це, управління BLE та Core Bluetooth

Автор: IT Sectr Опубліковано: 2026-07-16 Час читання: 11 хв

CBCentralManager — це центральний клас фреймворку Core Bluetooth в iOS, який керує скануванням, підключенням та взаємодією з BLE-периферійними пристроями. Core Bluetooth (iOS 5+, 2011) надає високорівневу абстракцію над BLE-стеком на рівні GATT, приховуючи від розробника деталі Link Layer та HCI. CBCentralManager реалізує роль Central: він сканує ефір через scanForPeripherals, ініціює підключення через connect, виявляє сервіси через discoverServices та керує передачею даних. За даними Apple Developer Documentation (2024), CBCentralManager підтримує до 7 одночасних підключень до BLE-пристроїв на пристроях з BLE 5.0.

Головне

  • CBCentralManager — клас iOS для керування BLE-скануванням, підключенням та передачею даних у ролі Central.
  • Сканування запускається через scanForPeripherals з фільтрацією за UUID сервісів для економії енергії.
  • Підключення виконується через connect(peripheral:options:) з відстеженням стану через делегат.
  • iOS підтримує до 7 одночасних BLE-підключень на пристроях з BLE 5.0.
  • Фонове сканування потребує включення bluetooth-central у Background Modes та використання CBCentralManagerScanOptionAllowDuplicatesKey.

Що таке CBCentralManager?

CBCentralManager — це основний клас Core Bluetooth для реалізації ролі Central в BLE-архітектурі на iOS. Він керує всім життєвим циклом BLE-з'єднання: від сканування пристроїв, що рекламуються, до передачі даних та відключення. CBCentralManager працює асинхронно через делегат CBCentralManagerDelegate, сповіщаючи додаток про події в Bluetooth-стеку.

Ініціалізація CBCentralManager запускає процес state restoration: менеджер перевіряє стан Bluetooth на пристрої та відновлює попередні з'єднання, якщо додаток було закрито. Процес ініціалізації може тривати від 50 до 500 мс залежно від стану Bluetooth. Додаток має дочекатися виклику centralManagerDidUpdateState перед початком будь-яких BLE-операцій.

Архітектура Core Bluetooth побудована на шаблоні Delegation: CBCentralManager делегує обробку подій (виявлення пристроїв, підключення, помилки) протоколу CBCentralManagerDelegate. Для роботи з конкретним Peripheral використовується протокол CBPeripheralDelegate, який сповіщає про виявлені сервіси, характеристики та отримані дані. Така асинхронна модель забезпечує неблокуючий інтерфейс користувача.

Стани CBCentralManager

CBCentralManager проходить через кілька станів, які визначають, чи доступний BLE-стек для роботи. Стан передається через делегат: centralManagerDidUpdateState(_:). Розробник зобов'язаний обробити всі стани — не тільки poweredOn, але й випадки, коли Bluetooth вимкнено або недоступний.

СтанЗначенняДія розробника
.poweredOnBluetooth увімкнено та готовийПочати сканування
.poweredOffBluetooth вимкненоПоказати сповіщення користувачеві
.unauthorizedНемає дозволуЗапросити дозвіл у Налаштуваннях
.unsupportedПристрій не підтримує BLEПриховати BLE-функції
.unknownСтан не визначеноОчікувати наступного оновлення
.resettingBluetooth перезавантажуєтьсяОчікувати відновлення

Unauthorized state стає все більш поширеним з iOS 13+. Починаючи з цієї версії, додаток повинен мати дозвіл NSBluetoothAlwaysUsageDescription у Info.plist. Без нього центральний менеджер переходить у стан .unauthorized, і сканування неможливе. Користувач може змінити дозвіл у Налаштуваннях > Конфіденційність > Bluetooth у будь-який момент.

Сканування BLE-пристроїв

scanForPeripherals(withServices:options:) — основний метод для запуску сканування. Параметр withServices приймає масив UUID сервісів для фільтрації: якщо передати nil, будуть виявлені всі пристрої, що значно збільшує енергоспоживання. Рекомендується завжди фільтрувати за UUID сервісів, які потрібні додатку. Опції сканування включають CBCentralManagerScanOptionAllowDuplicatesKey (повторні сповіщення про один пристрій).

swift
import CoreBluetooth

class BLEController: NSObject,
    CBCentralManagerDelegate {

    private var centralManager: CBCentralManager!

    override init() {
        super.init()
        centralManager =
            CBCentralManager(
                delegate: self,
                queue: nil
            )
    }

    func startScanning() {
        let serviceUUID =
            CBUUID("180F") // Сервіс батареї

        centralManager.scanForPeripherals(
            withServices: [serviceUUID],
            options: [
                CBCentralManagerScanOptionAllowDuplicatesKey: false
            ]
        )
    }
}

При виявленні пристрою викликається centralManager(_:didDiscover:advertisementData:rssi:). Параметр advertisementData містить повний словник даних рекламного пакета, включаючи ім'я пристрою (CBAdvertisementDataLocalNameKey), UUID сервісів (CBAdvertisementDataServiceUUIDsKey) та дані виробника (CBAdvertisementDataManufacturerDataKey). RSSI — рівень сигналу в dBm, доступний у момент виявлення.

Підключення до Peripheral

connect(_:options:) — метод для встановлення BLE-з'єднання з виявленим Peripheral. Після виклику connect iOS намагається підключитися до пристрою. Успішне підключення підтверджується викликом centralManager(_:didConnect:), помилка — centralManager(_:didFailToConnect:error:). Опції підключення включають CBConnectPeripheralOptionNotifyOnConnectionKey, CBConnectPeripheralOptionNotifyOnDisconnectionKey та CBConnectPeripheralOptionNotifyOnNotificationKey для фонових сповіщень.

swift
// Підключитися до BLE пристрою
func connectToPeripheral(
    _ peripheral: CBPeripheral
) {
    centralManager.connect(peripheral, options: nil)

    // Встановити делегат для Peripheral
    peripheral.delegate = self
}

// Делегат: успішне підключення
func centralManager(
    _ central: CBCentralManager,
    didConnect peripheral: CBPeripheral
) {
    print("Підключено до " +
          "\(peripheral.name ?? "unknown")")

    // Почати виявлення сервісів
    peripheral.discoverServices(nil)
}

// Делегат: помилка підключення
func centralManager(
    _ central: CBCentralManager,
    didFailToConnect peripheral: CBPeripheral,
    error: Error?
) {
    print("Connection failed: 
          \(error?.localizedDescription ?? "")")
}

Таймаут підключення на iOS становить 30 секунд. Якщо за цей час пристрій не відповів на connection request, викликається didFailToConnect. На таймаут впливають: відстань до пристрою, перешкоди, чи рекламується пристрій у даний момент. Перед підключенням переконайтеся, що пристрій знаходиться в режимі connectable advertising (ADV_IND, а не ADV_NONCONN_IND).

Виявлення сервісів та характеристик

Після підключення необхідно виявити сервіси (discoverServices) та характеристики (discoverCharacteristics) Peripheral. Це обов'язковий крок перед читанням або записом даних. Процес асинхронний: discoverServices повертає результат через peripheral(_:didDiscoverServices:), а discoverCharacteristics — через peripheral(_:didDiscoverCharacteristicsFor:error:).

Рекомендується передавати в discoverServices масив потрібних UUID, а не nil. Фільтрація прискорює виявлення та економить енергію. Якщо сервіс не буде знайдено, iOS повідомить порожній масив. Після виявлення характеристик можна читати їх значення (readValue), підписуватися на сповіщення (setNotifyValue) або записувати дані (writeValue).

Важливий нюанс: MTU узгоджується автоматично після підключення. Для отримання поточного MTU використовуйте peripheral.maximumWriteValueLength(for: .withResponse) або .withoutResponse. В iOS максимальний MTU — 512 байт для BLE 5.0 пристроїв. Якщо потрібно передати дані більше MTU, реалізуйте фрагментацію на рівні додатка.

Фонове сканування та обмеження iOS

Фонове сканування BLE-пристроїв на iOS потребує спеціального налаштування. Core Bluetooth підтримує background execution, але з суттєвими обмеженнями. Для роботи в фоні необхідно: включити bluetooth-central у Background Modes в Capabilities проекту, ініціалізувати CBCentralManager з опцією CBCentralManagerOptionRestoreIdentifierKey для state restoration та обробляти події центрального менеджера при переході в фон.

Обмеження фонового BLE в iOS: scanForPeripherals без фільтрації за UUID не працює в фоні. Додаток повинен вказувати конкретні UUID сервісів для сканування. iOS може затримувати доставку BLE-подій на невизначений час. Core Bluetooth автоматично відновлює сканування при виявленні matching-пристрою, навіть якщо додаток у фоні. Таймаут на фонове сканування: iOS може зупинити сканування через 10–30 хвилин для економії енергії.

State Restoration — механізм Core Bluetooth, який дозволяє відновити BLE-з'єднання після перезапуску додатка або перезавантаження iOS. Для його використання: вкажіть CBCentralManagerOptionRestoreIdentifierKey при ініціалізації, реалізуйте centralManager(_:willRestoreState:) у делегаті та відновіть список підключених Peripheral з переданого словника. State Restoration — критичний функціонал для BLE-додатків, що працюють у фоні, наприклад фітнес-трекерів або медичних пристроїв.

Обробка помилок та відновлення з'єднання

CBCentralManager генерує помилки в кількох сценаріях: підключення не вдалося (didFailToConnect), з'єднання розірвано (didDisconnectPeripheral), характеристика недоступна для читання/запису (didWriteValue error). Всі помилки Core Bluetooth повертаються через об'єкт Error з доменом CBErrorDomain. Найчастіші коди: CBErrorConnectionTimeout (0x04), CBErrorPeripheralDisconnected (0x07), CBErrorOperationNotSupported (0x0A).

Стратегія відновлення з'єднання: при отриманні didDisconnectPeripheral перевірте код помилки. Якщо помилка CBErrorConnectionTimeout або CBErrorPeripheralDisconnected — заплануйте автоматичне перепідключення через 1–5 секунд. Якщо помилка CBErrorOperationNotSupported — логуйте і не намагайтеся повторити операцію. Для критично важливих з'єднань (медичні пристрої) використовуйте exponential backoff з максимальним інтервалом 60 секунд.

swift
// Обробка відключення з автоматичним перепідключенням
func centralManager(
    _ central: CBCentralManager,
    didDisconnectPeripheral peripheral: CBPeripheral,
    error: Error?
) {
    guard let error = error else {
        return // Очікуване відключення
    }

    print("Disconnected: \(error.localizedDescription)")

    // Автоматичне перепідключення
    if shouldAutoReconnect {
        DispatchQueue.main.asyncAfter(
            deadline: .now() + reconnectDelay
        ) {
            central.connect(peripheral)
        }
    }
}

При розробці надійного BLE-додатка на iOS враховуйте: Core Bluetooth не гарантує доставку всіх пакетів при слабкому сигналі. Для надійної передачі використовуйте writeType .withResponse (підтверджений запис) та підписуйтеся на сповіщення (setNotifyValue) для отримання даних від Peripheral. Ведіть лог помилок для діагностики проблем з'єднання в продакшені.

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

Чому CBCentralManager не виявляє пристрої?

Перевірте стан менеджера через centralManagerDidUpdateState. Переконайтеся, що дозвіл NSBluetoothAlwaysUsageDescription є в Info.plist, Bluetooth увімкнено на пристрої та периферійний пристрій рекламується з правильним типом (connectable advertising, а не non-connectable).

Скільки BLE-пристроїв може одночасно підключитися до iOS?

На пристроях з BLE 5.0 (iPhone 8 та новіші) — до 7 одночасних підключень. На старіших пристроях — до 3–5. Кількість пристроїв, що скануються, не обмежена, але активні підключення мають жорсткий ліміт, встановлений Bluetooth Controller.

Як часто можна сканувати BLE на iOS без втрати батареї?

Рекомендується сканувати з фільтром за UUID і вимикати сканування, коли пристрій знайдено. Постійне сканування розряджає батарею: 1 година безперервного сканування споживає ~10–15% заряду iPhone. Використовуйте таймери та умови для зупинки сканування.

У чому різниця між CBCentralManager та CBPeripheralManager?

CBCentralManager — для сканування та підключення до зовнішніх BLE-пристроїв (роль Central). CBPeripheralManager — щоб ваш iOS-пристрій сам виступав у ролі BLE-периферії (рекламував сервіси). Один екземпляр може бути тільки в одній ролі.

Як обробити втрату з'єднання з BLE-пристроєм?

Реалізуйте centralManager(_:didDisconnectPeripheral:error:). Якщо помилка не nil — заплануйте автоматичне перепідключення з exponential backoff (1 с → 2 с → 4 с → 8 с → макс 60 с). Якщо помилка nil — пристрій відключився штатно (наприклад, користувач натиснув кнопку на пристрої).

Підсумки

  • CBCentralManager — головний клас Core Bluetooth для керування BLE-скануванням, підключенням та передачею даних у ролі Central на iOS.
  • Сканування запускається через scanForPeripherals з опціональною фільтрацією за UUID сервісів для зниження енергоспоживання.
  • Підключення виконується через connect, успіх підтверджується didConnect, помилка — didFailToConnect з таймаутом 30 секунд.
  • Після підключення необхідно виявити сервіси та характеристики через discoverServices та discoverCharacteristics.
  • Фонове сканування потребує bluetooth-central Background Mode та підтримується з обмеженнями (фільтрація за UUID, можливі затримки).
  • iOS підтримує до 7 одночасних BLE-підключень на пристроях з BLE 5.0, state restoration — для відновлення після перезапуску.
  • Обробка помилок та автоматичне перепідключення з exponential backoff — основа надійного BLE-додатка на iOS.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також