Core Bluetooth: архитектура и разработка на BLE на iOS

Автор: IT Sectr Публикувано: 2026-07-16 Време за четене: 10 мин

Core Bluetooth е рамката на Apple за взаимодействие с Bluetooth Low Energy на iOS, iPadOS и macOS. Рамката предоставя пълен набор от API за работа и в двете BLE роли: централно устройство (CBCentralManager) за сканиране и свързване с периферни устройства и периферно устройство (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 — системна рамка на Apple за BLE разработка на iOS, iPadOS и macOS
  • CBCentralManager — клас за сканиране и свързване с BLE периферни устройства от страна на централното устройство
  • CBPeripheralManager — клас за създаване на BLE сървър, публикуващ услуги и характеристики
  • GATT профил — йерархичен модел на услуги, характеристики и дескриптори за обмен на данни
  • Фонови режими — Core Bluetooth поддържа BLE комуникация във фонов режим чрез системни делегати и state restoration

Какво е Core Bluetooth: архитектура и компоненти

Core Bluetooth разделя BLE стека на две логически роли, определени от спецификацията Bluetooth SIG. Ролята на централно устройство (Central) е представена от класа CBCentralManager — инициира сканиране, установява връзки и управлява списъка на свързаните CBPeripheral. Ролята на периферно устройство (Peripheral) е представена от CBPeripheralManager — публикува услуги и характеристики, отговаря на заявки на централното устройство и изпраща известия. Една iOS сесия може едновременно да работи и в двете роли на различни BLE радиостанции, но типичното приложение използва една роля.

Архитектурата на Core Bluetooth включва пет ключови абстракции. CBCentralManager управлява състоянието на Bluetooth адаптера на устройството: poweredOn (готов за работа), poweredOff (Bluetooth изключен), unauthorized (без разрешение), unsupported (BLE недостъпен). CBPeripheral представлява отдалечено BLE устройство с неговия UUID, име, RSSI и GATT йерархия. CBService — логическа група от характеристики. CBCharacteristic — точка за данни за четене/запис/известия. CBPeripheralManager създава локален GATT сървър за емулиране на периферно устройство.

КласРоляОсновни методи
CBCentralManagerЦентрално устройство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 Настройки — делегатът получава повторно извикване и приложението може да възобнови сканирането.

CBCentralManager: сканиране и свързване на BLE устройства

CBCentralManager — входна точка за всички BLE операции от страна на централното устройство. Инициализацията приема делегат (CBCentralManagerDelegate) и опашка DispatchQueue — препоръката на Apple е да използвате main queue за простота или serial queue за производителност. След инициализация рамката автоматично проверява състоянието на Bluetooth и извиква centralManagerDidUpdateState: — първият задължителен делегат за обработка.

Сканирането се стартира с метода scanForPeripheralsWithServices:options:. Първият параметър е масив от CBUUID на услуги за филтриране: ако UUID на интересуващите услуги са известни, тяхното предаване намалява консумацията на енергия и времето за търсене. Ако е nil, всички BLE устройства в обхват се откриват. Опциите включват .allowDuplicatesKey (повторно откриване на същото устройство) и .solicitedServiceUUIDsKey (за услуги, публикувани на централното устройство).

swift
import CoreBluetooth

class BLECentral: NSObject {

    private var centralManager: CBCentralManager!
    private var discoveredPeripherals: [CBPeripheral] = []

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

    // Стартиране на BLE сканиране
    func startScan() {
        guard centralManager.state == .poweredOn else {
            print("Bluetooth недостъпен")
            return
        }
        // Сканиране на всички устройства (nil = без филтър)
        centralManager.scanForPeripherals(withServices: nil,
                                            options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
    }

    // Спиране на сканирането
    func stopScan() {
        centralManager.stopScan()
    }

    // Свързване с избраното устройство
    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 устройства. centralManagerDidUpdateState стартира сканиране, когато Bluetooth е включен. didDiscoverPeripheral събира намерените устройства в масива discoveredPeripherals с дедупликация по identifier. След свързване (didConnect) незабавно се стартира откриване на услуги — това е задължителна стъпка преди каквито и да било GATT операции.

CBPeripheralManager: създаване на BLE сървър на iOS

CBPeripheralManager — клас за емулиране на BLE периферно устройство на iOS. Приложението в роля на периферия може да публикува своите услуги и характеристики, да приема входящи заявки за четене/запис от централното устройство и да изпраща известия. CBPeripheralManager се използва за BLE аксесоари, емулирани от iPhone: дистанционни управления, клавиатури, тракери, IoT шлюзове.

Жизненият цикъл на CBPeripheralManager започва с инициализация и делегат CBPeripheralManagerDelegate. След потвърждение на poweredOn чрез peripheralManagerDidUpdateState:, услугите се публикуват (addService:) и рекламата се стартира (startAdvertising:). Рекламните данни CBAdvertisementData включват локално име (CBAdvertisementDataLocalNameKey), UUID на услуги (CBAdvertisementDataServiceUUIDsKey) и ниво на мощност (CBAdvertisementDataTxPowerLevelKey). Максималният размер на рекламен пакет е 31 байта за BLE 4.0, 251 байта за extended advertising BLE 5.0+.

swift
// BLE периферия на iOS чрез 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)
    }

    // Публикуване на услуга с характеристика
    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)
    }

    // Стартиране на реклама
    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()
        }
    }

    // Обработка на заявка за четене
    func peripheralManager(_ peripheral: CBPeripheralManager,
                        didReceiveRead request: CBATTRequest) {
        let data = "CurrentValue".data(using: .utf8)!
        request.value = data
        peripheralManager.respond(to: request, withResult: .success)
    }

    // Обработка на заявка за запис
    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 заявки от централното устройство. За изпращане на известия се използва методът updateValue:forCharacteristic:onSubscribedCentrals:.

