CBCentralManager w iOS — co to jest, zarządzanie BLE i Core Bluetooth

Autor: IT Sectr Opublikowano: 2026-07-16 Czas czytania: 11 min

CBCentralManager — to centralna klasa frameworka Core Bluetooth w iOS, która zarządza skanowaniem, łączeniem i interakcją z peryferyjnymi urządzeniami BLE. Core Bluetooth (iOS 5+, 2011) zapewnia wysokopoziomową abstrakcję nad stosem BLE na poziomie GATT, ukrywając przed programistą szczegóły Link Layer i HCI. CBCentralManager realizuje rolę Central: skanuje eter przez scanForPeripherals, inicjuje połączenie przez connect, wykrywa usługi przez discoverServices i zarządza przesyłaniem danych. Według Apple Developer Documentation (2024), CBCentralManager obsługuje do 7 jednoczesnych połączeń z urządzeniami BLE na urządzeniach z BLE 5.0.

Najważniejsze

  • CBCentralManager — klasa iOS do zarządzania skanowaniem BLE, łączeniem i przesyłaniem danych w roli Central.
  • Skanowanie uruchamiane jest przez scanForPeripherals z filtrowaniem po UUID usług w celu oszczędzania energii.
  • Połączenie wykonuje się przez connect(peripheral:options:) ze śledzeniem stanu przez delegata.
  • iOS obsługuje do 7 jednoczesnych połączeń BLE na urządzeniach z BLE 5.0.
  • Skanowanie w tle wymaga włączenia bluetooth-central w Background Modes i użycia CBCentralManagerScanOptionAllowDuplicatesKey.

Co to jest CBCentralManager?

CBCentralManager — to główna klasa Core Bluetooth do implementacji roli Central w architekturze BLE na iOS. Zarządza całym cyklem życia połączenia BLE: od skanowania reklamujących się urządzeń po przesyłanie danych i rozłączanie. CBCentralManager działa asynchronicznie przez delegata CBCentralManagerDelegate, powiadamiając aplikację o zdarzeniach w stosie Bluetooth.

Inicjalizacja CBCentralManager uruchamia proces state restoration: menedżer sprawdza stan Bluetooth na urządzeniu i przywraca poprzednie połączenia, jeśli aplikacja została zamknięta. Proces inicjalizacji może trwać od 50 do 500 ms w zależności od stanu Bluetooth. Aplikacja musi poczekać na wywołanie centralManagerDidUpdateState przed rozpoczęciem jakichkolwiek operacji BLE.

Architektura Core Bluetooth oparta jest na wzorcu Delegation: CBCentralManager deleguje obsługę zdarzeń (wykrywanie urządzeń, łączenie, błędy) do protokołu CBCentralManagerDelegate. Do pracy z konkretnym Peripheral używany jest protokół CBPeripheralDelegate, który powiadamia o wykryciu usług, charakterystyk i otrzymaniu danych. Taki asynchroniczny model zapewnia nieblokujące działanie UI.

Stany CBCentralManager

CBCentralManager przechodzi przez kilka stanów, które określają, czy stos BLE jest dostępny do pracy. Stan jest przekazywany przez delegata: centralManagerDidUpdateState(_:). Programista musi obsłużyć wszystkie stany — nie tylko poweredOn, ale także przypadki, gdy Bluetooth jest wyłączony lub niedostępny.

StanZnaczenieDziałanie programisty
.poweredOnBluetooth włączony i gotowyRozpocznij skanowanie
.poweredOffBluetooth wyłączonyPokaż alert użytkownikowi
.unauthorizedBrak uprawnieńPoproś o uprawnienia w Ustawieniach
.unsupportedUrządzenie nie obsługuje BLEUkryj funkcje BLE
.unknownStan nieokreślonyCzekaj na następną aktualizację
.resettingBluetooth restartuje sięCzekaj na przywrócenie

