Core Bluetooth
Implement Bluetooth Low Energy (BLE) communication on iOS using CBCentralManager (connecting to accessories) and CBPeripheralManager (advertising as an accessory). Targets Swift 6.3 / iOS 26+.
Contents
- Permissions and Background Modes
- Central vs Peripheral Roles
- Core Communication Contract
- State Restoration and MTU
- Route by Task
- Common Mistakes
- Review Checklist
- References
Permissions and Background Modes
Declare NSBluetoothAlwaysUsageDescription in Info.plist. For background execution, enable capabilities in Signing & Capabilities > Background Modes:
- Uses Bluetooth LE accessories: Central role in background (
bluetooth-central) - Acts as a Bluetooth LE accessory: Peripheral role in background (
bluetooth-peripheral)
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app requires Bluetooth to connect to external fitness sensors.</string>
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
</array>
Central vs Peripheral Roles
| Feature | Central (CBCentralManager) |
Peripheral (CBPeripheralManager) |
|---|---|---|
| Primary Task | Scans, connects, and consumes GATT services | Publishes services, advertises, responds to requests |
| Discovery | scanForPeripherals(withServices:options:) |
startAdvertising(_:) |
| Data Read/Write | readValue(for:) / writeValue(_:for:type:) |
respond(to:withResult:) |
| Updates | Subscribes with setNotifyValue(true, for:) |
updateValue(_:for:onSubscribedCentrals:) |
| Queue | Dedicated serial DispatchQueue |
Dedicated serial DispatchQueue |
Core Communication Contract
- Wait for
.poweredOn: Never call scan, connect, or advertise untilcentralManagerDidUpdateState(_:)reports.poweredOn. - Retain discovered peripherals: You must store a strong reference to
CBPeripheralinstances returned indidDiscover. If released, connection drops immediately. - Scan with service UUIDs: In background mode, scanning without explicit
CBUUIDfilters is disabled by iOS to preserve battery. - Discover narrowly: Pass specific
[CBUUID]arrays todiscoverServicesanddiscoverCharacteristicsrather thannilto avoid slow full-GATT enumeration. - Honor write types: Use
.withResponsefor acknowledged writes (peripheral(_:didWriteValueFor:error:)); use.withoutResponseonly whencanSendWriteWithoutResponseis verified.
State Restoration and MTU
- State Restoration: Pass
CBCentralManagerOptionRestoreIdentifierKeyduring manager initialization to allow iOS to relaunch the app in the background when a Bluetooth event occurs. Handle restoration incentralManager(_:willRestoreState:). - MTU & Packet Sizing: Check
peripheral.maximumWriteValueLength(for:)before sending large payloads. The default BLE MTU is 23 bytes (20 payload bytes). Do not assume 512-byte MTU without checking.
Route by Task
- For a complete SwiftUI-ready
@ObservableBLE manager, read SwiftUI BLE Integration. - For exponential backoff and automatic peripheral reconnection, read Reconnection Strategies.
- For byte buffers and binary data parsing helpers, read Data Parsing Helpers.
- For congestion control and packet flow management, read Write Flow Control.
- For managing multiple simultaneous peripherals, read Multiple Peripheral Management.
- For high-speed raw streaming without GATT overhead, read L2CAP Channels.
- For peripheral role request handling and subscription updates, read Peripheral Role: Responding to Requests.
Common Mistakes
- Initiating Bluetooth scanning before
centralManagerDidUpdateState(_:)transitions to.poweredOn. - Failing to retain the
CBPeripheralreference during connection, leading to silent drops. - Scanning without explicit service
CBUUIDs in background mode (system ignores unfiltered background scans). - Ignoring
canSendWriteWithoutResponse, causing silent packet drops during burst writes. - Performing heavy parsing or UI operations on the Core Bluetooth dispatch queue.
Review Checklist
-
NSBluetoothAlwaysUsageDescriptionprovided inInfo.plist - Required
UIBackgroundModesconfigured (bluetooth-central/bluetooth-peripheral) - State checked for
.poweredOnbefore issuing commands - Connected peripherals strongly referenced by the manager
- Service and characteristic discovery scoped to specific
[CBUUID] - Write type matches characteristic properties (
.withResponsevs.withoutResponse) - State restoration identifier configured and handled in
willRestoreState - Core Bluetooth delegate runs on a dedicated serial queue, with UI updates dispatched to
@MainActor - Maximum packet size validated with
maximumWriteValueLength
References
- Core Bluetooth extended patterns and L2CAP guide
- Core Bluetooth documentation
- CBCentralManager
- CBPeripheral
- CBPeripheralManager