iBeacon(2) - Bluetoothと位置情報設定を監視しよう
さて、では実装に入りましょう。以下のコードはこちらgithub: ESBeaconにアップしてありますので参照しながら読んでいただけるとよいかと思います。
iBeacon Singletonオブジェクトの用意
まずは、バックグランドでの動作も想定して、Viewから独立したiBeacon管理用オブジェクトをSingletonとして用意します。
こちらの記事のテンプレートを活用して、
Objective-C – Singleton(シングルトン)クラスの実装 -
ESBeaconというクラスをSingletonとして実装します。ESBeaconではBluetoothや位置情報のアップデートも受け取りますので、CBPeripheralManagerDelegate
およびCLLocationManagerDelegate
のdelegate宣言もしておきます。
ESBeacon.h
@interface ESBeacon : NSObject <CBPeripheralManagerDelegate, CLLocationManagerDelegate>
+ (ESBeacon *)sharedManager;
...
@end
ESBeacon.m
@implementation ESBeacon
+ (ESBeacon *)sharedManager
{
static ESBeacon *sharedSingleton;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedSingleton = [[ESBeacon alloc] initSharedInstance];
});
return sharedSingleton;
}
- (id)initSharedInstance {
self = [super init];
if (self) {
// Initialization of ESBeacon singleton.
...
}
return self;
}
- (id)init {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
これにより、[ESBeacon sharedManager]を呼ぶことでESBeaconのsingletonオブジェクトを取得することができます。githubのコードでは、ESBeaconViewController.m内で、
- (void)viewDidLoad
{
[super viewDidLoad];
self.beacon = [ESBeacon sharedManager];
...
}
このように呼び出しています。
Bluetoothのデバイス状況監視 - CBPeripheralManager
次にBluetoothのデバイス状況の監視設定をします。Bluetooth関連機能を使う場合は、@import CoreBluetooth
として機能をインポートします。
iBeaconの機能のみにアクセスする場合、CoreBluetoothをまったく使用せず、CoreLocationのみで実装することも可能ですが、Bluetoothがオフになっている場合、iBeaconへのアクセスをしてエラーが帰ってくるまで状況が把握できないので、Bluetoothのデバイス状況も監視し、必要な場合はユーザーへ設定の確認をうながすなどしたほうがよいでしょう。
Bluetoothの設定情報はCBPeripheralManager
のdelegateである、CBPeripheralManagerDelegate
で通知されますので、ESBeaconでCBPeripheralManagerをallocしてdelegateをselfにセットします。
ESBeacon.m
@interface ESBeacon ()
@property (nonatomic) CBPeripheralManager *peripheralManager;
@end
@implementation ESBeacon
- (id)initSharedInstance {
self = [super init];
if (self) {
// Initialization of ESBeacon singleton.
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
}
}
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
NSLog(@"peripheralManagerDidUpdateState: %@", [self peripheralStateString:peripheral.state]);
}
@end
[self peripheralStateString]ではCBPeripheralManagerStateに対応した文字列を返しています。これでBluetoothのデバイス状況監視が完了です。
位置情報設定の監視 - CLLocationManager
位置情報設定の監視は、CLLocationManager
のCLLocationManagerDelegate
から通知されます。設定が変更されると、didUpdateAuthorizationStatus
が呼ばれます。CBPeripheralManagerと同様、allocしてdelegateをselfにセットします。
ESBeacon.m
@interface ESBeacon ()
@property (nonatomic) CBPeripheralManager *peripheralManager;
@property (nonatomic) CLLocationManager *locationManager;
@end
@implementation ESBeacon
- (id)initSharedInstance {
self = [super init];
if (self) {
// Initialization of ESBeacon singleton.
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
}
}
@end
delegateのmethodを用意します。
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
NSLog(@"locationManager didChangeAuthorizationStatus %@", [self locationAuthorizationStatusString:status]);
}
これで位置情報設定情報のアップデートが受信できるようになりました。
githubのコードでは、アップデートがあった時にUIViewControllerに通知をして現在のデバイスの状態を画面に表示するようにしています。
アプリインストール直後で、まだ位置情報サービスのリクエスト一度もしていない状態だと、[CLLocationManager authorizationStatus]はkCLAuthorizationStatusNotDeterminedを返します。その通りなのですが、ちょっと不思議な感じがしますね。
次回はリージョン監視とレンジングを行います。