Core Bluetooth : architecture et développement BLE sur iOS

Auteur : IT Sectr Publié le : 2026-07-16 Temps de lecture : 10 min

Core Bluetooth est le framework d’Apple pour interagir avec Bluetooth Low Energy sur iOS, iPadOS et macOS. Le framework fournit un ensemble complet d’API pour fonctionner dans les deux rôles BLE : périphérique central (CBCentralManager) pour scanner et se connecter aux périphériques, et périphérique (CBPeripheralManager) pour émuler un serveur BLE. Core Bluetooth abstrait la pile de protocole BLE du radio physique jusqu’au profil GATT au niveau applicatif. Selon Apple Developer, 2026, Core Bluetooth est la seule API officielle d’Apple pour le développement BLE, prenant en charge BLE 4.0–5.4 avec extended advertising, 2M PHY et LE Audio.

Points clés

  • Core Bluetooth — framework système d’Apple pour le développement BLE sur iOS, iPadOS et macOS
  • CBCentralManager — classe pour scanner et se connecter aux périphériques BLE du côté du périphérique central
  • CBPeripheralManager — classe pour créer un serveur BLE qui publie des services et caractéristiques
  • Profil GATT — modèle hiérarchique de services, caractéristiques et descripteurs pour l’échange de données
  • Modes arrière-plan — Core Bluetooth prend en charge la communication BLE en arrière-plan via les délégués système et la restauration d’état

Qu’est-ce que Core Bluetooth : architecture et composants

Core Bluetooth divise la pile BLE en deux rôles logiques définis par la spécification Bluetooth SIG. Le rôle de périphérique central (Central) est représenté par la classe CBCentralManager — il initie le scan, établit les connexions et gère la liste des CBPeripheral connectés. Le rôle de périphérique (Peripheral) est représenté par CBPeripheralManager — il publie des services et caractéristiques, répond aux requêtes centrales et envoie des notifications. Une même session iOS peut fonctionner simultanément dans les deux rôles sur différents radios BLE, mais une application typique utilise un seul rôle.

L’architecture Core Bluetooth comprend cinq abstractions clés. CBCentralManager gère l’état de l’adaptateur Bluetooth du périphérique : poweredOn (prêt à fonctionner), poweredOff (Bluetooth désactivé), unauthorized (pas d’autorisation), unsupported (BLE indisponible). CBPeripheral représente un périphérique BLE distant avec son UUID, nom, RSSI et hiérarchie GATT. CBService — un groupe logique de caractéristiques. CBCharacteristic — un point de données pour lecture/écriture/notifications. CBPeripheralManager crée un serveur GATT local pour émuler un périphérique.

ClasseRôleMéthodes principales
CBCentralManagerPériphérique centralscanForPeripherals, connect, cancelPeripheralConnection, retrievePeripherals
CBPeripheralPériphérique distantdiscoverServices, discoverCharacteristics, readValue, writeValue, setNotifyValue
CBPeripheralManagerPériphérique localaddService, removeService, startAdvertising, respondToRequest, updateValue
CBCentralCentral distantmaximumUpdateValueLength, identifier, ancsAuthorized

Les états de CBCentralManager contrôlent toutes les opérations BLE. Au démarrage de l’application, centralManagerDidUpdateState est appelé avec l’état Bluetooth actuel. Si l’état n’est pas .poweredOn, toutes les appels BLE sont ignorés par le système. Le développeur doit vérifier l’état avant chaque scan et connexion. La transition de .poweredOff à .poweredOn se produit lorsque le Bluetooth est activé dans les Réglages iOS — le délégué reçoit un nouvel appel et l’application peut reprendre le scan.

CBCentralManager : scan et connexion des périphériques BLE

CBCentralManager est le point d’entrée pour toutes les opérations BLE du côté du périphérique central. L’initialisation prend un délégué (CBCentralManagerDelegate) et une DispatchQueue — Apple recommande d’utiliser la file principale pour la simplicité ou une file sérielle pour les performances. Après l’initialisation, le framework vérifie automatiquement l’état Bluetooth et appelle centralManagerDidUpdateState : — le premier délégué obligatoire à traiter.

Le scan commence avec la méthode scanForPeripheralsWithServices:options:. Le premier paramètre est un tableau de CBUUID de services pour filtrer : si les UUID des services souhaités sont connus, les transmettre réduit la consommation d’énergie et le temps de recherche. Si nil, tous les périphériques BLE à portée sont découverts. Les options incluent .allowDuplicatesKey (découvertes répétées du même périphérique) et .solicitedServiceUUIDsKey (pour les services publiés sur le central).

swift
import CoreBluetooth

class BLECentral: NSObject {

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

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

    // Démarrer le scan BLE
    func startScan() {
        guard centralManager.state == .poweredOn else {
            print("Bluetooth indisponible")
            return
        }
        // Scanner tous les périphériques (nil = aucun filtre)
        centralManager.scanForPeripherals(withServices: nil,
                                            options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
    }

    // Arrêter le scan
    func stopScan() {
        centralManager.stopScan()
    }

    // Connecter au périphérique sélectionné
    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)")
    }
}

La classe BLECentral démontre le cycle complet de scan et de connexion des périphériques BLE. centralManagerDidUpdateState lance le scan lorsque le Bluetooth est activé. didDiscoverPeripheral collecte les périphériques trouvés dans le tableau discoveredPeripherals avec déduplication par identifier. Après la connexion (didConnect), la découverte des services commence immédiatement — c’est une étape obligatoire avant toute opération GATT.

CBPeripheralManager : création d’un serveur BLE sur iOS

CBPeripheralManager est la classe pour émuler un périphérique BLE sur iOS. Une application en rôle périphérique peut publier ses services et caractéristiques, accepter les requêtes de lecture/écriture entrantes d’un périphérique central et envoyer des notifications. CBPeripheralManager est utilisé pour les accessoires BLE émulés par iPhone : télécommandes, claviers, trackers, passerelles IoT.

Le cycle de vie de CBPeripheralManager commence par l’initialisation et le délégué CBPeripheralManagerDelegate. Après réception de la confirmation poweredOn via peripheralManagerDidUpdateState:, les services sont publiés (addService:) et la publicité est lancée (startAdvertising:). Les données publicitaires CBAdvertisementData incluent le nom local (CBAdvertisementDataLocalNameKey), les UUID de services (CBAdvertisementDataServiceUUIDsKey) et le niveau de puissance d’émission (CBAdvertisementDataTxPowerLevelKey). La taille maximale d’un paquet publicitaire est de 31 octets pour BLE 4.0, 251 octets pour extended advertising BLE 5.0+.

swift
// Périphérique BLE sur 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)
    }

    // Publier le service avec caractéristique
    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)
    }

    // Démarrer la publicité
    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()
        }
    }

    // Traiter la requête de lecture
    func peripheralManager(_ peripheral: CBPeripheralManager,
                        didReceiveRead request: CBATTRequest) {
        let data = "CurrentValue".data(using: .utf8)!
        request.value = data
        peripheralManager.respond(to: request, withResult: .success)
    }

    // Traiter la requête d’écriture
    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)
    }
}

La classe BLEPeripheral crée un serveur BLE avec une seule caractéristique prenant en charge la lecture, l’écriture et les notifications. Après l’initialisation, peripheralManagerDidUpdateState publie le service via addService:, puis lance la publicité via startAdvertising:. Les gestionnaires didReceiveRead et didReceiveWrite répondent aux requêtes GATT entrantes du périphérique central. La méthode updateValue:forCharacteristic:onSubscribedCentrals: est utilisée pour envoyer des notifications.

Opérations GATT : lecture, écriture et notifications

Les opérations GATT (Generic Attribute Profile) sont le fondement de l’échange de données dans Core Bluetooth. Après la découverte des services et caractéristiques, le périphérique central peut effectuer trois types d’opérations : lire une valeur de caractéristique, écrire une valeur et s’abonner aux notifications/indications. Chaque opération est asynchrone et retourne le résultat via le délégué CBPeripheralDelegate correspondant.

Lecture : effectuée en appelant readValueForCharacteristic:. La valeur arrive dans peripheral:didUpdateValueForCharacteristic:error:. Important : la lecture retourne la valeur actuelle du périphérique, pas une valeur en cache. Si le périphérique ne prend pas en charge la lecture (propriété .read), l’appel retournera une erreur. Pour les grandes valeurs (plus grandes que MTU), BLE fragmente et réassemble automatiquement les données au niveau GATT.

Écriture : effectuée en appelant writeValue:forCharacteristic:type:. BLE prend en charge deux modèles d’écriture : withResponse (fiable, avec accusé de réception) et withoutResponse (rapide, sans accusé de réception). La propriété CBCharacteristic.properties définit les types d’écriture disponibles. La taille maximale d’un seul paquet d’écriture est limitée par MTU : 23 octets pour BLE 4.0 (20 octets de données utiles + 3 octets d’en-tête), jusqu’à 247 octets pour BLE 5.0 avec MTU étendu (MTU 251).

Notifications : activées en appelant setNotifyValue:true forCharacteristic:. Après l’abonnement, le périphérique envoie automatiquement des mises à jour via peripheral:didUpdateValueForCharacteristic: chaque fois que la valeur de la caractéristique change. Pour désactiver les notifications, appelez setNotifyValue:false forCharacteristic:. Core Bluetooth gère automatiquement le descripteur CCCD sur le périphérique.

OpérationMéthodeDéléguéType de transfert
LecturereadValueForCharacteristic:didUpdateValueForCharacteristicPolling (requête-réponse)
Écriture withResponsewriteValue:forCharacteristic:type:withResponsedidWriteValueForCharacteristicAvec accusé de réception
Écriture withoutResponsewriteValue:forCharacteristic:type:withoutResponseAucun déléguéSans accusé de réception
NotificationsetNotifyValue:true forCharacteristic:didUpdateNotificationStateForCharacteristic + didUpdateValueForCharacteristicPush du périphérique

Mode arrière-plan de Core Bluetooth et State Restoration

Le mode arrière-plan de Core Bluetooth permet aux applications BLE de continuer à scanner, maintenir les connexions et recevoir des notifications en arrière-plan. Pour l’activer, activez la capacité « Uses Bluetooth LE accessories » dans Xcode (Info.plist → Required background modes → App communicates using Core Bluetooth) et ajoutez la clé « bluetooth-central » à UIBackgroundModes. Pour le rôle périphérique — « bluetooth-peripheral ».

State Restoration est un mécanisme de Core Bluetooth pour restaurer l’état des connexions BLE après un redémarrage de l’application par iOS. Lorsque le mode arrière-plan est actif et qu’un restoreIdentifier est spécifié dans l’initialisation de CBCentralManager ou CBPeripheralManager, iOS enregistre l’état de la pile BLE à la fin de l’application et le restaure au prochain lancement. Le délégué centralManager:willRestoreState: reçoit un dictionnaire avec les CBPeripheral sauvegardés et les connexions en attente.

swift
// Configuration de Core Bluetooth avec 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 {

    // Restaurer l’état après le redémarrage
    func centralManager(_ central: CBCentralManager,
                        willRestoreState dict: [String : Any]) {
        if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey]
            as? [CBPeripheral] {
            for peripheral in peripherals {
                peripheral.delegate = self
                // Restaurer la découverte GATT
                peripheral.discoverServices(nil)
            }
        }
    }

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            print("Bluetooth prêt après la restauration")
        }
    }
}

Dans la configuration BLECentralWithRestoration, la clé CBCentralManagerOptionRestoreIdentifierKey active la sauvegarde d’état. Si l’application a été terminée par iOS (par exemple, en raison d’un manque de mémoire), au prochain lancement centralManager:willRestoreState: reçoit une liste des CBPeripheral précédemment connectés. L’application restaure les délégués et effectue une redécouverte des services — l’utilisateur ne remarque pas l’interruption de connexion. Sans State Restoration, toutes les sessions BLE sont perdues lorsque l’application se termine.

Exemple d’application BLE en Swift : central et périphérique

Un exemple complet d’application BLE en Swift combine les périphériques central et périphérique dans un seul projet. L’application peut fonctionner en deux modes : découvrir et se connecter aux périphériques BLE (Central) ou émuler un accessoire BLE (Peripheral). Ci-dessous une architecture avec un gestionnaire BLE commun qui sélectionne le rôle au démarrage.

swift
// Gestionnaire BLE universel pour central et périphérique
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)
        }
    }

    // Périphérique central : scan
    func scanForDevices() {
        centralManager?.scanForPeripherals(withServices: nil, options: nil)
    }

    // Périphérique : publicité
    func advertiseService() {
        let data: [String: Any] = [
            CBAdvertisementDataServiceUUIDsKey: [advertisedServiceUUID]
        ]
        peripheralManager?.startAdvertising(data)
    }
}

// Utilisation au démarrage
let isCentral = UserDefaults.standard.bool(forKey: "isCentral")
let manager = BLEManager(role: isCentral ? .central : .peripheral)

if isCentral {
    manager.scanForDevices()
} else {
    manager.advertiseService()
}

Le BLEManager sélectionne le rôle à l’initialisation et crée le gestionnaire correspondant (CBCentralManager ou CBPeripheralManager). Le drapeau de rôle peut être stocké dans UserDefaults ou transmis via un serveur de configuration. Cette approche permet à l’application BLE de s’adapter au cas d’utilisation : sur un point de vente, un iPhone fonctionne comme central pour scanner les terminaux de paiement ; sur une passerelle IoT — comme périphérique pour collecter les données des capteurs.

Questions fréquentes

Qu’est-ce que Core Bluetooth ?

Core Bluetooth est le framework d’Apple pour le développement BLE sur iOS, iPadOS et macOS. Il fournit des API pour les périphériques centraux (CBCentralManager) et périphériques (CBPeripheralManager). Il prend en charge BLE 4.0–5.4, extended advertising, 2M PHY et LE Audio. Core Bluetooth est la seule API officielle d’Apple pour la communication BLE, nécessaire pour toutes les applications iOS fonctionnant avec Bluetooth Low Energy.

Quelle est la différence entre CBCentralManager et CBPeripheralManager ?

CBCentralManager est une classe pour le rôle de périphérique central : il scanne les périphériques BLE, établit les connexions, lit et écrit les caractéristiques. CBPeripheralManager est une classe pour le rôle périphérique : il publie des services, répond aux requêtes de lecture/écriture et envoie des notifications. Un même iPhone peut fonctionner dans les deux rôles simultanément via différentes instances de gestionnaires.

Comment configurer Core Bluetooth pour le fonctionnement en arrière-plan ?

Pour le fonctionnement BLE en arrière-plan, activez la capacité « Uses Bluetooth LE accessories » dans Xcode et ajoutez la clé « bluetooth-central » à UIBackgroundModes. Pour le rôle périphérique — « bluetooth-peripheral ». Spécifiez un restoreIdentifier lors de l’initialisation du gestionnaire pour State Restoration. Sans ces paramètres, l’application en arrière-plan ne recevra pas les événements BLE et perdra les connexions.

Pourquoi Core Bluetooth ne trouve-t-il pas de périphériques ?

Raisons courantes : CBCentralManager.state != .poweredOn (Bluetooth désactivé ou non autorisé), délégué non défini, périphérique hors de portée ou n’envoyant pas de paquets publicitaires. Vérifiez l’autorisation NSBluetoothAlwaysUsageDescription dans Info.plist, l’état Bluetooth dans centralManagerDidUpdateState et assurez-vous que scanForPeripherals est appelé uniquement lorsque .poweredOn.

Peut-on connecter plusieurs CBPeripheral simultanément ?

Oui, Core Bluetooth prend en charge les connexions simultanées à plusieurs périphériques BLE. Chaque CBPeripheral est géré indépendamment via son propre délégué. iOS limite le nombre de connexions BLE simultanées au niveau système (généralement 5–7 pour iPhone). Pour les scénarios 1:N (par exemple, une salle de sport avec 10 trackers), il est nécessaire de mettre en file d’attente et de servir les périphériques de manière cyclique.

Résumé

  • Core Bluetooth — framework système d’Apple pour le développement BLE avec les classes CBCentralManager et CBPeripheralManager
  • CBCentralManager gère le scan, la connexion et les opérations GATT avec les périphériques BLE distants
  • CBPeripheralManager émule les périphériques BLE avec publication de services et traitement des requêtes entrantes
  • Profil GATT inclut services, caractéristiques et descripteurs avec opérations de lecture, écriture et notification
  • Mode arrière-plan nécessite UIBackgroundModes et restoreIdentifier pour State Restoration
  • MTU limite la taille des paquets BLE : 23 octets pour BLE 4.0, jusqu’à 251 octets pour BLE 5.0+ avec MTU étendu
  • Swift async/await via CheckedContinuation simplifie le code BLE asynchrone avec les délégués

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi