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 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.
| Classe | Papel | Métodos principais |
|---|---|---|
| CBCentralManager | Dispositivo central | scanForPeripherals, connect, cancelPeripheralConnection, retrievePeripherals |
| CBPeripheral | Periférico remoto | discoverServices, discoverCharacteristics, readValue, writeValue, setNotifyValue |
| CBPeripheralManager | Periférico local | addService, removeService, startAdvertising, respondToRequest, updateValue |
| CBCentral | Central remoto | maximumUpdateValueLength, 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 é 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).
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 é 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+.
// 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.
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ção | Método | Delegado | Tipo de transferência |
|---|---|---|---|
| Leitura | readValueForCharacteristic: | didUpdateValueForCharacteristic | Polling (solicitação-resposta) |
| Escrita withResponse | writeValue:forCharacteristic:type:withResponse | didWriteValueForCharacteristic | Com confirmação |
| Escrita withoutResponse | writeValue:forCharacteristic:type:withoutResponse | Sem delegado | Sem confirmação |
| Notificação | setNotifyValue:true forCharacteristic: | didUpdateNotificationStateForCharacteristic + didUpdateValueForCharacteristic | Push do periférico |
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.
// 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.
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.
// 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
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.
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.
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.
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.
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
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.
Leia também