CBCentralManagerは、iOSのCore Bluetoothフレームワークの中心的なクラスで、BLEペリフェラルデバイスのスキャン、接続、および相互作用を管理します。Core Bluetooth(iOS 5+、2011)は、GATTレベルでBLEスタック上の高レベルの抽象化を提供し、Link LayerとHCIの詳細を開発者から隠します。CBCentralManagerはCentralロールを実装します。scanForPeripheralsを介して電波をスキャンし、connectを介して接続を開始し、discoverServicesを介してサービスを発見し、データ転送を管理します。Apple Developer Documentation(2024)によると、CBCentralManagerはBLE 5.0対応デバイスで最大7つの同時BLE接続をサポートします。
重要なポイント
CBCentralManagerは、iOSのBLEアーキテクチャでCentralロールを実装するための主要なCore Bluetoothクラスです。スキャン中のデバイスの発見からデータ転送と切断まで、BLE接続のライフサイクル全体を管理します。CBCentralManagerはCBCentralManagerDelegateを介して非同期的に動作し、Bluetoothスタックのイベントをアプリに通知します。
CBCentralManagerの初期化はstate restorationプロセスを開始します。マネージャーはデバイスのBluetooth状態を確認し、アプリが閉じられていた場合は以前の接続を復元します。初期化プロセスはBluetoothの状態に応じて50〜500ミリ秒かかる場合があります。BLE操作を開始する前に、アプリはcentralManagerDidUpdateStateコールを待つ必要があります。
Core BluetoothアーキテクチャはDelegationパターンに基づいています。CBCentralManagerはイベント処理(デバイス発見、接続、エラー)をCBCentralManagerDelegateプロトコルに委任します。特定のペリフェラルを操作するには、CBPeripheralDelegateプロトコルが使用され、発見されたサービス、特性、受信データを通知します。この非同期モデルにより、ノンブロッキングUIが保証されます。
CBCentralManagerは複数の状態を経由します。これによりBLEスタックが利用可能かどうかが決まります。状態はデリゲートを介して渡されます:centralManagerDidUpdateState(_:)。開発者はすべての状態を処理する必要があります。poweredOnだけでなく、Bluetoothがオフまたは利用不可の場合も同様です。
| 状態 | 値 | 開発者の対応 |
|---|---|---|
| .poweredOn | Bluetoothがオンで準備完了 | スキャンを開始 |
| .poweredOff | Bluetoothがオフ | ユーザーにアラートを表示 |
| .unauthorized | 許可なし | 設定で許可を要求 |
| .unsupported | デバイスがBLE非対応 | BLE機能を非表示 |
| .unknown | 状態が未定義 | 次の更新を待機 |
| .resetting | Bluetoothを再起動中 | 復旧を待機 |
未許可状態はiOS 13+以降ますます一般的になっています。このバージョン以降、アプリはInfo.plistにNSBluetoothAlwaysUsageDescription許可が必要です。これがないと、セントラルマネージャーは.unauthorized状態に移行し、スキャンは不可能になります。ユーザーはいつでも設定 > プライバシー > Bluetoothで許可を変更できます。
scanForPeripherals(withServices:options:)はスキャンを開始するための主要メソッドです。withServicesパラメータはフィルタリング用のサービスUUIDの配列を受け入れます。nilを渡すとすべてのデバイスが発見され、消費電力が大幅に増加します。アプリに必要なサービスUUIDで常にフィルタリングすることをお勧めします。スキャンオプションにはCBCentralManagerScanOptionAllowDuplicatesKey(同じデバイスに関する繰り返し通知)が含まれます。
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") // バッテリーサービス
centralManager.scanForPeripherals(
withServices: [serviceUUID],
options: [
CBCentralManagerScanOptionAllowDuplicatesKey: false
]
)
}
}
デバイスが発見されると、centralManager(_:didDiscover:advertisementData:rssi:)が呼び出されます。advertisementDataパラメータには、デバイス名(CBAdvertisementDataLocalNameKey)、サービスUUID(CBAdvertisementDataServiceUUIDsKey)、製造元データ(CBAdvertisementDataManufacturerDataKey)を含むアドバタイズメントパケットデータの完全な辞書が含まれます。RSSIは発見時に利用可能なシグナルレベル(dBm)です。
connect(_:options:)は、発見されたペリフェラルとのBLE接続を確立するメソッドです。connectを呼び出した後、iOSはデバイスへの接続を試みます。接続成功はcentralManager(_:didConnect:)で確認され、エラーはcentralManager(_:didFailToConnect:error:)で通知されます。接続オプションには、バックグラウンド通知用のCBConnectPeripheralOptionNotifyOnConnectionKey、CBConnectPeripheralOptionNotifyOnDisconnectionKey、CBConnectPeripheralOptionNotifyOnNotificationKeyが含まれます。
// BLEデバイスに接続
func connectToPeripheral(
_ peripheral: CBPeripheral
) {
centralManager.connect(peripheral, options: nil)
// ペリフェラルのデリゲートを設定
peripheral.delegate = self
}
// デリゲート: 接続成功
func centralManager(
_ central: CBCentralManager,
didConnect peripheral: CBPeripheral
) {
print("接続先: " +
"\(peripheral.name ?? "unknown")")
// サービス発見を開始
peripheral.discoverServices(nil)
}
// デリゲート: 接続エラー
func centralManager(
_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?
) {
print("Connection failed:
\(error?.localizedDescription ?? "")")
}
iOSの接続タイムアウトは30秒です。この時間内にデバイスが接続要求に応答しない場合、didFailToConnectが呼び出されます。タイムアウトは、デバイスまでの距離、干渉、デバイスが現在アドバタイズ中かどうかに影響されます。接続前に、デバイスが接続可能なアドバタイズモード(ADV_IND、ADV_NONCONN_INDではない)であることを確認してください。
接続後、ペリフェラルのサービス(discoverServices)と特性(discoverCharacteristics)を発見する必要があります。これはデータの読み取りまたは書き込み前の必須手順です。プロセスは非同期です。discoverServicesはperipheral(_:didDiscoverServices:)を介して結果を返し、discoverCharacteristicsはperipheral(_:didDiscoverCharacteristicsFor:error:)を介して結果を返します。
discoverServicesにはnilではなく関連するUUIDの配列を渡すことをお勧めします。フィルタリングにより発見が高速化され、電力が節約されます。サービスが見つからない場合、iOSは空の配列を報告します。特性を発見した後、値の読み取り(readValue)、通知への登録(setNotifyValue)、またはデータの書き込み(writeValue)が可能です。
重要な注意点:MTUは接続後に自動的にネゴシエーションされます。現在のMTUを取得するには、peripheral.maximumWriteValueLength(for: .withResponse)または.withoutResponseを使用します。iOSでは、BLE 5.0デバイスの最大MTUは512バイトです。MTUより大きいデータを転送する必要がある場合は、アプリケーションレベルでフラグメンテーションを実装してください。
iOSでのBLEデバイスのバックグラウンドスキャンには特別な設定が必要です。Core Bluetoothはバックグラウンド実行をサポートしていますが、重要な制限があります。バックグラウンドで動作するには、プロジェクトのCapabilitiesでBackground Modesのbluetooth-centralを有効にし、state restoration用にCBCentralManagerOptionRestoreIdentifierKeyオプションを指定してCBCentralManagerを初期化し、バックグラウンド移行時にセントラルマネージャーのイベントを処理する必要があります。
iOSのバックグラウンドBLE制限:UUIDフィルタリングなしのscanForPeripheralsはバックグラウンドで機能しません。アプリはスキャン用に具体的なサービスUUIDを指定する必要があります。iOSはBLEイベントの配信を無期限に遅延させる可能性があります。Core Bluetoothは、アプリがバックグラウンドにあっても、一致するデバイスが発見されると自動的にスキャンを再開します。バックグラウンドスキャンのタイムアウト:iOSは電力を節約するために10〜30分後にスキャンを停止する場合があります。
State Restorationは、アプリの再起動またはiOSの再起動後にBLE接続を復元できるCore Bluetoothのメカニズムです。使用するには、初期化時にCBCentralManagerOptionRestoreIdentifierKeyを指定し、デリゲートでcentralManager(_:willRestoreState:)を実装し、渡された辞書から接続されたペリフェラルのリストを復元します。State Restorationは、フィットネストラッカーや医療機器など、バックグラウンドで動作するBLEアプリにとって重要な機能です。
CBCentralManagerはいくつかのシナリオでエラーを生成します:接続失敗(didFailToConnect)、接続切断(didDisconnectPeripheral)、特性が読み取り/書き込み不可(didWriteValueエラー)。すべてのCore Bluetoothエラーは、CBErrorDomainドメインのErrorオブジェクトを介して返されます。最も一般的なコード:CBErrorConnectionTimeout(0x04)、CBErrorPeripheralDisconnected(0x07)、CBErrorOperationNotSupported(0x0A)。
接続復旧戦略:didDisconnectPeripheralを受信したら、エラーコードを確認します。エラーがCBErrorConnectionTimeoutまたはCBErrorPeripheralDisconnectedの場合、1〜5秒後に自動再接続をスケジュールします。エラーがCBErrorOperationNotSupportedの場合は、ログに記録して操作を再試行しないでください。重要な接続(医療機器)の場合は、最大60秒の間隔で指数バックオフを使用します。
// 自動再接続による切断処理
func centralManager(
_ central: CBCentralManager,
didDisconnectPeripheral peripheral: CBPeripheral,
error: Error?
) {
guard let error = error else {
return // 予想される切断
}
print("Disconnected: \(error.localizedDescription)")
// 自動再接続
if shouldAutoReconnect {
DispatchQueue.main.asyncAfter(
deadline: .now() + reconnectDelay
) {
central.connect(peripheral)
}
}
}
iOSで堅牢なBLEアプリを開発する際の注意点:Core Bluetoothは弱いシグナルでの全パケットの配信を保証しません。信頼性の高い転送には、writeType .withResponse(確認済み書き込み)を使用し、ペリフェラルからデータを受信するために通知(setNotifyValue)に登録してください。本番環境での接続問題診断のためにエラーログを保持してください。
よくある質問
centralManagerDidUpdateStateを介してマネージャーの状態を確認してください。Info.plistにNSBluetoothAlwaysUsageDescriptionの許可があること、デバイスでBluetoothが有効であること、ペリフェラルデバイスが正しいタイプ(接続可能なアドバタイズ、非接続可能ではない)でアドバタイズしていることを確認してください。
BLE 5.0対応デバイス(iPhone 8以降)では最大7つの同時接続が可能です。古いデバイスでは最大3〜5です。スキャンされるデバイスの数に制限はありませんが、アクティブな接続にはBluetoothコントローラーによって設定された厳格な制限があります。
UUIDフィルタリングを使用したスキャンをお勧めします。デバイスが見つかったらスキャンを停止してください。継続的なスキャンはバッテリーを消耗します:1時間の中断のないスキャンでiPhoneの充電の約10〜15%を消費します。タイマーと条件を使用してスキャンを停止してください。
CBCentralManagerは外部BLEデバイス(Centralロール)のスキャンと接続用です。CBPeripheralManagerはiOSデバイス自体がBLEペリフェラルとして動作(サービスをアドバタイズ)するためのものです。1つのインスタンスは1つのロールのみ可能です。
centralManager(_:didDisconnectPeripheral:error:)を実装します。エラーがnilでない場合、指数バックオフ(1秒→2秒→4秒→8秒→最大60秒)で自動再接続をスケジュールします。エラーがnilの場合、デバイスは正常に切断されました(例:ユーザーがデバイスのボタンを押した)。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。