はじめに

 ここ最近 iBeacon が世間で大きな注目を集めているようです。    前回の記事では、iBeacon の基本的な機能や、その実装方法について紹介しました。今回は、実際に iBeacon を活用したアプリを作成する時に必要になる応用的な内容について紹介したいと思います。また、iOS 7.1 から対応した新たな機能についても紹介したいと思います。

 今回の記事が、iBeacon アプリをより良いものにする手助けになれば幸いです。  


すでに Beacon の範囲内にいる場合

  前回の記事では、すでに Beacon の範囲内にいた場合、didEnterRegion コールバックメソッドが呼ばれないと説明していました。しかし、すでに範囲内にあるか否かの判定は可能です。iBeacon の実装方法に関しては前回の記事を参考にしていただければ問題なく行えると思いますので今回は省略させて頂きます。

 すでに Beacon の範囲内にいた場合、それを検出するには以下のコールバックメソッドを実装します。

-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{

    switch (state) {
        case CLRegionStateInside:
            if([region isMemberOfClass:[CLBeaconRegion class]] && [CLLocationManager isRangingAvailable]){
                NSLog(@"Enter %@",region.identifier);
                //Beacon の範囲内に入った時に行う処理を記述する
            }
            break;

        case CLRegionStateOutside:
        case CLRegionStateUnknown:
        default:
            break;
    }
}

 この、locationManager:didDetermineState:forRegion というコールバックメソッドは、まずリージョン監視開始直後に必ず呼ばれます。その後は、iBeacon の状態が変化する度に呼ばれることになります。この時に渡される CLRegionState 型の変数により、現在の Beacon の状態を知ることが出来ます。この State の状態は次の表のようになります。

State 名 説明
CLRegionStateInside 領域の内側
CLRegionStateOutside 領域の外側
CLRegionStateUnknown 領域のどこにいるか不明

 このコールバックメソッドを使用することで、すでに Beacon の領域内であっても、領域の中に入ったという情報を取得することが出来ます。もちろん、このメソッドを実装したからといって didEnterRegion や didExitRegion が呼ばれなくなるというわけではないので、そちらもきちんと実装しておきましょう。


NSURLSession と組み合わせると、バックグラウンド通信が出来る

 ビーコンの検出をトリガとして、通信処理を行うことを考えます。その時に、アプリがバックグラウンドにいるまま、iBeacon の情報を取得し、サーバへ通信を行うということが出来ると、ユーザがわざわざアプリをフォアグラウンド表示する必要がなくなるのではないでしょうか。

 まずは、準備として、plist に設定を付け加えます。
plist に バックグラウンドモードを指定するための項目があります。そこで location というものを指定しておくと、バックグラウンドにいながら、iBeacon の情報を取得することが出来ます。

info.plist に以下の設定を追記しましょう。

<key>UIBackgroundModes</key>
<array>
    <string>location</string>
</array>

Xcode で編集する場合は、以下の画像のように設定します。

plist 画面

 UIBackgroundModes の value は Array になっていますので、他にもモード(fetch 等)を指定していた時は、そこに今回使用する location を追加しましょう。

 ここまでの設定を行うことで、バックグラウンドにいながらiBeacon の情報を取得することが出来るようになりました。後は通信をそのままバックグラウンドで行うことが出来るようになれば、今回の要件を達成することができます。

 バックグラウンドで通信を行うためには、iOS 7.0 から追加された、NSURLSession というクラスを使用します。この NSURLSession 自体は、単なる通信処理のキューでしかありません。なのでこのクラスを用いて、通信を行うには NSURLSession にタスクを追加する必要があります。
追加することの出来るタスクは 3 種類有るのですが、そのうちバックグラウンド通信を行うことのできるタスクは NSURLSessionDownloadTask だけになるので注意しましょう。実装の方法に関しては、ギャップロでもその記事を掲載していますのでそちらを参考にしてください。

 バックグラウンドで通信を行うことが出来るようになれば、iBeacon がかなり広い用途に使用することができます。
入店検知に限らず、お店の前を通りがかった時などに、自動で端末にそのお店の色々な情報を流すことが出来るということです。これは、商品の販売促進につながるなど、とても画期的な方法になりえるのではないでしょうか。


iOS 7.1 ではアプリがバックグラウンドに残っていない状態でも iBeacon の信号を受信出来る

 iOS 7.0 からバックグラウンド処理が実装できるようになり、アプリの自由度が増したように思えましたが、一つ問題が残っています。それは、アプリがバックグラウンドからも消えて、完全に終了してしまうと、その後の処理は一切行えないというものです。

 しかし、iOS 7.1 からはその常識を覆し、なんとバックグラウンドから完全に消え、動作をしていないアプリであっても、ビーコンを検出することが出来るようになったのです。

 アプリをバックグラウンドタスク一覧から消し、完全に終了した状態で、iBeacon の信号を iOS 端末が受け取ると、バックグラウンド状態でアプリが起動します。その際、AppDelegate の application:didFinishLaunchingWithOptions というデリゲートメソッドの launchOptions にどの機能を元にアプリが起動されたのかという情報が渡されます。取得の方法が以下になります。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //省略

    if([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]!=nil)
    {
        //10 秒後に通知を送るための設定
        UILocalNotification *notification = [[UILocalNotification alloc] init];
        notification.fireDate = [[NSDate date] dateByAddingTimeInterval:10]; 
        notification.timeZone = [NSTimeZone systemTimeZone];
        notification.alertBody = @"Notification_location";
        notification.alertAction = @"Open";

        // 通知を登録する
        [[UIApplication sharedApplication] scheduleLocalNotification:notification];
    }

    //省略   
}

 iBeacon の情報を検知したことでアプリがバックグラウンド起動した時には、UIApplicationLaunchOptionsLocationKey というキーで情報が渡されます。アプリを完全に終了すると、iBeacon の監視は一度終了してしまいます。そのため、この情報があることがわかったタイミングで、もう一度 startMonitoringForRegion を呼び出します。こうすることで、iBeacon の情報を再度取得することが可能になります。

 バックグラウンド状態でアプリが起動すると言いましたが、実際にバックグラウンドタスク一覧にこのアプリが現れるということは無いようです。そのため、もしアプリを起動し直して欲しい場合には、今回のように通知を行い、それを経由してユーザにアプリを立ち上げてもらうなどの工夫を行う必要があります。


おわりに

 今回の記事はいかがだったでしょうか。
iBeacon は調べれば調べるほど、iOS のキラーコンテンツとなり得る可能性を持っていますね!
今後も、iBeacon に関する情報を入手次第、特集したいと思います!

 それではまた次回の記事をお楽しみに。