[iBeacon] Mac を iBeacon 端末にする(Swift3編)
1 はじめに
iBeaconの発信(ペリフェラル側)は、Macでも作成可能です。この事については、既に、ここDevelopers.IOでも、紹介されておりますので、詳しくは、こちらをご参照下さい。
[iOS 7] [iBeacon] Mac を Beacon 端末にする
既に、語り尽くされた感のあるiBeaconの話ですが、今回これをSwift3で書いてみましたので紹介させて下さい。
なお、CBPeripheralManager が Yosemite (10.10) で動作しなかった問題については、改善されており、本記事で紹介するコードは、El Capitan(10.11) 及びmacOS Sierra(10.12) で問題なく動作させる事ができました。
[iOS][OS X] Yosemite で Beacon アプリを動作させる
CBPeripheralManager startAdvertising not working on OS X yosemite
2 検証環境
MacBook Air (13-inch, Mid 2013)
OS X El Capitan(10.11.6) 及び、macOS Sierra (10.12.2)
iPhone 6 (iOS 10.2)
Xcode 8.2.1 (8C1002)
3 基本的な手順
iBeaconの発信は、超簡単に言ってしまうと次の手順だけです。
- CBPeripheralManagerのインスタンス生成
- startAdvertising(_:)で発信開始
- stopAdvertising()で発信停止
そして、それぞれコードは、下記のようになります。
// インスタンスの生成 let manager = CBPeripheralManager(delegate: self, queue: nil)
let beaconData = ・・・アドバタイズメントデータの生成 // 発信開始 manager.startAdvertising(beaconData as! [String : Any]?)
// 発信停止 manager.stopAdvertising()
4 アドバタイズメントデータ
MacでiBeaconの作業をする場合に、少し面倒なのは、発信開始時に使用するstartAdvertising(_:)のパラメータに渡すアドバタイズメントデータの生成です。
iOSでは、CLBeaconRegionが利用可能なため、比較的簡単に生成できるのですが、OS X(macOS)では、これを自前で実装する必要があります。
//参考:iOSの場合の例 let uuid = UUID.init(uuidString: "myuuid") let beaconRegion = CLBeaconRegion.init(proximityUUID: uuid!, major: 1, minor: 1, identifier: "jp.classmethod.myregion") let beaconData = NSDictionary(dictionary: beaconRegion.peripheralData(withMeasuredPower: nil)) manager.startAdvertising(beaconData as? [String : Any] )
Mac用に自前でアドバタイズメントデータを生成するクラスは次のとおりです。
import CoreLocation final class BeaconData: NSObject { var advertisement: NSDictionary! init(proximityUUID: UUID?, major: UInt16?, minor: UInt16?, measuredPower: Int8?) { var buffer = [CUnsignedChar](repeating: 0, count: 21) (proximityUUID! as NSUUID).getBytes(&buffer) buffer[16] = CUnsignedChar(major! >> 8) buffer[17] = CUnsignedChar(major! & 255) buffer[18] = CUnsignedChar(minor! >> 8) buffer[19] = CUnsignedChar(minor! & 255) buffer[20] = CUnsignedChar(bitPattern: measuredPower!) let data = NSData(bytes: buffer, length: buffer.count) advertisement = NSDictionary(object: data, forKey: "kCBAdvDataAppleBeaconKey" as NSCopying) } }
そして、上記クラスは、下記のように利用可能です。
let uuid = UUID.init(uuidString: "myuuid") let beaconData = BeaconData(proximityUUID: uuid, major: 1, minor: 1, measuredPower: -60) manager.startAdvertising(beaconData.advertisement as! [String : Any]?)
5 CBPeripheralManagerDelegate
CBPeripheralManagerのインスタンスを生成する際に、delegateの指定がありますが、ここには、CBPeripheralManagerDelegateプロトコルを実装したクラスを設定します。
CBPeripheralManagerDelegateプロトコルでは、peripheralManagerDidUpdateState(_:)でBluetoothの状態を受け取ることができます。
サンプルでは、ここで、Bluetoothの電源がONで使用可能な事を確認し、操作ボタンを有効にしました。
class ViewController: NSViewController, CBPeripheralManagerDelegate { // ・・・省略 func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { if peripheral.state == CBPeripheralManagerState.poweredOn { // 使用可能なのでボタンを有効にする startButton.isEnabled = true stopButton.isEnabled = true } } // ・・・省略 }
6 最後に
iBeaconの発信(ペリフェラル側)の作成アドバタイズメントのデータの生成以外は、iOSの場合と同じです。そして、swiftで書くと非常にシンプルでした。
コードは下記に置いています。気になるところが有りましたら、ぜひ教えてやってください。
[GitHub] https://github.com/furuya02/iBeaconSender
7 参考資料
API Reference CBPeripheralManager
[iOS 7] [iBeacon] Mac を Beacon 端末にする