iBeaconsを触ってみた
iBeaconとは
iBeacon は iOS の 位置情報サービス を拡張する新しいテクノロジーです。iBeacon の設置場所に近づいたり離れたりすると、iOS デバイスから App に通知させることができます。位置のモニタリングのほか、App によって iBeacon (たとえば、Apple Store 直営店のディスプレイやレジカウンター) との距離を測定することもできます。iBeacon では、位置情報を明らかにするために緯度と経度ではなく、BLE (Bluetooth Low Energy) 信号を利用します。この信号を iOS デバイスが検出します。Bluetooth テクノロジーについて詳しくは、Bluetooth の公式 Web サイト を参照してください。
引用 : support.apple.com
iBeaconはiOS7より新たに追加されたBlutoothを使った位置情報サービスの新しいテクノロジーです。少し前から 興味はあったのですが、まだ触っていませんでした。 しかし、iOS7.1になって様々な改良(iOS7.1でのiBeaconが改善されまくった話)が加えられて、実用的に使えそうとの噂を聞きつけたのでちょっと触ってみようと思います。
目標
今回はまずはどんな物かを実際に触ってみるという所ですので、サービスなどは考えずにとりあえず動作させる所までをやってみたいと思います。
- beacon端末が買えなかったので MBAとiPhone5sの両方をiBeacon端末にしてみます
- 受信側はiOS7.1
- 受信したら通知メッセージを出す簡単なもの
予備知識
概要
- BLE4.0 (Bluetooth Low Energy) を利用した近距離無線通信
- CoreLocation.frameworkを使用
- 使えるのはiPhone4s以降、 iPadは第3世代以降(なのでiPad2は使えない模様)
用語
Advertise(アドバタイズ) : ある機器が別の機器に管理情報などを伝達する事
proximity UUID : 128bitのUUIDで表現される識別子(組織単位で使用される事を想定)
major : 16bit 同一 proximity UUIDを持つiBeaconの識別子として使用
minor : 16bit 同一 proximity UUIDとmajorを持つiBeaconの識別子として使用
リージョン(UUID)監視 : Beacon領域の出入をチェック
Ranging(レンジング) : エリア内のBeacon情報を取得(距離測定)
major,minorは省略可能だがこれらを使ってグルーピング、カテゴライズする事が出来る
iBeaconsで出来る事
- リージョン iBeaconの領域観測(範囲に入ったか出たか)
- Beaconより情報を取得(プッシュ通知)
- Ranging 距離観測
OS X を Beacon端末に
まずはOS XでiBeacon端末化します。本当は端末を買いたかったですが、それなりに値段もしますし(というか売り切れ。。)簡単に出来るようなのでやってみます。
とは言っても、OSXをiBeacon端末化する素晴らしい記事があったので、そちらを参考にOSXアプリを作るだけです。
Mac を Beacon にしたい!@dev.classmethod.jp
アプリを作ったら、proximity UUIDを固有の物にしないといけませんので、ターミナルでUUIDを生成してコードに埋め込みます。
% uuidgen
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
// UUIDを適当に作成(uuidgenコマンドで生成する)
NSUUID *proximityUUID = [[NSUUID alloc] initWithUUIDString:@"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"];
// アドバタイズ用のデータを作成
MBCBeaconAdvertisementData *beaconData
= [[MBCBeaconAdvertisementData alloc] initWithProximityUUID:proximityUUID
major:1
minor:1
measuredPower:-58];
// アドバタイズ開始
[peripheral startAdvertising:beaconData.beaconAdvertisement];
iOSをBeacon端末に
次にiOSをiBeacon端末化してみます。githubにソースをおいておくので、よかったら参考にして下さい。 atsu666/iOS-iBeaconSenderApp
iOSアプリでは、テスト用に使えるようにUUIDなどを固定せずにアプリ側で自由に設定できるようにしてみました。
CBPeripheralManagerDelegateインターフェイスを実装していきます。RequireなメソッドはperipheralManagerDidUpdateState:になります。
CBPeripheralManagerDelegate Protocol Reference
//----------------------------------------------------
// ViewController.h
//----------------------------------------------------
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreBluetooth/CoreBluetooth.h>
@interface ViewController : UIViewController <CBPeripheralManagerDelegate>
@end
//----------------------------------------------------
// ViewController.m
//----------------------------------------------------
- (void)viewDidLoad
{
[super viewDidLoad];
// CBPeripheralManagerを作成
self.manager = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];
// アドバタイズを開始
[self beginAdvertising];
}
- (void)beginAdvertising
{
NSUUID *uuid = [[NSUUID alloc]initWithUUIDString:self.uuidField.text];
uint16_t major = (uint16_t)[self.majorField.text integerValue];
uint16_t manor = (uint16_t)[self.minorField.text integerValue];
// uuid, major, minor, identifierを指定して BeconRegionを作成
CLBeaconRegion *beacon = [[CLBeaconRegion alloc]initWithProximityUUID:uuid
major:major
minor:manor
identifier:self.identifierField.text];
NSDictionary *beaconData = [beacon peripheralDataWithMeasuredPower:nil];
[self.manager stopAdvertising];
[self.manager startAdvertising:beaconData];
}
//----------------------------------------------------------------
// Required Method ペリフェラルデバイスの状態を監視
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
switch (peripheral.state) {
case CBPeripheralManagerStatePoweredOn:
self.statusLabel.text = @"CBPeripheralManagerStatePoweredOn";
break;
case CBPeripheralManagerStatePoweredOff:
self.statusLabel.text = @"CBPeripheralManagerStatePoweredOff";
break;
case CBPeripheralManagerStateResetting:
self.statusLabel.text = @"CBPeripheralManagerStateResetting";
break;
case CBPeripheralManagerStateUnauthorized:
self.statusLabel.text = @"CBPeripheralManagerStateUnauthorized";
break;
case CBPeripheralManagerStateUnknown:
self.statusLabel.text = @"CBPeripheralManagerStateUnknown";
break;
case CBPeripheralManagerStateUnsupported:
self.statusLabel.text = @"CBPeripheralManagerStateUnsupported";
break;
}
}
受信側アプリをiOSで作る
iBeacon端末が出来たので受信側のiOSアプリを作ります。機能的にはiOSの通知機能を使う事と取得情報を出力する 簡単なものになります。
こちらもgithubに公開しときます。 atsu666/iOS-BeaconReceiverApp
CLLocationManagerDelegateインターフェイスを実装していきます。 重要なデリゲートメソッドはlocationManagerDidPauseLocationUpdates:になります。 ここで、ビーコンを監視して処理を書いていきます。
CLLocationManagerDelegate Protocol Reference
//----------------------------------------------------
// ViewController.h
//----------------------------------------------------
#import <UIKit/UIKit.h>
@import CoreLocation;
@interface ViewController : UIViewController <CLLocationManagerDelegate>
@end
//----------------------------------------------------
// ViewController.m
//----------------------------------------------------
- (void)viewDidLoad
{
[super viewDidLoad];
if ( [CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]] ) {
// Managerを作成
self.manager = [CLLocationManager new];
self.manager.delegate = self; // デリゲートを設定
// Beacon情報を設定(ここで設定した情報のビーコンを監視します)
self.proximityUUID = [[NSUUID alloc]initWithUUIDString:UUID];
self.identifier = IDENTIFIER;
self.major = (uint16_t)[MAJOR integerValue];
self.minor = (uint16_t)[MINOR integerValue];
// Beacon情報を元にリージョンを作成
self.region = [[CLBeaconRegion alloc]initWithProximityUUID:self.proximityUUID
major:self.major
minor:self.minor
identifier:self.identifier];
self.region.notifyOnEntry = YES; // 領域に入った事を監視
self.region.notifyOnExit = YES; // 領域を出た事を監視
self.region.notifyEntryStateOnDisplay = NO; // デバイスのディスプレイがオンのとき、ビーコン通知が送信されないように設定
[self.manager startMonitoringForRegion:self.region]; // 領域監視を開始
[self.manager startRangingBeaconsInRegion:self.region]; // iBeaconとの距離測定を開始
}
}
#pragma mark CLLocationManagerDelegate
//-------------------------------------
// 領域に入った時
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region
{
[self sendNotification:@"ようこそ!"];
}
//-------------------------------------
// 領域から出た時
- (void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region
{
[self sendNotification:@"さようなら!"];
}
//--------------------------------------------------------------
// iBeaconを監視
- (void)locationManager:(CLLocationManager *)manager
didRangeBeacons:(NSArray *)beacons
inRegion:(CLBeaconRegion *)region
{
// init
NSString *uuid = @"unknown";
CLProximity proximity = CLProximityUnknown;
CLLocationAccuracy accuracy = 0.0;
NSInteger rssi = 0;
NSNumber *major = @0;
NSNumber *minor = @0;
// near beacon
CLBeacon *beacon = beacons.firstObject;
uuid = beacon.proximityUUID.UUIDString;
proximity = beacon.proximity;
accuracy = beacon.accuracy;
rssi = beacon.rssi;
major = beacon.major;
minor = beacon.minor;
// update view
self.uuidLabel.text = beacon.proximityUUID.UUIDString;
self.majorLabel.text = [NSString stringWithFormat:@"%@", major];
self.minorLabel.text = [NSString stringWithFormat:@"%@", minor];
self.accuracyLabel.text = [NSString stringWithFormat:@"%f", accuracy];
self.rssiLabel.text = [NSString stringWithFormat:@"%ld", (long)rssi];
switch (proximity) {
case CLProximityUnknown:
self.proximityLabel.text = @"CLProximityUnknown";
break;
case CLProximityImmediate:
self.proximityLabel.text = @"CLProximityImmediate";
break;
case CLProximityNear:
self.proximityLabel.text = @"CLProximityNear";
break;
case CLProximityFar:
self.proximityLabel.text = @"CLProximityFar";
break;
default:
break;
}
if ( proximity == CLProximityUnknown ) {
self.beconStateLabel.text = @"UNKNOWN";
} else {
self.beconStateLabel.text = @"ENTER";
}
//-------------------------------------------------------------
// iBeaconの電波強度を調べて、近距離に来た場合
if ( proximity == CLProximityImmediate && rssi > -40 ) {
self.beconStateLabel.text = @"TOUCH";
}
}
実際に動かしてみて
結構、精度高く動いてくれている印象でした。 領域に入った時には瞬時に反応して、電波強度(RSSI)や精度(Accuracy)から距離も大体とれるので、 タッチした時など出来そうです。 ただ、やはり領域から出たときの反応は30-40秒ほどタイムラグがあって通知がされました。
また、アプリを完全に落とした状態でもiOS7.1だとちゃんと通知がされましたので、 サービスとして問題なく使えそうです。
という事でiBeaconを触ってみました。 なんかiBeaconを利用したアプリ作りたいですね。
参考にした記事
- [iOS 7] 新たな領域観測サービス iBeacon を使ってみる | Developers.IO
- [iOS 7] [iBeacon] Mac を Beacon 端末にする
- CBPeripheralManagerDelegate Protocol Reference
- CLLocationManagerDelegate Protocol Reference