やっぱりLGBluetoothが好き…///

LGBluetoothはiOSでBLEを扱うときに初心者にはとてもとっつきやすいライブラリです。CoreBluetooth.frameworkの冗長な部分を色々マイルドにしてくれます。

入門記事としてはLGBluetooth自体の[README](https://github.com/l0gg3r/LGBluetooth)と @shu223 さんが書いた[入門記事](http://d.hatena.ne.jp/shu223/20140510/1399859747)を見るといいです。

こんな感じで使います。

```objc
#import "LGBluetooth.h"

@property (nonatomic) LGPeripheral *p;

...

// ペリフェラルが一つでも見つかればスキャンをやめてすぐにcompletionブロックの中身を実行する
[[LGCentralManager sharedInstance] setPeripheralsCountToStop:1];

// スキャン開始
[[LGCentralManager sharedInstance]
 scanForPeripheralsByInterval:5 // 最長で5秒間スキャンを実行する
 services:@[[CBUUID UUIDWithString:@"00000000-0000-0000-0000-000000000000"]] // ここでCBUUIDの配列を渡すとServiceのUUIDを指定してスキャンできる
 options:nil
 completion:^(NSArray *peripherals) {
     if (peripherals.count > 0) {
         // ※必ずpropertyに含める
         self.p = (LGPeripheral *)peripherals[0];

         // 値の書き込み
         int8_t dataToWrite[2] = {0x00, 0x01};

         // Utilsを使えばServiceやCharacteristicを探索する記述を書かなくてもいい
         [LGUtils writeData:[NSData dataWithBytes:&dataToWrite length:sizeof(dataToWrite)]
                charactUUID:@"11111111-1111-1111-1111-111111111111"
                serviceUUID:@"22222222-2222-2222-2222-222222222222"
                 peripheral:self.p completion:^(NSError *error) {
                     NSLog(@"Error : %@", error);
                     [self.p disconnectWithCompletion:^(NSError *error) {
                     }];
                 }];
     } else {
         NSLog(@"Not Found!!");
     }
 }];

```

これだけです！

スキャンして、見つけて、接続して、サービスとキャラクタリスティックを探索して、値を書き込んで、最後に切断するまでの記述がこれだけで済みます！

ただやっぱり使い続けていくとまあ色々手を加えたくなったり、新しく書くものについては自分でCoreBluetooth.frameworkを軽くラップしたものを使っています。

でも、でもでも！入門時の導入の容易さやプロトをつくるときの初速を考えると今でも使い続けたいいいライブラリだと思っています。

今回はこのLGBluetoothを改造しながら使っていったときにやったことをまとめたいと思います。

## CBCentralManagerStatePoweredOffの検知

```diff:LGBluetoothAkerun/LGCentralManager.m
@@ -280,6 +266,14 @@
             LGLogError(@"%@", message);
         });
     }
+    if (central.state == CBCentralManagerStatePoweredOff) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            DDLogDebug(@"*** did power off");
+            [[NSNotificationCenter defaultCenter] postNotificationName:kLGCMStatePoweredOff
+                                                                object:self
+                                                              userInfo:@{@"error" : message}];
+        });
+    }
 }

 - (void)centralManager:(CBCentralManager *)central
```

これを追加しておくことで、

```objc
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(centralManagerPowerOff:)
                                             name:kLGCMStatePoweredOff
                                           object:nil];
```

```objc
- (void)centralManagerPowerOff:(NSNotification *)notification {    
    // 処理
}
```

などとして、ユーザーがBLEをOFFにしたときなども気づくことができます。

## 保存と復元

BLEは毎回一々スキャンしていると接続まで毎回待たされることになるので、OS側でキャッシュしてスキャンせずにそこから見つかったペリフェラルに接続できるようにします。

```diff:LGBluetoothAkerun/LGCentralManager.m
@@ -310,6 +302,23 @@
     });
 }

+
+- (void)centralManager:(CBCentralManager *)central
+      willRestoreState:(NSDictionary<NSString *, id> *)dict
+{
+}
+
 /*----------------------------------------------------*/
 #pragma mark - LifeCycle -
 /*----------------------------------------------------*/
@@ -332,7 +341,7 @@ static LGCentralManager *sharedInstance = nil;
        self = [super init];
        if (self) {
         _centralQueue = dispatch_queue_create("com.LGBluetooth.LGCentralQueue", DISPATCH_QUEUE_SERIAL);
-        _manager      = [[CBCentralManager alloc] initWithDelegate:self queue:self.centralQueue];
+        _manager      = [[CBCentralManager alloc] initWithDelegate:self queue:self.centralQueue options:@{CBCentralManagerOptionRestoreIdentifierKey: @"jp.co.hogehoge.LGCCentralRestore"}];
         _cbCentralManagerState = _manager.state;
         _scannedPeripherals = [NSMutableArray new];
         _peripheralsCountToStop = NSUIntegerMax;
```

willRestoreStateは必須なので追加。あとはCBCentralManagerを生成するときに、CBCentralManagerOptionRestoreIdentifierKeyに適当な文字列をしていしておきます。

あとは一度スキャンしたときに、そのペリフェラルのUUID(iOSが生成したもの)を覚えておき、次回はそれをキーにしてまずは取得を試みます。

実はLGBluetoothには初めからキャッシュされたペリフェラルをキャッシュから引っ張る（リトリーブ）関数が用意されているので、それを使います。

```objc
NSArray *cachedPeripheral = [[LGCentralManager sharedInstance] retrievePeripheralsWithIdentifiers:@[cachedUUID]];
```

cachedPeripheralは、ようはスキャンされたあとに取得できるペリフェラルとほぼ同じなので、あとは接続すればいいだけです。

プロトをつくっているときとかは、高速化は割りと後回しになりますが、最初からオレオレLGBluetoothにしておけば最初から高速に接続できるので、ユーザー体験がどうなるかも検証できていいですね。

## まとめ

LGBluetoothを使えば死ぬほど簡単にBLEを使ったアプリケーションが書けます。
あとは実際に問題があったときにソースを読んでCoreBluetoothの使い方を知るなんて流れがいいのではないでしょうか？（自分がそうでした）

Enjoy BLE!