Core Bluetooth — фреймворк Apple для взаимодействия с Bluetooth Low Energy на iOS, iPadOS и macOS. Фреймворк предоставляет полный набор API для работы в обеих ролях BLE: центральное devicesо (CBCentralManager) для сканирования и подключения к периферии, и периферийное devicesо (CBPeripheralManager) для эмуляции BLE-сервера. Core Bluetooth абстрагирует стек BLE-протокола от физического радио до прикладного GATT-профиля. По данным Apple Developer, 2026, Core Bluetooth — единственный официальный API Apple для BLE-разработки, поддерживающий BLE 4.0–5.4 с extended advertising, 2M PHY и LE Audio.
Главное
Core Bluetooth разделяет BLE-стек на две логические роли, определённые спецификацией Bluetooth SIG. Роль центрального devicesа (Central) представлена классом CBCentralManager — он инициирует сканирование, устанавливает соединения и управляет списком подключённых CBPeripheral. Роль периферийного devicesа (Peripheral) представлена CBPeripheralManager — он публикует сервисы и характеристики, отвечает на запросы центрального и отправляет уведомления. Одна iOS-сессия может одновременно работать в обеих ролях на разных BLE-радио, но типовое приложение использует одну роль.
Архитектура Core Bluetooth включает пять ключевых абстракций. CBCentralManager управляет состоянием Bluetooth-адаптера devicesа: poweredOn (готов к работе), poweredOff (Bluetooth disabled), unauthorized (нет разрешения), unsupported (BLE недоступен). CBPeripheral представляет удалённое BLE-devicesо с его UUID, именем, RSSI и GATT-иерархией. CBService — логическая группа характеристик. CBCharacteristic — точка данных для чтения/записи/уведомлений. CBPeripheralManager создаёт локальный GATT-сервер для эмуляции периферии.
| Класс | Роль | Основные методы |
|---|---|---|
| CBCentralManager | Центральное devicesо | scanForPeripherals, connect, cancelPeripheralConnection, retrievePeripherals |
| CBPeripheral | Удалённая периферия | discoverServices, discoverCharacteristics, readValue, writeValue, setNotifyValue |
| CBPeripheralManager | Локальная периферия | addService, removeService, startAdvertising, respondToRequest, updateValue |
| CBCentral | Удалённый центральный | maximumUpdateValueLength, identifier, ancsAuthorized |
Состояния CBCentralManager управляют всеми BLE-операциями. При старте приложения centralManagerDidUpdateState вызывается с текущим состоянием Bluetooth. Если состояние не .poweredOn, любые BLE-вызовы игнорируются системой. Разработчик обязан проверять state перед каждым сканированием и подключением. Переход из .poweredOff в .poweredOn происходит при включении Bluetooth в iOS Settings — делегат получает повторный вызов, и приложение может возобновить сканирование.
CBCentralManager — точка входа для всех BLE-операций со стороны центрального devicesа. Инициализация принимает делегат (CBCentralManagerDelegate) и очередь DispatchQueue — рекомендация Apple использовать main queue для простоты или serial queue для производительности. После инициализации фреймворк автоматически проверяет состояние Bluetooth и вызывает centralManagerDidUpdateState: — первый обязательный делегат для обработки.
Сканирование запускается методом scanForPeripheralsWithServices:options:. Первый параметр — массив CBUUID сервисов для фильтрации: если известны UUID интересующих сервисов, передача их сокращает энергопотребление и время поиска. Если nil, обнаруживаются все BLE-devicesа в зоне действия. Опции включают .allowDuplicatesKey (повторные обнаружения одного devicesа) и .solicitedServiceUUIDsKey (для сервисов, публикуемых на централи).
import CoreBluetooth
class BLECentral: NSObject {
private var centralManager: CBCentralManager!
private var discoveredPeripherals: [CBPeripheral] = []
override init() {
super.init()
centralManager = CBCentralManager(delegate: self, queue: .main)
}
// Start BLE scanning
func startScan() {
guard centralManager.state == .poweredOn else {
print("Bluetooth unavailable")
return
}
// Scan all devices (nil = no filter)
centralManager.scanForPeripherals(withServices: nil,
options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
}
// Stop scanning
func stopScan() {
centralManager.stopScan()
}
// Connect to selected device
func connect(to peripheral: CBPeripheral) {
centralManager.connect(peripheral, options: nil)
}
}
// MARK: - CBCentralManagerDelegate
extension BLECentral: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
startScan()
}
}
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any],
rssi: NSNumber) {
if !discoveredPeripherals.contains(where: { $0.identifier == peripheral.identifier }) {
discoveredPeripherals.append(peripheral)
print("Found devices: \(peripheral.name ?? "Unknown"), RSSI: \(rssi)")
}
}
func centralManager(_ central: CBCentralManager,
didConnect peripheral: CBPeripheral) {
print("Connected: \(peripheral.identifier)")
peripheral.delegate = self
peripheral.discoverServices(nil)
}
func centralManager(_ central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: Error?) {
print("Disconnected: \(peripheral.identifier)")
}
}
Класс BLECentral демонстрирует полный цикл сканирования и подключения BLE-devices. centralManagerDidUpdateState запускает сканирование при включённом Bluetooth. didDiscoverPeripheral собирает найденные devicesа в массив discoveredPeripherals с дедупликацией по identifier. После подключения (didConnect) немедленно запускается discovery сервисов — это обязательный шаг перед любыми GATT-операциями.
CBPeripheralManager — класс для эмуляции BLE-периферийного devicesа на iOS. Приложение в роли периферии может публиковать свои сервисы и характеристики, принимать входящие запросы на чтение/запись от центрального devicesа и отправлять уведомления. CBPeripheralManager используется для BLE-аксессуаров, эмулируемых iPhone: пульты, клавиатуры, трекеры, IoT-шлюзы.
Жизненный цикл CBPeripheralManager начинается с инициализации и делегата CBPeripheralManagerDelegate. После подтверждения poweredOn через peripheralManagerDidUpdateState: публикуются сервисы (addService:) и запускается реклама (startAdvertising:). Рекламные данные CBAdvertisementData включают локальное имя (CBAdvertisementDataLocalNameKey), UUID сервисов (CBAdvertisementDataServiceUUIDsKey) и уровень мощности (CBAdvertisementDataTxPowerLevelKey). Максимальный размер рекламного пакета — 31 bytes для BLE 4.0, 251 bytes для extended advertising BLE 5.0+.
// BLE peripheral on iOS via CBPeripheralManager
class BLEPeripheral: NSObject {
private var peripheralManager: CBPeripheralManager!
let serviceUUID = CBUUID(string: "1234")
let characteristicUUID = CBUUID(string: "5678")
override init() {
super.init()
peripheralManager = CBPeripheralManager(delegate: self, queue: .main)
}
// Publish service with characteristic
func setupService() {
let characteristic = CBMutableCharacteristic(
type: characteristicUUID,
properties: [.read, .write, .notify],
value: nil,
permissions: [.readable, .writeable]
)
let service = CBMutableService(type: serviceUUID, primary: true)
service.characteristics = [characteristic]
peripheralManager.add(service)
}
// Start advertising
func startAdvertising() {
let advertisementData: [String: Any] = [
CBAdvertisementDataLocalNameKey: "My BLE Device",
CBAdvertisementDataServiceUUIDsKey: [serviceUUID]
]
peripheralManager.startAdvertising(advertisementData)
}
}
// MARK: - CBPeripheralManagerDelegate
extension BLEPeripheral: CBPeripheralManagerDelegate {
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
setupService()
}
}
func peripheralManager(_ peripheral: CBPeripheralManager,
didAdd service: CBService,
error: Error?) {
if error == nil {
startAdvertising()
}
}
// Handle read request
func peripheralManager(_ peripheral: CBPeripheralManager,
didReceiveRead request: CBATTRequest) {
let data = "CurrentValue".data(using: .utf8)!
request.value = data
peripheralManager.respond(to: request, withResult: .success)
}
// Handle write request
func peripheralManager(_ peripheral: CBPeripheralManager,
didReceiveWrite requests: [CBATTRequest]) {
for request in requests {
if let value = request.value {
print("Write: \(value)")
}
}
peripheralManager.respond(to: requests.first!, withResult: .success)
}
}
Класс BLEPeripheral создаёт BLE-сервер с одной характеристикой, поддерживающей чтение, запись и уведомления. После инициализации peripheralManagerDidUpdateState публикует сервис через addService:, затем запускает рекламу через startAdvertising:. Обработчики didReceiveRead и didReceiveWrite отвечают на входящие GATT-запросы от центрального devicesа. Для отправки уведомлений используется метод updateValue:forCharacteristic:onSubscribedCentrals:.
GATT-операции (Generic Attribute Profile) — основа обмена данными в Core Bluetooth. После discovery сервисов и характеристик центральное devicesо может выполнять три типа операций: чтение значения характеристики, запись значения и подписка на уведомления/индикации. Каждая операция асинхронна и возвращает результат через соответствующий делегат CBPeripheralDelegate.
Чтение выполняется вызовом readValueForCharacteristic:. Значение приходит в peripheral:didUpdateValueForCharacteristic:error:. Важно: чтение возвращает текущее значение с devicesа, а не кешированное. Если devicesо не поддерживает чтение (свойство .read), вызов вернёт ошибку. Для больших значений (больше MTU) BLE автоматически фрагментирует и собирает данные на уровне GATT.
Запись выполняется writeValue:forCharacteristic:type:. BLE поддерживает две модели записи: withResponse (надежная, с подтверждением) и withoutResponse (быстрая, без подтверждения). Свойство CBCharacteristic.properties определяет доступные типы записи. Максимальный размер одного write-пакета ограничен MTU: 23 bytesа для BLE 4.0 (20 bytes полезных данных + 3 bytesа заголовка), до 247 bytes для BLE 5.0 с extended MTU (MTU 251).
Уведомления активируются вызовом setNotifyValue:true forCharacteristic:. После подписки периферия автоматически отправляет обновления через peripheral:didUpdateValueForCharacteristic: всякий раз, когда значение характеристики меняется. Для отключения уведомлений вызывается setNotifyValue:false forCharacteristic:. Core Bluetooth автоматически управляет CCCD-дескриптором на периферии.
| Операция | Метод | Делегат | Тип передачи |
|---|---|---|---|
| Чтение | readValueForCharacteristic: | didUpdateValueForCharacteristic | Polling (запрос-ответ) |
| Запись withResponse | writeValue:forCharacteristic:type:withResponse | didWriteValueForCharacteristic | С подтверждением |
| Запись withoutResponse | writeValue:forCharacteristic:type:withoutResponse | Нет делегата | Без подтверждения |
| Уведомление | setNotifyValue:true forCharacteristic: | didUpdateNotificationStateForCharacteristic + didUpdateValueForCharacteristic | Push от периферии |
Фоновый режим Core Bluetooth позволяет BLE-приложению продолжать сканирование, поддерживать соединения и получать уведомления при нахождении в background. Для активации требуется: включить capability "Uses Bluetooth LE accessories" в Xcode (Info.plist → Required background modes → App communicates using Core Bluetooth) и добавить ключ "bluetooth-central" в UIBackgroundModes. Для периферийной роли — "bluetooth-peripheral".
State Restoration — механизм Core Bluetooth для восстановления состояния BLE-соединений после перезапуска приложения системой iOS. При активации фонового режима и указании restoreIdentifier в инициализации CBCentralManager или CBPeripheralManager, iOS сохраняет состояние BLE-стека при завершении приложения и восстанавливает его при следующем запуске. Делегат centralManager:willRestoreState: получает словарь с сохранёнными CBPeripheral и ожидающими соединениями.
// Core Bluetooth configuration with State Restoration
class BLECentralWithRestoration: NSObject {
let restoreIdentifier = "com.app.blecentral"
private var centralManager: CBCentralManager!
override init() {
super.init()
let options: [String: Any] = [
CBCentralManagerOptionRestoreIdentifierKey: restoreIdentifier,
CBCentralManagerOptionShowPowerAlertKey: true
]
centralManager = CBCentralManager(delegate: self,
queue: nil,
options: options)
}
}
extension BLECentralWithRestoration: CBCentralManagerDelegate {
// Restore state after restart
func centralManager(_ central: CBCentralManager,
willRestoreState dict: [String : Any]) {
if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey]
as? [CBPeripheral] {
for peripheral in peripherals {
peripheral.delegate = self
// Restore GATT discovery
peripheral.discoverServices(nil)
}
}
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("Bluetooth ready after restoration")
}
}
}
В конфигурации BLECentralWithRestoration ключ CBCentralManagerOptionRestoreIdentifierKey активирует сохранение состояния. Если приложение было завершено iOS (например, из-за нехватки памяти), при следующем запуске centralManager:willRestoreState: получает список ранее подключённых CBPeripheral. Приложение восстанавливает делегаты и выполняет повторный discovery сервисов — пользователь не замечает разрыва соединения. Без State Restoration все BLE-сессии теряются при завершении приложения.
Полный пример BLE-приложения на Swift объединяет центральное и периферийное devicesо в одном проекте. Приложение может работать в двух режимах: обнаруживать и подключаться к BLE-devicesам (Central) или эмулировать BLE-аксессуар (Peripheral). Ниже приведена архитектура с общим менеджером BLE, выбирающим роль при старте.
// Universal BLE manager for central and peripheral
class BLEManager {
enum Role {
case central
case peripheral
}
private let role: Role
private var centralManager: CBCentralManager?
private var peripheralManager: CBPeripheralManager?
let advertisedServiceUUID = CBUUID(string: "A001")
init(role: Role) {
self.role = role
switch role {
case .central:
centralManager = CBCentralManager(delegate: nil, queue: .main)
case .peripheral:
peripheralManager = CBPeripheralManager(delegate: nil, queue: .main)
}
}
// Central device: scanning
func scanForDevices() {
centralManager?.scanForPeripherals(withServices: nil, options: nil)
}
// Peripheral device: advertising
func advertiseService() {
let data: [String: Any] = [
CBAdvertisementDataServiceUUIDsKey: [advertisedServiceUUID]
]
peripheralManager?.startAdvertising(data)
}
}
// Usage on startup
let isCentral = UserDefaults.standard.bool(forKey: "isCentral")
let manager = BLEManager(role: isCentral ? .central : .peripheral)
if isCentral {
manager.scanForDevices()
} else {
manager.advertiseService()
}
Менеджер BLEManager выбирает роль при инициализации и создаёт соответствующий Manager (CBCentralManager или CBPeripheralManager). Флаг роли может храниться в UserDefaults или передаваться через сервер конфигурации. Такой подход позволяет BLE-приложению адаптироваться под сценарий использования: на точке продажи iPhone работает как централь для сканирования платежных терминалов, на IoT-шлюзе — как периферия для сбора данных с датчиков.
Часто задаваемые вопросы
Core Bluetooth — фреймворк Apple для BLE-разработки на iOS, iPadOS и macOS. Предоставляет API для работы центрального (CBCentralManager) и периферийного (CBPeripheralManager) devices. Поддерживает BLE 4.0–5.4, extended advertising, 2M PHY и LE Audio. Core Bluetooth — единственный официальный API Apple для BLE-коммуникации, обязательный для всех iOS-приложений, работающих с Bluetooth Low Energy.
CBCentralManager — класс для работы в роли центрального devicesа: сканирует BLE-периферию, устанавливает соединения, читает и пишет характеристики. CBPeripheralManager — класс для работы в роли периферии: публикует сервисы, отвечает на запросы чтения/записи и отправляет уведомления. Один iPhone может работать в двух ролях одновременно через разные инстансы менеджеров.
Для фоновой BLE-работы включите capability "Uses Bluetooth LE accessories" в Xcode и добавьте ключ "bluetooth-central" в UIBackgroundModes. Для периферийной роли — "bluetooth-peripheral". Укажите restoreIdentifier при инициализации менеджера для State Restoration. Без этих настроек приложение в background не получает BLE-события и теряет соединения.
Основные причины: CBCentralManager.state != .poweredOn (Bluetooth disabled или не авторизован), делегат не установлен, devicesо вне зоны действия или не отправляет рекламные пакеты. Проверьте разрешение NSBluetoothAlwaysUsageDescription в Info.plist, статус Bluetooth в centralManagerDidUpdateState и убедитесь, что scanForPeripherals вызывается только при .poweredOn.
Да, Core Bluetooth поддерживает одновременное подключение к нескольким BLE-devicesам. Каждый CBPeripheral управляется независимо через собственный делегат. iOS ограничивает количество одновременных BLE-соединений на уровне системы (обычно 5–7 для iPhone). Для 1:N сценариев (например, фитнес-центр с 10 трекерами) требуется постановка в очередь и циклическое обслуживание периферий.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также