iBeacon について


以前、勉強会でたどたどしく発表させていただいたiBeaconについて書きます。
今更ながらiBeaconですが、まだ今後普及する可能性があるのではと思って書きます。。

#iBeaconとは?

* Beaconと呼ばれる発信機から出ているBluetooth Low Energy（BLE）の信号を受信する機能。
* 近くのお店のクーポンや商品情報を通知にすることなどに利用されている。



# iBeacon利用時に必要な条件
* Beacon機器（aplix、estimote、Gimbalなど）
	* 1個３００円〜３０００円くらい
	* iPhoneやMacでもOK
* iOS7以降
* Bluetoothが搭載されたiPhone/iPad/iPodなど
* 位置情報「常に利用」の許可

#実装

##Beacon監視開始

```swift:Beacon監視開始
        locationManager = CLLocationManager()
        locationManager.delegate = self
        
        //iBeaconは位置情報「常に利用」の許可が必要なのでrequestAlwaysAuthorization()が必要。info.plistにもNSLocationAlwaysUsageDescriptionを追加しておく。
        if locationManager.respondsToSelector("requestAlwaysAuthorization") {
            locationManager.requestAlwaysAuthorization()
        }

   		 //ビーコン領域を生成
        let uuidString = "EBEFD083-70A2-47C8-9837-E7B5634DF524"
        let beaconIdentifier = "sample_iBeacon"
        let beaconUUID = NSUUID(UUIDString: uuidString)!
        let beaconRegion = CLBeaconRegion(proximityUUID: beaconUUID,
            identifier: beaconIdentifier)
        //let beaconRegion = CLBeaconRegion(proximityUUID: beaconUUID, major: 3, minor: 1, identifier: beaconIdentifier)
        
        //beacon領域に入ったときのdelegateからの通知がいらないときはfalse。defaultはtrue
        //beaconRegion.notifyOnEntry = false
        
        
        //beacon領域に入ったときのdelegateからの通知がいらないときはfalse。defaultはtrue
        //beaconRegion.notifyOnExit = false
        
        //iPhoneのロック解除ボタンが押されて、ロック中画面が表示されたときにBeaconの状態（内側にいるか外側にいるか）を確認するかどうか。defaultはfalse
        beaconRegion.notifyEntryStateOnDisplay = true

        //Beaconの領域IN/OUTの監視開始
        //これで、locationManager:didEnterRegion や 
        //locationManager:didExitRegionが通知される(アプリが起動していない時でも)
        //「uuidString/major/minorの組み合わせ」をbeaconRegionに指定する。
        //20個のbeaconRegionオブジェクトを監視可能
        locationManager.startMonitoringForRegion(beaconRegion)
```
* locationManager.startMonitoringForRegion()を行うと、以下の「Beacon領域IN/OUTを検知(delegate)」が **アプリを起動していなくても**、コールバックされる。


##Beacon領域IN/OUTを検知(delegate)
* これらは、アプリを起動していなくてもコールバックされる。その際、AppDelegateのdidFinishLaunchingWithOptionsがコールされた後に以下のdelegateメソッドがコールバックされる。

```swift:Beacon領域IN/OUTを検知(delegate)
    /**
    * beaconの領域に入った
    */
    func locationManager(manager: CLLocationManager,
        didEnterRegion region: CLRegion) {
            manager.startRangingBeaconsInRegion(region as! CLBeaconRegion)
            manager.startUpdatingLocation()
            //結構感度が良い
    }
    
    /**
     * beaconの領域から出た
     */
    func locationManager(manager: CLLocationManager,
        didExitRegion region: CLRegion) {
            //didEnterRegionに比べて感度が悪い
    }
    
    /**
     * beaconRegion.notifyEntryStateOnDisplay = true時に、iPhoneのロック解除ボタンが押されて、ロック中画面が表示された時、コールされる。
     */
    func locationManager(manager: CLLocationManager,
        didDetermineState state: CLRegionState,
        forRegion region: CLRegion) {
            //現在、対象Beaconの内側/外側/どちらかかわらないかが、stateで取得できる
    }
```    

##Beacon領域IN/OUTのエラー検知(delegate)

```swift:Beacon領域IN/OUTのエラー検知(delegate)
    
    /**
    * beacon監視でエラー。
    */
    func locationManager(manager: CLLocationManager, monitoringDidFailForRegion region: CLRegion?, withError error: NSError)      {
        //ex) 監視するbeaconが無効、beaconを２１種類以上登録した場合など
	}
```


##Beaconデータの受信開始

```swift:Beaconデータの受信開始
    
        locationManager.delegate = self
        //Beaconデータの受信開始。Beaconデータ（CLBeacon）には
               //uuid/major/minor/CLProximity(すぐ近く/近い/遠い)/rssi(信号強度)が入っている
        locationManager.startRangingBeaconsInRegion(beaconRegion)
```
* locationManager.startRangingBeaconsInRegion()を行った後、以下の「Beaconデータ受信を検知(delegate)」は **アプリを起動しているときだけ**、コールバックされる。


##Beaconデータ受信を検知(delegate)
* これらはアプリを起動しているときだけコールバックされる。

```swift:Beaconデータ受信を検知(delegate)
    /**
    * Beaconデータ受信処理
    */
    func locationManager(manager: CLLocationManager,
        didRangeBeacons beacons: [CLBeacon],
        inRegion region: CLBeaconRegion) {
            //Beaconデータ受信時は何度もコールされる。CLBeaconにはuuid/major/minor/CLProximity(すぐ近く/近い/遠い)/rssi(信号強度) が入っている
            //Beacon範囲に入っている時はbeaconsリストにCLBeaconオブジェクトが入っているが、
            //Beacon範囲から出てもしばらくbeaconsリストが空でコールされる。
    }

```


##Beaconデータ受信のエラー検知(delegate)

```swift:Beaconデータ受信のエラー検知(delegate)

    func locationManager(manager: CLLocationManager,
        rangingBeaconsDidFailForRegion region: CLBeaconRegion,
        withError error: NSError) {
        //beaconデータ受信でエラー。
        //ex) 監視するbeaconが無効など
    }
```


# よいと思ったところ
* iPhoneのロック解除ボタンを押した時にもBeacon検知タイミングがあるところ。これはローカル通知したいときに、ユーザーの目につきそうだと思った。
* Beacon検知している時、ロック画面左下にアプリのアイコンが表示される。

![ibeacon1.png](https://qiita-image-store.s3.amazonaws.com/0/37373/0c7accc4-6fa4-96f2-2eb0-51ac87adfebc.png "ibeacon1.png")
スマートフォンECラボ様(http://smartphone-ec.net/)

* 省電力
	* [GPSを利用した領域観測](http://qiita.com/HIkaruSato/items/5b1e7564c3b2d529f4c5)に比べてiPhoneの電池消耗が少ない
	* Beacon機器も乾電池２本でほとんどのものが１年以上は持つ。


# 悪いと思ったところ

* iPhoneの電源ONにした直後１〜５分くらいBeaconを検知できない時間がある。
* Beacon領域OUTの検知が遅いので、それを早めに検知したい時は工夫が必要そう。
	* Beaconデータ受信検知で受信データが空になった時と組み合わるなど

# まとめ

* 実装はかなり簡単(Bluetooth通信がframeworkにラップされている)。
* アプリを起動していなくても、起動できるトリガーが多い（Beacon IN/OUT検知、ロック画面表示時）。
* 日本でも徐々にiBeaconサービスが出てきているので今後普及するかも？