Core Bluetooth:iOSにおけるBLEのアーキテクチャと開発

著者: IT Sectr 公開日: 2026-07-16 読了時間: 10 分

Core Bluetoothは、iOS、iPadOS、macOSでBluetooth Low Energyと対話するためのAppleのフレームワークです。このフレームワークは、両方のBLEロールで動作するための完全なAPIセットを提供します:中央デバイス(CBCentralManager)は周辺機器のスキャンと接続用、周辺デバイス(CBPeripheralManager)はBLEサーバーのエミュレーション用です。Core Bluetoothは、物理無線からアプリケーションレベルのGATTプロファイルまで、BLEプロトコルスタックを抽象化します。Apple Developer、2026によると、Core BluetoothはBLE開発のための唯一の公式Apple APIであり、BLE 4.0–5.4、extended advertising、2M PHY、LE Audioをサポートしています。

重要なポイント

  • Core Bluetooth — iOS、iPadOS、macOS向けBLE開発のためのAppleのシステムフレームワーク
  • CBCentralManager — 中央デバイス側からBLE周辺機器をスキャンして接続するためのクラス
  • CBPeripheralManager — サービスと特性を公開するBLEサーバーを作成するためのクラス
  • GATTプロファイル — データ交換のためのサービス、特性、ディスクリプタの階層モデル
  • バックグラウンドモード — Core Bluetoothはシステムデリゲートとstate restorationを通じてバックグラウンドでのBLE通信をサポート

Core Bluetoothとは:アーキテクチャとコンポーネント

Core Bluetoothは、BLEスタックをBluetooth SIG仕様で定義された2つの論理ロールに分割します。中央デバイスのロール(Central)はCBCentralManagerクラスで表されます — スキャンを開始し、接続を確立し、接続されたCBPeripheralのリストを管理します。周辺デバイスのロール(Peripheral)はCBPeripheralManagerで表されます — サービスと特性を公開し、中央からの要求に応答し、通知を送信します。1つのiOSセッションは異なるBLE無線で両方のロールを同時に操作できますが、通常のアプリケーションは1つのロールを使用します。

Core Bluetoothアーキテクチャには5つの主要な抽象化が含まれています。CBCentralManagerはデバイスのBluetoothアダプターの状態を管理します:poweredOn(動作準備完了)、poweredOff(Bluetooth無効)、unauthorized(許可なし)、unsupported(BLE利用不可)。CBPeripheralは、UUID、名前、RSSI、GATT階層を持つリモートBLEデバイスを表します。CBService — 特性の論理グループ。CBCharacteristic — 読み取り/書き込み/通知のためのデータポイント。CBPeripheralManagerは周辺機器をエミュレートするためのローカルGATTサーバーを作成します。

クラスロール主要メソッド
CBCentralManager中央デバイスscanForPeripherals, connect, cancelPeripheralConnection, retrievePeripherals
CBPeripheralリモート周辺discoverServices, discoverCharacteristics, readValue, writeValue, setNotifyValue
CBPeripheralManagerローカル周辺addService, removeService, startAdvertising, respondToRequest, updateValue
CBCentralリモート中央maximumUpdateValueLength, identifier, ancsAuthorized

CBCentralManagerの状態はすべてのBLE操作を制御します。アプリが起動すると、centralManagerDidUpdateStateが現在のBluetooth状態で呼び出されます。状態が.poweredOnでない場合、システムはBLE呼び出しを無視します。開発者はスキャンと接続の前に状態を確認する必要があります。.poweredOffから.poweredOnへの遷移は、iOS設定でBluetoothが有効になったときに発生します — デリゲートが再度呼び出され、アプリはスキャンを再開できます。

CBCentralManager:BLEデバイスのスキャンと接続

CBCentralManagerは、中央デバイス側でのすべてのBLE操作のエントリポイントです。初期化はデリゲート(CBCentralManagerDelegate)とDispatchQueueを受け取ります — Appleはシンプルさのためにメインキュー、パフォーマンスのためにシリアルキューを推奨しています。初期化後、フレームワークは自動的にBluetooth状態をチェックし、centralManagerDidUpdateState:を呼び出します — 処理する最初の必須デリゲートです。