GATT операции: четене, запис и известия

GATT операции (Generic Attribute Profile) — основата за обмен на данни в Core Bluetooth. След откриване на услуги и характеристики, централното устройство може да извърши три типа операции: четене на стойност на характеристика, запис на стойност и абониране за известия/индикации. Всяка операция е асинхронна и връща резултата чрез съответния CBPeripheralDelegate делегат.

Четене се извършва чрез извикване на readValueForCharacteristic:. Стойността пристига в peripheral:didUpdateValueForCharacteristic:error:. Важно: четенето връща текущата стойност от устройството, а не кеширана. Ако устройството не поддържа четене (свойство .read), извикването ще върне грешка. За големи стойности (по-големи от MTU) BLE автоматично фрагментира и сглобява данни на GATT ниво.

Запис се извършва чрез writeValue:forCharacteristic:type:. BLE поддържа два модела на запис: withResponse (надежден, с потвърждение) и withoutResponse (бърз, без потвърждение). Свойството CBCharacteristic.properties определя наличните типове запис. Максималният размер на един пакет за запис е ограничен от MTU: 23 байта за BLE 4.0 (20 байта полезни данни + 3 байта заглавка), до 247 байта за BLE 5.0 с extended MTU (MTU 251).

Известия се активират чрез извикване на setNotifyValue:true forCharacteristic:. След абониране периферното устройство автоматично изпраща актуализации чрез peripheral:didUpdateValueForCharacteristic: всеки път, когато стойността на характеристиката се промени. За деактивиране на известията се извиква setNotifyValue:false forCharacteristic:. Core Bluetooth автоматично управлява CCCD дескриптора на периферното устройство.

ОперацияМетодДелегатТип на предаване
ЧетенеreadValueForCharacteristic:didUpdateValueForCharacteristicPolling (заявка-отговор)
Запис withResponsewriteValue:forCharacteristic:type:withResponsedidWriteValueForCharacteristicС потвърждение
Запис withoutResponsewriteValue:forCharacteristic:type:withoutResponseНяма делегатБез потвърждение
ИзвестиеsetNotifyValue:true forCharacteristic:didUpdateNotificationStateForCharacteristic + didUpdateValueForCharacteristicPush от периферия

Фонов режим на Core Bluetooth и State Restoration

Фонов режим Core Bluetooth позволява на BLE приложението да продължи да сканира, поддържа връзки и получава известия, докато е на фонов режим. За активиране е необходимо: включете 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 и висящи връзки.

swift
// Core Bluetooth конфигурация с 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 {

    // Възстановяване на състоянието след рестарт
    func centralManager(_ central: CBCentralManager,
                        willRestoreState dict: [String : Any]) {
        if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey]
            as? [CBPeripheral] {
            for peripheral in peripherals {
                peripheral.delegate = self
                // Възстановяване на GATT откриване
                peripheral.discoverServices(nil)
            }
        }
    }

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            print("Bluetooth готов след възстановяване")
        }
    }
}

В конфигурацията BLECentralWithRestoration ключът CBCentralManagerOptionRestoreIdentifierKey активира запазване на състоянието. Ако приложението е било прекратено от iOS (например поради липса на памет), при следващото стартиране centralManager:willRestoreState: получава списък с предварително свързани CBPeripheral. Приложението възстановява делегатите и извършва повторно откриване на услуги — потребителят не забелязва прекъсване на връзката. Без State Restoration всички BLE сесии се губят при прекратяване на приложението.

Пример за BLE приложение в Swift: център и периферия

Пълен пример на BLE приложение в Swift обединява централно и периферно устройство в един проект. Приложението може да работи в два режима: откриване и свързване с BLE устройства (Central) или емулиране на BLE аксесоар (Peripheral). По-долу е представена архитектурата с общ BLE мениджър, който избира роля при стартиране.

swift
// Универсален BLE мениджър за център и периферия
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)
        }
    }

    // Централно устройство: сканиране
    func scanForDevices() {
        centralManager?.scanForPeripherals(withServices: nil, options: nil)
    }

    // Периферно устройство: реклама
    func advertiseService() {
        let data: [String: Any] = [
            CBAdvertisementDataServiceUUIDsKey: [advertisedServiceUUID]
        ]
        peripheralManager?.startAdvertising(data)
    }
}

// Използване при стартиране
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?

Core Bluetooth — рамка на Apple за BLE разработка на iOS, iPadOS и macOS. Предоставя API за работа на централно (CBCentralManager) и периферно (CBPeripheralManager) устройство. Поддържа BLE 4.0–5.4, extended advertising, 2M PHY и LE Audio. Core Bluetooth е единственото официално API на Apple за BLE комуникация, задължително за всички iOS приложения, работещи с Bluetooth Low Energy.

Каква е разликата между CBCentralManager и CBPeripheralManager?

CBCentralManager — клас за работа в роля на централно устройство: сканира BLE периферни устройства, установява връзки, чете и пише характеристики. CBPeripheralManager — клас за работа в роля на периферия: публикува услуги, отговаря на заявки за четене/запис и изпраща известия. Един iPhone може едновременно да работи в две роли чрез различни инстанции на мениджъри.

Как да конфигурираме Core Bluetooth за фонова работа?

За BLE фонова работа включете capability „Uses Bluetooth LE accessories” в Xcode и добавете ключа „bluetooth-central” в UIBackgroundModes. За периферната роля — „bluetooth-peripheral”. Посочете restoreIdentifier при инициализация на мениджъра за State Restoration. Без тези настройки приложението на фонов режим не получава BLE събития и губи връзки.

Защо Core Bluetooth не открива устройства?

Основни причини: CBCentralManager.state != .poweredOn (Bluetooth изключен или неоторизиран), делегатът не е зададен, устройството е извън обхват или не изпраща рекламни пакети. Проверете разрешението NSBluetoothAlwaysUsageDescription в Info.plist, състоянието на Bluetooth в centralManagerDidUpdateState и се уверете, че scanForPeripherals се извиква само при .poweredOn.

Могат ли да се свържат няколко CBPeripheral едновременно?

Да, Core Bluetooth поддържа едновременно свързване с множество BLE устройства. Всеки CBPeripheral се управлява независимо чрез собствен делегат. iOS ограничава броя на едновременните BLE връзки на системно ниво (обикновено 5–7 за iPhone). За 1:N сценарии (например фитнес център с 10 тракера) се изисква опашка и циклично обслужване на периферни устройства.

Резюме

  • Core Bluetooth — системна рамка на Apple за BLE разработка с класове CBCentralManager и CBPeripheralManager
  • CBCentralManager управлява сканиране, свързване и GATT операции с отдалечени BLE устройства
  • CBPeripheralManager емулира BLE периферия с публикуване на услуги и обработка на входящи заявки
  • GATT профил включва услуги, характеристики и дескриптори с операции за четене, запис и известия
  • Фонов режим изисква UIBackgroundModes и restoreIdentifier за State Restoration
  • MTU BLE ограничава размера на пакета: 23 байта за BLE 4.0, до 251 байта за BLE 5.0+ с extended MTU
  • Swift async/await чрез CheckedContinuation опростява асинхронния BLE код с делегати

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също