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 — это основной класс 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, который уведомляет об обнаружении сервисов, характеристик и получении данных. Такая асинхронная модель обеспечивает неблокирующую работу UI.
CBCentralManager проходит через несколько состояний, определяющих, доступен ли BLE-стек для работы. Состояние передаётся через делегат: centralManagerDidUpdateState(_:). Разработчик обязан обработать все состояния — не только poweredOn, но и случаи, когда Bluetooth выключен или недоступен.
| Состояние | Значение | Действие разработчика |
|---|---|---|
| .poweredOn | Bluetooth включён и готов | Начать сканирование |
| .poweredOff | Bluetooth выключен | Показать алерт пользователю |
| .unauthorized | Нет разрешения | Запросить разрешение в Settings |
| .unsupported | Устройство не поддерживает BLE | Скрыть BLE-функции |
| .unknown | Состояние не определено | Ожидать следующего обновления |
| .resetting | Bluetooth перезагружается | Ожидать восстановления |
Unauthorized state становится всё более частым с iOS 13+. Начиная с этой версии, приложение должно иметь разрешение NSBluetoothAlwaysUsageDescription в Info.plist. Без него центральный менеджер переходит в состояние .unauthorized, и сканирование невозможно. Пользователь может изменить разрешение в Settings > Privacy > Bluetooth в любой момент.
scanForPeripherals(withServices:options:) — основной метод для запуска сканирования. Параметр withServices принимает массив UUID сервисов для фильтрации: если передать nil, будут обнаружены все устройства, что значительно увеличивает энергопотребление. Рекомендуется всегда фильтровать по UUID сервисов, которые нужны приложению. Опции сканирования включают CBCentralManagerScanOptionAllowDuplicatesKey (повторные уведомления об одном устройстве).
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") // Battery Service
centralManager.scanForPeripherals(
withServices: [serviceUUID],
options: [
CBCentralManagerScanOptionAllowDuplicatesKey: false
]
)
}
}
При обнаружении устройства вызывается centralManager(_:didDiscover:advertisementData:rssi:). Параметр advertisementData содержит полный словарь данных рекламного пакета, включая имя устройства (CBAdvertisementDataLocalNameKey), UUID сервисов (CBAdvertisementDataServiceUUIDsKey) и данные производителя (CBAdvertisementDataManufacturerDataKey). RSSI — уровень сигнала в dBm, доступный в момент обнаружения.
connect(_:options:) — метод для установки BLE-соединения с обнаруженным Peripheral. После вызова connect iOS пытается подключиться к устройству. Успешное подключение подтверждается вызовом centralManager(_:didConnect:), ошибка — centralManager(_:didFailToConnect:error:). Опции подключения включают CBConnectPeripheralOptionNotifyOnConnectionKey, CBConnectPeripheralOptionNotifyOnDisconnectionKey и CBConnectPeripheralOptionNotifyOnNotificationKey для фоновых уведомлений.
// Connect to BLE device
func connectToPeripheral(
_ peripheral: CBPeripheral
) {
centralManager.connect(peripheral, options: nil)
// Set delegate for Peripheral
peripheral.delegate = self
}
// Delegate: successful connection
func centralManager(
_ central: CBCentralManager,
didConnect peripheral: CBPeripheral
) {
print("Connected to " +
"\(peripheral.name ?? "unknown")")
// Start service discovery
peripheral.discoverServices(nil)
}
// Delegate: connection error
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, реализуйте фрагментацию на уровне приложения.
Фоновое сканирование BLE-устройств на iOS требует специальной настройки. Core Bluetooth поддерживает background execution, но с существенными ограничениями. Для работы в фоне необходимо: включить bluetooth-central в Background Modes в Capabilities проекта, инициализировать CBCentralManager с опцией CBCentralManagerOptionRestoreIdentifierKey для state restoration и обрабатывать события центрального менеджера при переходе в фон.
Ограничения фонового BLE в iOS: scanForPeripherals без фильтрации по UUID не работает в фоне. Приложение должно указывать конкретные UUID сервисов для сканирования. iOS может задерживать delivery BLE-событий на неопределённое время. Core Bluetooth автоматически возобновляет сканирование при обнаружении matching-устройства, даже если приложение в фоне. Timeout на фоновое сканирование: 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 секунд.
// Handle disconnect with auto-reconnect
func centralManager(
_ central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: Error?
) {
guard let error = error else {
return // Expected disconnect
}
print("Disconnected: \(error.localizedDescription)")
// Automatic reconnection
if shouldAutoReconnect {
DispatchQueue.main.asyncAfter(
deadline: .now() + reconnectDelay
) {
central.connect(peripheral)
}
}
}
При разработке надёжного BLE-приложения на iOS учитывайте: Core Bluetooth не гарантирует доставку всех пакетов при слабом сигнале. Для надёжной передачи используйте writeType .withResponse (подтверждённая запись) и подписывайтесь на уведомления (setNotifyValue) для получения данных от Peripheral. Ведите лог ошибок для диагностики проблем соединения в продакшене.
Часто задаваемые вопросы
Проверьте состояние менеджера через centralManagerDidUpdateState. Убедитесь, что разрешение NSBluetoothAlwaysUsageDescription есть в Info.plist, Bluetooth включён на устройстве и периферийное устройство рекламируется с правильным типом (connectable advertising, а не non-connectable).
На устройствах с BLE 5.0 (iPhone 8 и новее) — до 7 одновременных подключений. На более старых устройствах — до 3–5. Количество сканируемых устройств не ограничено, но активные подключения имеют жёсткий лимит, установленный Bluetooth Controller.
Рекомендуется сканировать с фильтром по UUID и отключать сканирование, когда устройство найдено. Постоянное сканирование разряжает батарею: 1 час непрерывного сканирования потребляет ~10–15% заряда iPhone. Используйте таймеры и условия для остановки сканирования.
CBCentralManager — для сканирования и подключения к внешним BLE-устройствам (роль Central). CBPeripheralManager — чтобы ваше iOS-устройство само выступало в роли BLE-периферии (рекламировало сервисы). Один экземпляр может быть только в одной роли.
Реализуйте centralManager(_:didDisconnectPeripheral:error:). Если ошибка не nil — запланируйте автоматическое переподключение с exponential backoff (1 с → 2 с → 4 с → 8 с → макс 60 с). Если ошибка nil — устройство отключилось штатно (например, пользователь нажал кнопку на устройстве).
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также