Unauthorized state staje się coraz częstszy od iOS 13+. Począwszy od tej wersji, aplikacja musi mieć uprawnienie NSBluetoothAlwaysUsageDescription w Info.plist. Bez niego centralny menedżer przechodzi w stan .unauthorized i skanowanie jest niemożliwe. Użytkownik może zmienić uprawnienia w Ustawieniach > Prywatność > Bluetooth w dowolnym momencie.

Skanowanie urządzeń BLE

scanForPeripherals(withServices:options:) — główna metoda do uruchamiania skanowania. Parametr withServices przyjmuje tablicę UUID usług do filtrowania: jeśli przekażesz nil, zostaną wykryte wszystkie urządzenia, co znacznie zwiększa zużycie energii. Zaleca się zawsze filtrować po UUID usług, które są potrzebne aplikacji. Opcje skanowania obejmują CBCentralManagerScanOptionAllowDuplicatesKey (powtarzające się powiadomienia o tym samym urządzeniu).

swift
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") // Serwis Baterii

        centralManager.scanForPeripherals(
            withServices: [serviceUUID],
            options: [
                CBCentralManagerScanOptionAllowDuplicatesKey: false
            ]
        )
    }
}

Po wykryciu urządzenia wywoływana jest centralManager(_:didDiscover:advertisementData:rssi:). Parametr advertisementData zawiera pełny słownik danych pakietu reklamowego, w tym nazwę urządzenia (CBAdvertisementDataLocalNameKey), UUID usług (CBAdvertisementDataServiceUUIDsKey) i dane producenta (CBAdvertisementDataManufacturerDataKey). RSSI — poziom sygnału w dBm, dostępny w momencie wykrycia.

Łączenie z Peripheral

connect(_:options:) — metoda do ustanawiania połączenia BLE z wykrytym Peripheral. Po wywołaniu connect iOS próbuje połączyć się z urządzeniem. Udane połączenie potwierdzane jest przez wywołanie centralManager(_:didConnect:), błąd — centralManager(_:didFailToConnect:error:). Opcje połączenia obejmują CBConnectPeripheralOptionNotifyOnConnectionKey, CBConnectPeripheralOptionNotifyOnDisconnectionKey i CBConnectPeripheralOptionNotifyOnNotificationKey dla powiadomień w tle.

swift
// Połącz z urządzeniem BLE
func connectToPeripheral(
    _ peripheral: CBPeripheral
) {
    centralManager.connect(peripheral, options: nil)

    // Ustaw delegata dla Peripheral
    peripheral.delegate = self
}

// Delegat: udane połączenie
func centralManager(
    _ central: CBCentralManager,
    didConnect peripheral: CBPeripheral
) {
    print("Połączono z " +
          "\(peripheral.name ?? "unknown")")

    // Rozpocznij wykrywanie usług
    peripheral.discoverServices(nil)
}

