CBPeripheral — třída frameworku Core Bluetooth, která reprezentuje vzdálené BLE zařízení na iOS. Každý objekt CBPeripheral zapouzdřuje UUID, název, RSSI a hierarchii GATT služeb připojeného BLE zařízení. Vývojář interaguje s periferií výhradně prostřednictvím CBPeripheral: discovery služeb (discoverServices:), čtení charakteristik (readValueForCharacteristic:), zápis dat (writeValue:forCharacteristic:type:) a přihlášení k odběru oznámení (setNotifyValue:forCharacteristic:). Podle Apple Developer, 2026 je CBPeripheral — centrální objekt pro všechny operace s BLE-periferií, vrácený CBCentralManagerem při detekci nebo připojení zařízení.
Hlavní body
CBPeripheral — je objekt, který reprezentuje vzdálené BLE zařízení v iOS aplikaci. Na rozdíl od CBCentralManageru, který spravuje lokální Bluetooth adaptér iPhone, CBPeripheral modeluje externí periferní zařízení: senzor, fitness tracker, maják, lékařské zařízení. Každá instance CBPeripheral obsahuje jedinečný identifikátor (UUID), který je zachován mezi relacemi připojení — Apple spojuje UUID s konkrétním zařízením prostřednictvím systémového Bondingu.
CBPeripheral není vytvářen přímo přes init. Framework Core Bluetooth vrací objekt CBPeripheral ve dvou scénářích: při detekci zařízení pomocí scanForPeripheralsWithServices: (delegát didDiscoverPeripheral) a při připojení k dříve známému zařízení pomocí retrievePeripheralsWithIdentifiers:. Po obdržení objektu vývojář zavolá connectPeripheral: na CBCentralManager, po čemž se CBPeripheral stane dostupným pro GATT operace.
Životní cyklus CBPeripheral zahrnuje šest stavů: disconnected (počáteční), connecting (po volání connect), connected (po didConnectPeripheral), discovering (během volání discoverServices), discovered (po obdržení služeb) a disconnecting (po cancelPeripheralConnection). Každý stav je sledován prostřednictvím delegáta CBPeripheralDelegate — povinný protokol pro každou BLE aplikaci na iOS.
CBPeripheral ukládá hierarchickou GATT strukturu sestávající ze tří úrovní. Kořenová úroveň — pole CBService (služby), každá služba obsahuje pole CBCharacteristic (charakteristiky), každá charakteristika obsahuje pole CBDescriptor (deskriptory). Tento model plně odpovídá specifikaci Bluetooth GATT: služba — funkce zařízení (například „Heart Rate Service"), charakteristika — konkrétní hodnota (puls 72 bpm), deskriptor — metadata charakteristiky (jednotky měření, konfigurace oznámení).
| Úroveň | Třída Core Bluetooth | Popis |
|---|---|---|
| Služba | CBService | Logická skupina příbuzných charakteristik, identifikovaná UUID (16-bit, 32-bit nebo 128-bit) |
| Charakteristika | CBCharacteristic | Konkrétní hodnota dat, podporuje čtení, zápis, oznámení |
| Deskriptor | CBDescriptor | Metadata charakteristiky: konfigurace klienta CCCD, User Description, Presentation Format |
Standardní BLE služby jsou registrovány u Bluetooth SIG: Heart Rate Service (UUID 180D), Battery Service (180F), Device Information (180A), Blood Pressure (1810). Pro vlastní služby se používají 128-bit UUID (například E20A39F4-73F5-4BC4-A12F-17D1AD07A961). iOS automaticky rozpoznává standardní UUID a zobrazuje lidsky čitelná jména; vlastní UUID se zobrazují v hex formátu.
Po připojení je hierarchie CBPeripheral prázdná — služby a charakteristiky nejsou načteny. Vývojář musí zavolat discoverServices: pro získání služeb a poté pro každou službu zavolat discoverCharacteristics:forService:. Pokud služba obsahuje zahrnuté služby (includedServices), dodatečně se volá discoverIncludedServices:forService:. Teprve po dokončení discovery hierarchie se CBPeripheral naplní a stane se dostupným pro čtení a zápis.
Discovery (detekce) GATT struktury CBPeripheral — povinný krok před jakýmikoli operacemi čtení nebo zápisu. Metoda discoverServices: spouští asynchronní vyhledávání všech služeb zařízení. Pokud je předáno nil, jsou detekovány všechny služby; pokud je předáno pole CBUUID — pouze služby s uvedenými UUID (optimalizace času). Výsledek přichází do delegáta peripheral:didDiscoverServices: — objekt CBPeripheral vyplní vlastnost services polem CBService.
Po obdržení služeb je pro každou CBService nutné zavolat discoverCharacteristics:forService:. Podobně, nil — všechny charakteristiky, pole CBUUID — pouze uvedené. Výsledek: peripheral:didDiscoverCharacteristicsForService:error:. V této fázi CBCharacteristic získává vlastnosti (properties: .read, .write, .notify, .indicate), které určují povolené operace.
import CoreBluetooth
extension BLEViewController: CBPeripheralDelegate {
// 1. Discovery služby
func peripheral(_ peripheral: CBPeripheral,
didDiscoverServices error: Error?) {
guard let services = peripheral.services else { return }
for service in services {
// Požadavek charakteristik pro každou službu
peripheral.discoverCharacteristics(nil, for: service)
}
}
// 2. Discovery charakteristiky
func peripheral(_ peripheral: CBPeripheral,
didDiscoverCharacteristicsFor service: CBService,
error: Error?) {
guard let characteristics = service.characteristics else { return }
for characteristic in characteristics {
if characteristic.properties.contains(.read) {
peripheral.readValue(for: characteristic)
}
if characteristic.properties.contains(.notify) {
peripheral.setNotifyValue(true, for: characteristic)
}
}
}
// 3. Čtení hodnoty
func peripheral(_ peripheral: CBPeripheral,
didUpdateValueFor characteristic: CBCharacteristic,
error: Error?) {
guard let data = characteristic.value,
let value = String(data: data, encoding: .utf8)
else { return }
print("Characteristic value: \(value)")
}
}
V příkladu jsou implementovány tři povinné metody detekce CBPeripheralDelegate. didDiscoverServices prochází všechny nalezené služby a požaduje charakteristiky. didDiscoverCharacteristicsForService kontroluje vlastnosti každé charakteristiky: pro .read volá readValue, pro .notify — setNotifyValue(true). Metoda didUpdateValueForCharacteristic přijímá aktuální hodnotu ve formátu Data.
Čtení hodnot CBCharacteristic se provádí metodou readValueForCharacteristic:. Výsledek přichází asynchronně do peripheral:didUpdateValueForCharacteristic:error:. Důležité: zařízení může mít hodnotu v mezipaměti (characteristic.value je dostupný ihned po discovery), ale pro získání aktuální hodnoty je volání readValue povinné. iOS může ukládat hodnoty do mezipaměti kvůli energetické účinnosti — readValue obnovuje mezipaměť.
Zápis hodnot se provádí metodou writeValue:forCharacteristic:type:. Parametr type určuje typ zápisu: .withResponse (CBCharacteristicWriteWithResponse) — zařízení potvrzuje zápis přes didWriteValueForCharacteristic; .withoutResponse (CBCharacteristicWriteWithoutResponse) — zápis bez potvrzení, maximální rychlost, ale bez záruky doručení. Specifikace BLE omezuje MTU (Maximum Transmission Unit): až 23 bajtů pro BLE 4.0, až 251 bajtů pro BLE 5.0+. Pro data větší než MTU je vyžadována fragmentace na úrovni aplikace.
// Čtení a zápis charakteristik CBPeripheral
class BLEService {
private let peripheral: CBPeripheral
private let serviceUUID = CBUUID(string: "180D")
private let charUUID = CBUUID(string: "2A37")
init(peripheral: CBPeripheral) {
self.peripheral = peripheral
}
// Čtení s potvrzením
func readHeartRate() {
guard let service = peripheral.services?.first(where: { $0.uuid == serviceUUID }),
let characteristic = service.characteristics?.first(where: { $0.uuid == charUUID })
else { return }
peripheral.readValue(for: characteristic)
}
// Zápis s potvrzením (withResponse)
func writeWithResponse(data: Data) {
guard let characteristic = findCharacteristic() else { return }
peripheral.writeValue(data, for: characteristic,
type: .withResponse)
}
// Zápis bez potvrzení (withoutResponse)
// Maximální propustnost, bez záruky doručení
func writeWithoutResponse(data: Data) {
guard let characteristic = findCharacteristic() else { return }
peripheral.writeValue(data, for: characteristic,
type: .withoutResponse)
}
private func findCharacteristic() -> CBCharacteristic? {
return peripheral.services?
.flatMap { $0.characteristics ?? [] }
.first(where: { $0.uuid == charUUID })
}
}
Výběr typu zápisu withResponse nebo withoutResponse závisí na požadavcích na spolehlivost. Pro příkazy (rozsvítit světlo, otevřít zámek) použijte withResponse — záruka doručení je kritická. Pro streamovaná data (puls, teplota) použijte withoutResponse — ztráta jednoho paketu je nevýznamná. BLE zařízení může podporovat pouze jeden typ zápisu — zkontrolujte vlastnost characteristic.properties.contains(.write) a .writeWithoutResponse.
Oznámení (notifications) — BLE mechanismus, při kterém periferní zařízení odesílá hodnotu charakteristiky centrálnímu zařízení asynchronně, bez neustálého pollingu ze strany centrálního. CBPeripheral aktivuje přihlášení prostřednictvím metody setNotifyValue:forCharacteristic:. Po aktivaci přihlášení iOS automaticky zapisuje CCCD (Client Characteristic Configuration Descriptor) na periferii a zařízení začíná odesílat aktualizace při každé změně hodnoty.
Na rozdíl od indikací (indicate), oznámení nevyžadují potvrzení od centrálního — paket je odeslán a zapomenut. To poskytuje maximální šířku pásma, ale je možná ztráta paketů. Indikace vyžadují potvrzení na úrovni protokolu (L2CAP) — spolehlivější, ale pomalejší. CBCharacteristic prostřednictvím vlastnosti properties přesně určuje, který režim podporuje: .notify, .indicate nebo oba.
Při odpojení CBPeripheral (disconnect, opuštění dosahu) jsou všechna aktivní přihlášení automaticky resetována. Při opětovném připojení je nutné znovu zavolat setNotifyValue:true pro každou charakteristiku. iOS také ztrácí přihlášení při opuštění foreground aplikace (pokud není aktivován režim na pozadí) — pro práci na pozadí je vyžadováno povolení capability „Uses Bluetooth LE accessories“ v Info.plist.
// Správa přihlášení k oznámením CBPeripheral
class NotificationManager: NSObject {
private var peripheral: CBPeripheral?
private var subscribedCharacteristics: Set<CBUUID> = []
// Přihlásit se k oznámením pro všechny .notify charakteristiky
func subscribeToAllNotifications(peripheral: CBPeripheral) {
self.peripheral = peripheral
guard let services = peripheral.services else { return }
for service in services {
guard let characteristics = service.characteristics else { continue }
for characteristic in characteristics {
if characteristic.properties.contains(.notify)
|| characteristic.properties.contains(.indicate) {
peripheral.setNotifyValue(true, for: characteristic)
subscribedCharacteristics.insert(characteristic.uuid)
}
}
}
}
// Odhlásit se ze všech oznámení
func unsubscribeFromAll() {
guard let peripheral = peripheral else { return }
guard let services = peripheral.services else { return }
for service in services {
guard let characteristics = service.characteristics else { continue }
for characteristic in characteristics {
if subscribedCharacteristics.contains(characteristic.uuid) {
peripheral.setNotifyValue(false, for: characteristic)
}
}
}
subscribedCharacteristics.removeAll()
}
// Obsluha oznámení
func peripheral(_ peripheral: CBPeripheral,
didUpdateNotificationStateFor characteristic: CBCharacteristic,
error: Error?) {
if characteristic.isNotifying {
print("Subscription active: \(characteristic.uuid)")
} else {
print("Subscription inactive: \(characteristic.uuid)")
}
}
}
Správce přihlášení NotificationManager demonstruje správnou práci s oznámeními CBPeripheral. subscribeToAllNotifications prochází všechny služby a charakteristiky, aktivuje .notify a .indicate. subscribedCharacteristics sleduje aktivní přihlášení pro správné odhlášení. didUpdateNotificationStateForCharacteristic potvrzuje úspěšnou změnu stavu přihlášení prostřednictvím vlastnosti characteristic.isNotifying.
Úplný pracovní cyklus s CBPeripheral zahrnuje: získání objektu od CBCentralManager, připojení, discovery, čtení/zápis, přihlášení k oznámením a odpojení. V následujícím příkladu je implementována třída BLEConnection, která spravuje úplný životní cyklus BLE-periferie ve Swift pomocí moderního async/await API (iOS 15+).
import CoreBluetooth
// Úplný příklad správy CBPeripheral s async/await
class BLEConnection: NSObject {
private let centralManager: CBCentralManager
private var peripheral: CBPeripheral?
private var continuation: CheckedContinuation<Void, Error>?
override init() {
centralManager = CBCentralManager(delegate: nil, queue: .main)
super.init()
centralManager.delegate = self
}
// 1. Připojit k periferii
func connect(to peripheral: CBPeripheral) async throws {
self.peripheral = peripheral
peripheral.delegate = self
centralManager.connect(peripheral, options: nil)
try await withCheckedThrowingContinuation { continuation in
self.continuation = continuation
}
}
// 2. Discovery
func discoverServices() async throws {
guard let peripheral = peripheral else {
throw BLEError.notConnected
}
peripheral.discoverServices(nil)
try await withCheckedThrowingContinuation { continuation in
self.continuation = continuation
}
}
}
// 3. CBCentralManager
extension BLEConnection: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
// Zpracování stavu Bluetooth zařízení
}
func centralManager(_ central: CBCentralManager,
didConnect peripheral: CBPeripheral) {
continuation?.resume()
continuation = nil
}
func centralManager(_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?) {
continuation?.resume(throwing: error ?? BLEError.connectionFailed)
continuation = nil
}
}
enum BLEError: Error {
case notConnected
case connectionFailed
case serviceNotFound
case characteristicNotFound
}
Třída BLEConnection používá Swift Concurrency (async/await) prostřednictvím CheckedContinuation — moderní vzor pro práci s delegátskými API Core Bluetooth. connect(to:) očekává potvrzení připojení přes didConnectPeripheral, discoverServices() — přes didDiscoverServices. Tento přístup eliminuje vnořené delegáty a činí BLE kód lineárním a čitelným. Zpracování chyb prostřednictvím BLEError pokrývá všechny typické scénáře selhání BLE spojení.
Často kladené otázky
CBPeripheral pro dříve připojené zařízení lze získat prostřednictvím retrievePeripheralsWithIdentifiers: na CBCentralManager. Předejte pole UUID (NSUUID) dříve uložených zařízení — framework vrátí pole CBPeripheral pro zařízení v systémové databázi BLE-bondingu. To funguje pouze pro zařízení, se kterými byl iPhone dříve spárován. Pro nové zařízení je skenování povinné.
Hlavní příčiny: zařízení je mimo dosah (RSSI pod prahem), BLE rádio je vypnuto (CBCentralManager.state != .poweredOn), delegát CBPeripheralDelegate není nastaven (peripheral.delegate = self) nebo volání discoverServices bylo provedeno před připojením. Zkontrolujte stav centralManager.state, ujistěte se, že delegát je nastaven před voláním connect a použijte retry s timeoutem 5–10 sekund.
Příčina — použití .withResponse na charakteristice, která podporuje pouze .writeWithoutResponse nebo naopak. Zkontrolujte characteristic.properties před voláním. Také může být problém s MTU: pokud data > 20 bajtů (BLE 4.0 MTU), je vyžadováno vyjednání MTU prostřednictvím negotiateMTU nebo fragmentace. Použijte peripheral.maximumWriteValueLength(for: .withResponse) pro určení maximální velikosti paketu.
CBPeripheral mimo dosah se neodpojí okamžitě — iOS jej přepne do stavu .disconnected po timeoutu (obvykle 20–30 sekund). Pro monitorování použijte readRSSI na CBPeripheral — při nedostupnosti vrátí chybu s kódem CBError.connectionTimeout. Také sledujte centralManager:didDisconnectPeripheral:error: pro včasnou detekci přerušení spojení.
Core Bluetooth není vláknově bezpečný — všechna volání CBPeripheral musí být prováděna z jedné fronty (obvykle main queue nebo sériová serial queue uvedená při inicializaci CBCentralManager). Souběžná volání z různých vláken vedou k race condition a pádu aplikace. Použijte DispatchQueue(label: „com.app.ble“) pro všechny BLE operace a DispatchQueue.main.async pro aktualizaci UI.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také