スキャンはscanForPeripheralsWithServices:options:メソッドで開始されます。最初のパラメータはフィルタリング用のCBUUIDサービスの配列です:目的のサービスのUUIDがわかっている場合、それを渡すと消費電力と検索時間が削減されます。nilの場合は、範囲内のすべてのBLEデバイスが検出されます。オプションには、.allowDuplicatesKey(同じデバイスの重複検出)と.solicitedServiceUUIDsKey(中央で公開されるサービス用)が含まれます。

swift
import CoreBluetooth

class BLECentral: NSObject {

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

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

    // BLEスキャンを開始
    func startScan() {
        guard centralManager.state == .poweredOn else {
            print("Bluetoothが利用できません")
            return
        }
        // すべてのデバイスをスキャン(nil = フィルターなし)
        centralManager.scanForPeripherals(withServices: nil,
                                            options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
    }

    // スキャンを停止
    func stopScan() {
        centralManager.stopScan()
    }

    // 選択したデバイスに接続
    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)")
    }
}

BLECentralクラスは、BLEデバイスのスキャンと接続の完全なサイクルを示しています。centralManagerDidUpdateStateはBluetoothが有効なときにスキャンを開始します。didDiscoverPeripheralは、identifierによる重複排除を行い、見つかったデバイスをdiscoveredPeripherals配列に収集します。接続(didConnect)後、すぐにサービス検出が開始されます — これはGATT操作の前の必須ステップです。

CBPeripheralManager:iOSでのBLEサーバーの作成

CBPeripheralManagerは、iOSでBLE周辺デバイスをエミュレートするためのクラスです。周辺ロールのアプリは、サービスと特性を公開し、中央デバイスからの読み取り/書き込み要求を受け入れ、通知を送信できます。CBPeripheralManagerはiPhoneでエミュレートされるBLEアクセサリに使用されます:リモコン、キーボード、トラッカー、IoTゲートウェイなど。

CBPeripheralManagerのライフサイクルは、初期化とCBPeripheralManagerDelegateから始まります。peripheralManagerDidUpdateState:を介してpoweredOnの確認を受けた後、サービスが公開され(addService:)、アドバタイジングが開始されます(startAdvertising:)。アドバタイジングデータCBAdvertisementDataには、ローカル名(CBAdvertisementDataLocalNameKey)、サービスUUID(CBAdvertisementDataServiceUUIDsKey)、送信電力レベル(CBAdvertisementDataTxPowerLevelKey)が含まれます。最大アドバタイジングパケットサイズは、BLE 4.0で31バイト、extended advertising BLE 5.0+で251バイトです。

swift
// CBPeripheralManagerを介したiOS上のBLE周辺機器
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)
    }

    // 特性を持つサービスを公開
    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)
    }

    // アドバタイジングを開始
    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()
        }
    }

    // 読み取り要求を処理
    func peripheralManager(_ peripheral: CBPeripheralManager,
                        didReceiveRead request: CBATTRequest) {
        let data = "CurrentValue".data(using: .utf8)!
        request.value = data
        peripheralManager.respond(to: request, withResult: .success)
    }

    // 書き込み要求を処理
    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)
    }
}

BLEPeripheralクラスは、読み取り、書き込み、通知をサポートする単一の特性を持つBLEサーバーを作成します。初期化後、peripheralManagerDidUpdateStateはaddService:を介してサービスを公開し、次にstartAdvertising:を介してアドバタイジングを開始します。didReceiveReadとdidReceiveWriteハンドラは、中央デバイスからの着信GATT要求に応答します。通知の送信にはupdateValue:forCharacteristic:onSubscribedCentrals:メソッドが使用されます。

GATT操作:読み取り、書き込み、通知

GATT操作(Generic Attribute Profile)は、Core Bluetoothにおけるデータ交換の基盤です。サービスと特性の検出後、中央デバイスは3種類の操作を実行できます:特性値の読み取り、値の書き込み、通知/ indicationの購読。各操作は非同期で、対応するCBPeripheralDelegateコールバックを介して結果を返します。

読み取り:readValueForCharacteristic:を呼び出して実行します。値はperipheral:didUpdateValueForCharacteristic:error:で到着します。重要:読み取りはデバイスから現在の値を返し、キャッシュされた値ではありません。デバイスが読み取りをサポートしていない場合(.readプロパティ)、呼び出しはエラーを返します。大きな値(MTUより大きい)の場合、BLEは自動的にGATTレベルでデータを分割して再構成します。

書き込み:writeValue:forCharacteristic:type:を呼び出して実行します。BLEは2つの書き込みモデルをサポートしています:withResponse(信頼性高、確認応答あり)とwithoutResponse(高速、確認応答なし)。CBCharacteristic.propertiesプロパティが利用可能な書き込みタイプを定義します。単一の書き込みパケットの最大サイズはMTUによって制限されます:BLE 4.0で23バイト(20バイトのペイロード+3バイトのヘッダー)、拡張MTU(MTU 251)のBLE 5.0で最大247バイト。

通知:setNotifyValue:true forCharacteristic:を呼び出して有効化します。購読後、周辺機器は特性値が変更されるたびに、peripheral:didUpdateValueForCharacteristic:を介して自動的に更新を送信します。通知を無効にするには、setNotifyValue:false forCharacteristic:を呼び出します。Core Bluetoothは周辺機器のCCCDディスクリプタを自動的に管理します。

操作メソッドデリゲート転送タイプ
読み取りreadValueForCharacteristic:didUpdateValueForCharacteristicポーリング(要求-応答)
withResponse書き込みwriteValue:forCharacteristic:type:withResponsedidWriteValueForCharacteristic確認応答あり
withoutResponse書き込みwriteValue:forCharacteristic:type:withoutResponseデリゲートなし確認応答なし
通知setNotifyValue:true forCharacteristic:didUpdateNotificationStateForCharacteristic + didUpdateValueForCharacteristic周辺からのプッシュ

Core BluetoothのバックグラウンドモードとState Restoration

バックグラウンドモードでは、Core Bluetoothを使用するBLEアプリがバックグラウンドにいる間もスキャンを継続し、接続を維持し、通知を受信できます。有効にするには、Xcodeで“Uses Bluetooth LE accessories”機能を有効にし(Info.plist → Required background modes → App communicates using Core Bluetooth)、UIBackgroundModesに“bluetooth-central”キーを追加します。周辺ロールの場合は—“bluetooth-peripheral”。

State Restorationは、iOSによるアプリ再起動後にBLE接続の状態を復元するためのCore Bluetoothのメカニズムです。バックグラウンドモードがアクティブで、CBCentralManagerまたはCBPeripheralManagerの初期化でrestoreIdentifierが指定されている場合、iOSはアプリ終了時にBLEスタックの状態を保存し、次回起動時に復元します。デリゲートcentralManager:willRestoreState:は、保存されたCBPeripheralと保留中の接続を含む辞書を受け取ります。

swift
// State Restorationを使用したCore Bluetoothの設定
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 {

    // 再起動後に状態を復元
    func centralManager(_ central: CBCentralManager,
                        willRestoreState dict: [String : Any]) {
        if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey]
            as? [CBPeripheral] {
            for peripheral in peripherals {
                peripheral.delegate = self
                // GATT検出を復元
                peripheral.discoverServices(nil)
            }
        }
    }

    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            print("復元後にBluetooth準備完了")
        }
    }
}

BLECentralWithRestoration構成では、CBCentralManagerOptionRestoreIdentifierKeyキーが状態保存を有効にします。アプリがiOSによって終了された場合(メモリ不足など)、次回起動時にcentralManager:willRestoreState:は以前に接続されたCBPeripheralのリストを受け取ります。アプリはデリゲートを復元し、サービスの再検出を実行します — ユーザーは接続の中断に気づきません。State Restorationがない場合、アプリ終了時にすべてのBLEセッションが失われます。

SwiftでのBLEアプリ例:中央と周辺

完全な例として、SwiftのBLEアプリが中央デバイスと周辺デバイスの両方を1つのプロジェクトに統合しています。アプリは2つのモードで動作できます:BLEデバイスを検出して接続する(中央)、またはBLEアクセサリをエミュレートする(周辺)。以下は、起動時にロールを選択する共通のBLEマネージャーを使用したアーキテクチャです。