// Delegat: błąd połączenia
func centralManager(
    _ central: CBCentralManager,
    didFailToConnect peripheral: CBPeripheral,
    error: Error?
) {
    print("Connection failed: 
          \(error?.localizedDescription ?? "")")
}

Limit czasu połączenia na iOS wynosi 30 sekund. Jeśli w tym czasie urządzenie nie odpowiedziało na żądanie połączenia, wywoływane jest didFailToConnect. Na limit czasu wpływają: odległość do urządzenia, zakłócenia, czy urządzenie aktualnie się reklamuje. Przed połączeniem upewnij się, że urządzenie znajduje się w trybie connectable advertising (ADV_IND, a nie ADV_NONCONN_IND).

Wykrywanie usług i charakterystyk

Po połączeniu należy wykryć usługi (discoverServices) i charakterystyki (discoverCharacteristics) Peripheral. To obowiązkowy krok przed odczytem lub zapisem danych. Proces jest asynchroniczny: discoverServices zwraca wynik przez peripheral(_:didDiscoverServices:), a discoverCharacteristics — przez peripheral(_:didDiscoverCharacteristicsFor:error:).

Zaleca się przekazywanie w discoverServices tablicy interesujących UUID, a nie nil. Filtrowanie przyspiesza wykrywanie i oszczędza energię. Jeśli usługa nie zostanie znaleziona, iOS zgłosi pustą tablicę. Po wykryciu charakterystyk można odczytać ich wartości (readValue), subskrybować powiadomienia (setNotifyValue) lub zapisywać dane (writeValue).

Ważny niuans: MTU jest uzgadniane automatycznie po połączeniu. Aby uzyskać bieżące MTU, użyj peripheral.maximumWriteValueLength(for: .withResponse) lub .withoutResponse. W iOS maksymalne MTU to 512 bajtów dla urządzeń BLE 5.0. Jeśli potrzebujesz przesłać dane większe niż MTU, zaimplementuj fragmentację na poziomie aplikacji.

Skanowanie w tle i ograniczenia iOS

Skanowanie w tle urządzeń BLE na iOS wymaga specjalnej konfiguracji. Core Bluetooth obsługuje background execution, ale ze znacznymi ograniczeniami. Do pracy w tle konieczne jest: włączenie bluetooth-central w Background Modes w Capabilities projektu, inicjalizacja CBCentralManager z opcją CBCentralManagerOptionRestoreIdentifierKey dla state restoration oraz obsługa zdarzeń centralnego menedżera przy przejściu w tło.

Ograniczenia BLE w tle w iOS: scanForPeripherals bez filtrowania po UUID nie działa w tle. Aplikacja musi określać konkretne UUID usług do skanowania. iOS może opóźniać dostarczanie zdarzeń BLE na nieokreślony czas. Core Bluetooth automatycznie wznawia skanowanie po wykryciu pasującego urządzenia, nawet jeśli aplikacja jest w tle. Limit czasu skanowania w tle: iOS może zatrzymać skanowanie po 10–30 minutach w celu oszczędzania energii.

State Restoration — mechanizm Core Bluetooth, który pozwala przywrócić połączenia BLE po ponownym uruchomieniu aplikacji lub restarcie iOS. Aby go użyć: podaj CBCentralManagerOptionRestoreIdentifierKey przy inicjalizacji, zaimplementuj centralManager(_:willRestoreState:) w delegacie i przywróć listę podłączonych Peripheral z przekazanego słownika. State Restoration — krytyczna funkcjonalność dla aplikacji BLE działających w tle, np. trackerów fitness lub urządzeń medycznych.

Obsługa błędów i przywracanie połączenia

CBCentralManager generuje błędy w kilku scenariuszach: połączenie nie powiodło się (didFailToConnect), połączenie zostało zerwane (didDisconnectPeripheral), charakterystyka jest niedostępna do odczytu/zapisu (didWriteValue error). Wszystkie błędy Core Bluetooth są zwracane przez obiekt Error z domeną CBErrorDomain. Najczęstsze kody: CBErrorConnectionTimeout (0x04), CBErrorPeripheralDisconnected (0x07), CBErrorOperationNotSupported (0x0A).

Strategia przywracania połączenia: po otrzymaniu didDisconnectPeripheral sprawdź kod błędu. Jeśli błąd to CBErrorConnectionTimeout lub CBErrorPeripheralDisconnected — zaplanuj automatyczne ponowne połączenie za 1–5 sekund. Jeśli błąd to CBErrorOperationNotSupported — zaloguj i nie próbuj powtarzać operacji. W przypadku krytycznych połączeń (urządzenia medyczne) użyj exponential backoff z maksymalnym interwałem 60 sekund.

swift
// Obsługa rozłączenia z auto-ponownym łączeniem
func centralManager(
    _ central: CBCentralManager,
    didDisconnectPeripheral peripheral: CBPeripheral,
    error: Error?
) {
    guard let error = error else {
        return // Oczekiwane rozłączenie
    }

    print("Disconnected: \(error.localizedDescription)")

    // Automatyczne ponowne łączenie
    if shouldAutoReconnect {
        DispatchQueue.main.asyncAfter(
            deadline: .now() + reconnectDelay
        ) {
            central.connect(peripheral)
        }
    }
}

Podczas tworzenia niezawodnej aplikacji BLE na iOS uwzględnij: Core Bluetooth nie gwarantuje dostarczenia wszystkich pakietów przy słabym sygnale. Do niezawodnego przesyłania używaj writeType .withResponse (potwierdzony zapis) i subskrybuj powiadomienia (setNotifyValue), aby otrzymywać dane od Peripheral. Prowadź dziennik błędów do diagnozowania problemów z połączeniem w produkcji.

Często zadawane pytania

Dlaczego CBCentralManager nie wykrywa urządzeń?

Sprawdź stan menedżera przez centralManagerDidUpdateState. Upewnij się, że uprawnienie NSBluetoothAlwaysUsageDescription znajduje się w Info.plist, Bluetooth jest włączony na urządzeniu, a urządzenie peryferyjne reklamuje się z prawidłowym typem (connectable advertising, a nie non-connectable).

Ile urządzeń BLE może jednocześnie połączyć się z iOS?

Na urządzeniach z BLE 5.0 (iPhone 8 i nowsze) — do 7 jednoczesnych połączeń. Na starszych urządzeniach — do 3–5. Liczba skanowanych urządzeń jest nieograniczona, ale aktywne połączenia mają ścisły limit ustawiony przez Bluetooth Controller.

Jak często można skanować BLE na iOS bez utraty baterii?

Zaleca się skanowanie z filtrem po UUID i wyłączanie skanowania po znalezieniu urządzenia. Ciągłe skanowanie rozładowuje baterię: 1 godzina ciągłego skanowania zużywa ~10–15% baterii iPhone'a. Używaj timerów i warunków do zatrzymania skanowania.

Jaka jest różnica między CBCentralManager a CBPeripheralManager?

CBCentralManager — do skanowania i łączenia z zewnętrznymi urządzeniami BLE (rola Central). CBPeripheralManager — aby twoje urządzenie iOS samo działało jako peryferium BLE (reklamowało usługi). Jedna instancja może być tylko w jednej roli.

Jak obsłużyć utratę połączenia z urządzeniem BLE?

Zaimplementuj centralManager(_:didDisconnectPeripheral:error:). Jeśli błąd nie jest nil — zaplanuj automatyczne ponowne połączenie z exponential backoff (1 s → 2 s → 4 s → 8 s → maks. 60 s). Jeśli błąd jest nil — urządzenie rozłączyło się normalnie (np. użytkownik nacisnął przycisk na urządzeniu).

Podsumowanie

  • CBCentralManager — główna klasa Core Bluetooth do zarządzania skanowaniem BLE, łączeniem i przesyłaniem danych w roli Central na iOS.
  • Skanowanie uruchamiane jest przez scanForPeripherals z opcjonalnym filtrowaniem po UUID usług w celu zmniejszenia zużycia energii.
  • Połączenie wykonuje się przez connect, sukces potwierdzany jest przez didConnect, błąd — przez didFailToConnect z limitem czasu 30 sekund.
  • Po połączeniu należy wykryć usługi i charakterystyki przez discoverServices i discoverCharacteristics.
  • Skanowanie w tle wymaga bluetooth-central Background Mode i jest obsługiwane z ograniczeniami (filtrowanie po UUID, możliwe opóźnienia).
  • iOS obsługuje do 7 jednoczesnych połączeń BLE na urządzeniach z BLE 5.0, state restoration — do przywracania po restarcie.
  • Obsługa błędów i automatyczne ponowne łączenie z exponential backoff — podstawa niezawodnej aplikacji BLE na iOS.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również