0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【iOS】iBeacon の Region として iPhone を利用する

Last updated at Posted at 2021-01-26

環境

  • Xcode 12.3
  • iPhone 6 Plus
  • iOS 12.6

目的

  • iBeacon を用いた勤怠管理システムを構築するための実験として現在利用していない試験機 (iOS 12.6)の iPhone を iBeacon の Region として動作させたい
  • いずれは raspberry pi に置き換える予定なので最低限動けばOK

ポイント

Info.plist の設定

  • iOS 13 以降では Privacy - Bluetooth Always Usage Description の設定が必要
  • 今回は iOS 12.6 の端末で動けば良いので実は不要だが一応設定

スクリーンショット 2021-01-26 16.06.01.png

Region の作成

  • Region: Central 側が出入りを確認可能な「地域」
  • UUID(地域を一意に定めるもの)、major・minor(ビーコン識別用の値)、identifier(内部管理用のIDで信号には含まれない)が存在
  • iOS 13前後で仕様が異なるため今回は条件分けを行った
PeripheralManager.swift
    // Region を作成する
    private func createBeaconRegion() -> CLBeaconRegion {
        
        guard let uuid = UUID(uuidString: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") else { fatalError() }
        
        let identifier = "xxx.xxxx.xxxxx.xxxxx"
        
        if #available(iOS 13.0, *) {
            
            return CLBeaconRegion(uuid: uuid, identifier: identifier)
        }
        else {
            
            return CLBeaconRegion(proximityUUID: uuid, identifier: identifier)
        }
    }

CBPeripheralManagerDelegate

  • CBPeripheralManager インスタンスを通じて通信を行うが、その際 Delegate を実装しておく必要がある
  • func peripheralManagerDidUpdateState(_:)CBPeripheralManager インスタンス の状態が変化した際に呼ばれる
    • CBPeripheralManager インスタンスが生成されたタイミングでも呼ばれるため初期化処理には注意が必要
    • 今回は単純に BLE ON になったらアドバタイズ開始、それ以外ではアドバタイズ停止するように
  • CBPeripheralManagerDelegate を適用するクラスは NSObjectProtocol に準拠しておく必要があるため注意
PeripheralManager.swift
extension PeripheralManager: CBPeripheralManagerDelegate {
    
    // Bluetooth の電源ON/OFF または 接続状態が切り替わった場合に呼び出されるメソッド
    // CBPeripheralManager のインスタンスが生成された時点で一度呼び出される
    func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
        
        switch peripheral.state {
        case .poweredOn: self.startAdvertising()
        default: self.stopAdvertising()
        }
    }
}

その他

  • PeripheralManager クラスをシングルトンとして保持
    • 単一の Region としての役割のみを期待
    • (ないとは思うが)拡張する際にはどの画面からでも同一のマネージャクラスにアクセスできるように
  • startAdvertising() stopAdvertising() を外部から参照可能に
    • (ないとは思うが)拡張する際に利便のよいように
  • setupManager() を公開
    • CBPeripheralManager インスタンスが生成されるとその時点で状態監視が始まる
    • PeripheralManager インスタンスと同時に CBPeripheralManager インスタンスを生成すると処理の順序が交錯し分かりづらい

実装全体

PeripheralManager.swift
import CoreLocation
import CoreBluetooth
import Foundation


// MARK: - PeripheralManager

final class PeripheralManager: NSObject {
    
    static let shared = PeripheralManager()
    
    func setupManager() {
        
        if self.manager == nil {
            
            let region = self.createBeaconRegion()
            
            self.beaconPeripheralData = region.peripheralData(withMeasuredPower: nil)
            self.manager = CBPeripheralManager(delegate: self, queue: nil)
        }
    }
    
    // アドバタイズを開始する
    func startAdvertising() {
        
        if let manager = self.manager,
           let data = self.beaconPeripheralData as? [String : Any] {
            
            manager.startAdvertising(data)
        }
    }
    
    // アドバタイズを停止する
    func stopAdvertising() {
        
        if let manager = self.manager {
            
            manager.stopAdvertising()
        }
    }
    
    
    // MARK: - Private
    
    private var beaconPeripheralData: NSDictionary?
    
    private var manager: CBPeripheralManager?
    
    // Region を作成する
    private func createBeaconRegion() -> CLBeaconRegion {
        
        guard let uuid = UUID(uuidString: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") else { fatalError() }
        
        let identifier = "xxx.xxxx.xxxxx.xxxxx"
        
        if #available(iOS 13.0, *) {
            
            return CLBeaconRegion(uuid: uuid, identifier: identifier)
        }
        else {
            
            return CLBeaconRegion(proximityUUID: uuid, identifier: identifier)
        }
    }
}


// MARK: - CBPeripheralManagerDelegate

extension PeripheralManager: CBPeripheralManagerDelegate {
    
    // Bluetooth の電源ON/OFF または 接続状態が切り替わった場合に呼び出されるメソッド
    // CBPeripheralManager のインスタンスが生成された時点で一度呼び出される
    func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
        
        switch peripheral.state {
        case .poweredOn: self.startAdvertising()
        default: self.stopAdvertising()
        }
    }
}

AppDelegate.swift

import UIKit


// MARK: - AppDelegate

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    
    // MARK: - UIApplicationDelegate

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // PeripheralManager を設定する
        PeripheralManager.shared.setupManager()
        return true
    }
}

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?