Core Bluetooth: arquitetura e desenvolvimento BLE no iOS

Autor: IT Sectr Publicado: 2026-07-16 Tempo de leitura: 10 min

Core Bluetooth é o framework da Apple para interagir com Bluetooth Low Energy no iOS, iPadOS e macOS. O framework fornece um conjunto completo de APIs para operar em ambos os papéis BLE: dispositivo central (CBCentralManager) para escanear e conectar a periféricos, e dispositivo periférico (CBPeripheralManager) para emular um servidor BLE. O Core Bluetooth abstrai a pilha de protocolo BLE desde o rádio físico até o perfil GATT de aplicação. De acordo com Apple Developer, 2026, o Core Bluetooth é a única API oficial da Apple para desenvolvimento BLE, suportando BLE 4.0–5.4 com extended advertising, 2M PHY e LE Audio.

Principais pontos

  • Core Bluetooth — framework de sistema da Apple para desenvolvimento BLE no iOS, iPadOS e macOS
  • CBCentralManager — classe para escanear e conectar a periféricos BLE do lado do dispositivo central
  • CBPeripheralManager — classe para criar um servidor BLE que publica serviços e características
  • Perfil GATT — modelo hierárquico de serviços, características e descritores para troca de dados
  • Modos em segundo plano — Core Bluetooth suporta comunicação BLE em segundo plano através de delegados do sistema e restauração de estado

O que é Core Bluetooth: arquitetura e componentes

Core Bluetooth divide a pilha BLE em dois papéis lógicos definidos pela especificação Bluetooth SIG. O papel de dispositivo central (Central) é representado pela classe CBCentralManager — ele inicia o escaneamento, estabelece conexões e gerencia a lista de CBPeripherals conectados. O papel de dispositivo periférico (Peripheral) é representado pelo CBPeripheralManager — ele publica serviços e características, responde a solicitações centrais e envia notificações. Uma mesma sessão iOS pode operar simultaneamente em ambos os papéis em diferentes rádios BLE, mas um aplicativo típico usa um único papel.

A arquitetura do Core Bluetooth inclui cinco abstrações principais. CBCentralManager gerencia o estado do adaptador Bluetooth do dispositivo: poweredOn (pronto para funcionar), poweredOff (Bluetooth desativado), unauthorized (sem permissão), unsupported (BLE indisponível). CBPeripheral representa um dispositivo BLE remoto com seu UUID, nome, RSSI e hierarquia GATT. CBService — um grupo lógico de características. CBCharacteristic — um ponto de dados para leitura/escrita/notificações. CBPeripheralManager cria um servidor GATT local para emular um periférico.

ClassePapelMétodos principais
CBCentralManagerDispositivo centralscanForPeripherals, connect, cancelPeripheralConnection, retrievePeripherals
CBPeripheralPeriférico remotodiscoverServices, discoverCharacteristics, readValue, writeValue, setNotifyValue
CBPeripheralManagerPeriférico localaddService, removeService, startAdvertising, respondToRequest, updateValue
CBCentralCentral remotomaximumUpdateValueLength, identifier, ancsAuthorized

Estados do CBCentralManager controlam todas as operações BLE. Quando o aplicativo inicia, centralManagerDidUpdateState é chamado com o estado atual do Bluetooth. Se o estado não for .poweredOn, qualquer chamada BLE é ignorada pelo sistema. O desenvolvedor deve verificar o estado antes de cada escaneamento e conexão. A transição de .poweredOff para .poweredOn ocorre quando o Bluetooth é ativado nas Configurações do iOS — o delegado recebe uma chamada repetida e o aplicativo pode retomar o escaneamento.

CBCentralManager: escaneamento e conexão de dispositivos BLE

CBCentralManager é o ponto de entrada para todas as operações BLE do lado do dispositivo central. A inicialização aceita um delegado (CBCentralManagerDelegate) e uma DispatchQueue — a Apple recomenda usar a fila principal para simplicidade ou uma fila serial para desempenho. Após a inicialização, o framework verifica automaticamente o estado do Bluetooth e chama centralManagerDidUpdateState: — o primeiro delegado obrigatório a ser tratado.

O escaneamento começa com o método scanForPeripheralsWithServices:options:. O primeiro parâmetro é um array de CBUUID de serviços para filtrar: se os UUIDs dos serviços desejados forem conhecidos, passá-los reduz o consumo de energia e o tempo de busca. Se for nil, todos os dispositivos BLE no alcance são descobertos. As opções incluem .allowDuplicatesKey (descobertas repetidas do mesmo dispositivo) e .solicitedServiceUUIDsKey (para serviços publicados no 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)
    }

    // Iniciar escaneamento BLE
    func startScan() {
        guard centralManager.state == .poweredOn else {
            print("Bluetooth indisponível")
            return
        }
        // Escaneie todos os dispositivos (nil = sem filtro)
        centralManager.scanForPeripherals(withServices: nil,
                                            options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
    }

    // Parar escaneamento
    func stopScan() {
        centralManager.stopScan()
    }

    // Conectar ao dispositivo selecionado
    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)")
    }
}

A classe BLECentral demonstra o ciclo completo de escaneamento e conexão de dispositivos BLE. centralManagerDidUpdateState inicia o escaneamento quando o Bluetooth está ativado. didDiscoverPeripheral coleta os dispositivos encontrados no array discoveredPeripherals com deduplicação por identifier. Após a conexão (didConnect), a descoberta de serviços começa imediatamente — esta é uma etapa obrigatória antes de qualquer operação GATT.

CBPeripheralManager: criação de um servidor BLE no iOS

CBPeripheralManager é a classe para emular um dispositivo periférico BLE no iOS. Um aplicativo no papel periférico pode publicar seus serviços e características, aceitar solicitações de leitura/escrita recebidas de um dispositivo central e enviar notificações. O CBPeripheralManager é usado para acessórios BLE emulados pelo iPhone: controles remotos, teclados, rastreadores, gateways IoT.

O ciclo de vida do CBPeripheralManager começa com a inicialização e o delegado CBPeripheralManagerDelegate. Após receber a confirmação de poweredOn via peripheralManagerDidUpdateState:, os serviços são publicados (addService:) e a publicidade é iniciada (startAdvertising:). Os dados de publicidade CBAdvertisementData incluem o nome local (CBAdvertisementDataLocalNameKey), UUIDs de serviços (CBAdvertisementDataServiceUUIDsKey) e nível de potência de transmissão (CBAdvertisementDataTxPowerLevelKey). O tamanho máximo do pacote de publicidade é de 31 bytes para BLE 4.0, 251 bytes para extended advertising BLE 5.0+.

swift
// Periférico BLE no 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)
    }

    // Publicar serviço com característica
    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)
    }

    // Iniciar publicidade
    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()
        }
    }

    // Manipular solicitação de leitura
    func peripheralManager(_ peripheral: CBPeripheralManager,
                        didReceiveRead request: CBATTRequest) {
        let data = "CurrentValue".data(using: .utf8)!
        request.value = data
        peripheralManager.respond(to: request, withResult: .success)
    }

    // Manipular solicitação de escrita
    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)
    }
}

A classe BLEPeripheral cria um servidor BLE com uma única característica que suporta leitura, escrita e notificações. Após a inicialização, peripheralManagerDidUpdateState publica o serviço via addService:, então inicia a publicidade via startAdvertising:. Os manipuladores didReceiveRead e didReceiveWrite respondem a solicitações GATT recebidas do dispositivo central. O método updateValue:forCharacteristic:onSubscribedCentrals: é usado para enviar notificações.

Operações GATT: leitura, escrita e notificações

As operações GATT (Generic Attribute Profile) são a base da troca de dados no Core Bluetooth. Após a descoberta de serviços e características, o dispositivo central pode realizar três tipos de operações: ler um valor de característica, escrever um valor e assinar notificações/indicações. Cada operação é assíncrona e retorna o resultado através do delegado CBPeripheralDelegate correspondente.

Leitura: é realizada chamando readValueForCharacteristic:. O valor chega em peripheral:didUpdateValueForCharacteristic:error:. Importante: a leitura retorna o valor atual do dispositivo, não um valor em cache. Se o dispositivo não suportar leitura (propriedade .read), a chamada retornará um erro. Para valores grandes (maiores que MTU), o BLE fragmenta e remonta automaticamente os dados no nível GATT.

Escrita: é realizada chamando writeValue:forCharacteristic:type:. O BLE suporta dois modelos de escrita: withResponse (confiável, com confirmação) e withoutResponse (rápido, sem confirmação). A propriedade CBCharacteristic.properties define os tipos de escrita disponíveis. O tamanho máximo de um único pacote de escrita é limitado pelo MTU: 23 bytes para BLE 4.0 (20 bytes de dados úteis + 3 bytes de cabeçalho), até 247 bytes para BLE 5.0 com MTU estendido (MTU 251).

Notificações: são ativadas chamando setNotifyValue:true forCharacteristic:. Após a assinatura, o periférico envia automaticamente atualizações via peripheral:didUpdateValueForCharacteristic: sempre que o valor da característica muda. Para desativar as notificações, chame setNotifyValue:false forCharacteristic:. O Core Bluetooth gerencia automaticamente o descritor CCCD no periférico.

OperaçãoMétodoDelegadoTipo de transferência
LeiturareadValueForCharacteristic:didUpdateValueForCharacteristicPolling (solicitação-resposta)
Escrita withResponsewriteValue:forCharacteristic:type:withResponsedidWriteValueForCharacteristicCom confirmação
Escrita withoutResponsewriteValue:forCharacteristic:type:withoutResponseSem delegadoSem confirmação
NotificaçãosetNotifyValue:true forCharacteristic:didUpdateNotificationStateForCharacteristic + didUpdateValueForCharacteristicPush do periférico

Modo em segundo plano do Core Bluetooth e State Restoration

O modo em segundo plano do Core Bluetooth permite que aplicativos BLE continuem escaneando, mantenham conexões e recebam notificações enquanto estão em segundo plano. Para ativá-lo, é necessário habilitar a capacidade “Uses Bluetooth LE accessories” no Xcode (Info.plist → Required background modes → App communicates using Core Bluetooth) e adicionar a chave “bluetooth-central” ao UIBackgroundModes. Para o papel periférico — “bluetooth-peripheral”.

State Restoration é um mecanismo do Core Bluetooth para restaurar o estado das conexões BLE após um reinício do aplicativo pelo iOS. Quando o modo em segundo plano está ativo e um restoreIdentifier é especificado na inicialização do CBCentralManager ou CBPeripheralManager, o iOS salva o estado da pilha BLE quando o aplicativo é encerrado e o restaura na próxima inicialização. O delegado centralManager:willRestoreState: recebe um dicionário com os CBPeripherals salvos e conexões pendentes.

swift
// Configuração do Core Bluetooth com 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 {

    // Restaurar estado após reinicialização
    func centralManager(_ central: CBCentralManager,
                        willRestoreState dict: [String : Any]) {
        if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey]
            as? [CBPeripheral] {
            for peripheral in peripherals {
                peripheral.delegate = self
                // Restaurar descoberta GATT
                peripheral.discoverServices(nil)
            }
        }
    }

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            print("Bluetooth pronto após restauração")
        }
    }
}

Na configuração BLECentralWithRestoration, a chave CBCentralManagerOptionRestoreIdentifierKey ativa a preservação de estado. Se o aplicativo foi encerrado pelo iOS (por exemplo, devido à pressão de memória), na próxima inicialização centralManager:willRestoreState: recebe uma lista de CBPeripherals conectados anteriormente. O aplicativo restaura os delegados e realiza a rediscovery de serviços — o usuário não percebe a interrupção da conexão. Sem o State Restoration, todas as sessões BLE são perdidas quando o aplicativo é encerrado.

Exemplo de aplicativo BLE em Swift: central e periférico

Um exemplo completo de um aplicativo BLE em Swift combina dispositivos central e periférico em um único projeto. O aplicativo pode operar em dois modos: descobrir e conectar a dispositivos BLE (Central) ou emular um acessório BLE (Peripheral). Abaixo está uma arquitetura com um gerenciador BLE comum que seleciona o papel na inicialização.

swift
// Gerenciador BLE universal para central e periférico
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)
        }
    }

    // Dispositivo central: escaneamento
    func scanForDevices() {
        centralManager?.scanForPeripherals(withServices: nil, options: nil)
    }

    // Dispositivo periférico: publicidade
    func advertiseService() {
        let data: [String: Any] = [
            CBAdvertisementDataServiceUUIDsKey: [advertisedServiceUUID]
        ]
        peripheralManager?.startAdvertising(data)
    }
}

// Uso na inicialização
let isCentral = UserDefaults.standard.bool(forKey: "isCentral")
let manager = BLEManager(role: isCentral ? .central : .peripheral)

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

O BLEManager seleciona o papel na inicialização e cria o Manager correspondente (CBCentralManager ou CBPeripheralManager). A flag de papel pode ser armazenada em UserDefaults ou passada através de um servidor de configuração. Esta abordagem permite que o aplicativo BLE se adapte ao caso de uso: em um ponto de venda, um iPhone funciona como central para escanear terminais de pagamento; em um gateway IoT — como periférico para coletar dados de sensores.

Perguntas frequentes

O que é Core Bluetooth?

Core Bluetooth é o framework da Apple para desenvolvimento BLE no iOS, iPadOS e macOS. Ele fornece APIs tanto para dispositivos centrais (CBCentralManager) quanto periféricos (CBPeripheralManager). Suporta BLE 4.0–5.4, extended advertising, 2M PHY e LE Audio. Core Bluetooth é a única API oficial da Apple para comunicação BLE, necessária para todos os aplicativos iOS que trabalham com Bluetooth Low Energy.

Qual é a diferença entre CBCentralManager e CBPeripheralManager?

CBCentralManager é uma classe para operar no papel de dispositivo central: escaneia periféricos BLE, estabelece conexões, lê e escreve características. CBPeripheralManager é uma classe para operar no papel periférico: publica serviços, responde a solicitações de leitura/escrita e envia notificações. Um único iPhone pode funcionar em ambos os papéis simultaneamente através de diferentes instâncias de gerenciadores.

Como configurar o Core Bluetooth para operação em segundo plano?

Para operação BLE em segundo plano, habilite a capacidade “Uses Bluetooth LE accessories” no Xcode e adicione a chave “bluetooth-central” ao UIBackgroundModes. Para o papel periférico — “bluetooth-peripheral”. Especifique um restoreIdentifier ao inicializar o gerenciador para State Restoration. Sem essas configurações, o aplicativo em segundo plano não receberá eventos BLE e perderá as conexões.

Por que o Core Bluetooth não encontra dispositivos?

Razões comuns: CBCentralManager.state != .poweredOn (Bluetooth desativado ou não autorizado), delegado não definido, dispositivo fora do alcance ou não enviando pacotes de publicidade. Verifique a permissão NSBluetoothAlwaysUsageDescription no Info.plist, o status do Bluetooth em centralManagerDidUpdateState e certifique-se de que scanForPeripherals seja chamado apenas quando .poweredOn.

É possível conectar vários CBPeripherals simultaneamente?

Sim, o Core Bluetooth suporta conexões simultâneas a múltiplos dispositivos BLE. Cada CBPeripheral é gerenciado independentemente através de seu próprio delegado. O iOS limita o número de conexões BLE simultâneas no nível do sistema (normalmente 5–7 para iPhone). Para cenários 1:N (por exemplo, uma academia com 10 rastreadores), é necessário enfileirar e atender periféricos ciclicamente.

Resumo

  • Core Bluetooth — framework de sistema da Apple para desenvolvimento BLE com as classes CBCentralManager e CBPeripheralManager
  • CBCentralManager gerencia escaneamento, conexão e operações GATT com dispositivos BLE remotos
  • CBPeripheralManager emula periféricos BLE com publicação de serviços e manipulação de solicitações recebidas
  • Perfil GATT inclui serviços, características e descritores com operações de leitura, escrita e notificação
  • Modo em segundo plano requer UIBackgroundModes e restoreIdentifier para State Restoration
  • MTU limita o tamanho do pacote BLE: 23 bytes para BLE 4.0, até 251 bytes para BLE 5.0+ com MTU estendido
  • Swift async/await via CheckedContinuation simplifica o código BLE assíncrono com delegados

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também