swift
// 中央と周辺のためのユニバーサルBLEマネージャー
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)
        }
    }

    // 中央デバイス:スキャン
    func scanForDevices() {
        centralManager?.scanForPeripherals(withServices: nil, options: nil)
    }

    // 周辺デバイス:アドバタイジング
    func advertiseService() {
        let data: [String: Any] = [
            CBAdvertisementDataServiceUUIDsKey: [advertisedServiceUUID]
        ]
        peripheralManager?.startAdvertising(data)
    }
}

// 起動時の使用
let isCentral = UserDefaults.standard.bool(forKey: "isCentral")
let manager = BLEManager(role: isCentral ? .central : .peripheral)

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

BLEManagerは初期化時にロールを選択し、対応するManager(CBCentralManagerまたはCBPeripheralManager)を作成します。ロールフラグはUserDefaultsに保存するか、構成サーバーを介して渡すことができます。このアプローチにより、BLEアプリはユースケースに適応できます:販売時点ではiPhoneが中央として支払い端末をスキャンし、IoTゲートウェイでは周辺としてセンサーからデータを収集します。

よくある質問

Core Bluetoothとは何ですか?

Core Bluetoothは、iOS、iPadOS、macOS向けBLE開発のためのAppleのフレームワークです。中央(CBCentralManager)と周辺(CBPeripheralManager)の両方のデバイスにAPIを提供します。BLE 4.0–5.4、extended advertising、2M PHY、LE Audioをサポートしています。Core BluetoothはBLE通信のための唯一の公式Apple APIであり、Bluetooth Low Energyを扱うすべてのiOSアプリに必要です。

CBCentralManagerとCBPeripheralManagerの違いは何ですか?

CBCentralManagerは中央デバイスロールで動作するためのクラスです:BLE周辺機器をスキャンし、接続を確立し、特性を読み書きします。CBPeripheralManagerは周辺ロールで動作するためのクラスです:サービスを公開し、読み取り/書き込み要求に応答し、通知を送信します。1台のiPhoneは異なるマネージャーインスタンスを通じて両方のロールを同時に実行できます。

バックグラウンド動作のためにCore Bluetoothを設定するには?

バックグラウンドBLE動作には、Xcodeで“Uses Bluetooth LE accessories”機能を有効にし、UIBackgroundModesに“bluetooth-central”キーを追加します。周辺ロールの場合は—“bluetooth-peripheral”。State Restorationのためにマネージャーを初期化する際にrestoreIdentifierを指定します。これらの設定がないと、バックグラウンドのアプリはBLEイベントを受信できず、接続が失われます。

Core Bluetoothがデバイスを見つけられないのはなぜですか?

一般的な理由:CBCentralManager.state != .poweredOn(Bluetoothが無効または未承認)、デリゲートが設定されていない、デバイスが範囲外またはアドバタイジングパケットを送信していない。Info.plistのNSBluetoothAlwaysUsageDescription権限、centralManagerDidUpdateStateのBluetoothステータスを確認し、scanForPeripheralsが.poweredOnの場合にのみ呼び出されるようにしてください。

複数のCBPeripheralを同時に接続できますか?

はい、Core Bluetoothは複数のBLEデバイスへの同時接続をサポートしています。各CBPeripheralは独自のデリゲートを通じて独立して管理されます。iOSはシステムレベルで同時BLE接続数を制限します(通常iPhoneで5~7)。1:Nのシナリオ(10個のトラッカーがあるフィットネスセンターなど)では、周辺機器をキューに入れて循環的にサービスする必要があります。

まとめ

  • Core Bluetooth — CBCentralManagerとCBPeripheralManagerクラスを使用したBLE開発のためのAppleのシステムフレームワーク
  • CBCentralManagerはリモートBLEデバイスとのスキャン、接続、GATT操作を管理
  • CBPeripheralManagerはサービス公開と着信要求処理でBLE周辺機器をエミュレート
  • GATTプロファイルには読み取り、書き込み、通知操作を含むサービス、特性、ディスクリプタが含まれる
  • バックグラウンドモードにはState RestorationのためのUIBackgroundModesとrestoreIdentifierが必要
  • MTUはBLEパケットサイズを制限:BLE 4.0で23バイト、拡張MTUのBLE 5.0+で最大251バイト
  • Swift async/awaitはCheckedContinuationを介してデリゲートを使用した非同期BLEコードを簡素化

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください