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 је једини званични Apple API за 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 одређује доступне типове писања. Максимална величина једног write пакета ограничена је 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 је једини званични Apple API за 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. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође