Help us understand the problem. What is going on with this article?

【Core Bluetooth】ペリフェラル別に通信ログをはいてデバッグしやすくする

More than 3 years have passed since last update.

Core Bluetooth を使う開発をしていると、「あれ、さっきは普通にWriteリクエスト飛んだのに、今回は飛ばなかったな・・・」みたいなトラブルがたびたびあります。

で、原因を調査すべく CBCentralManagerDelegate や CBPeripheralDelegate プロトコルの各種デリゲートメソッドに NSLog (Swift なら println)を仕込んだりするわけですが、それぞれサービスやらキャラクタリスティックやらがたくさんあって、さらにペリフェラルが複数台ある場合、ログが大量に流れてどのペリフェラルがどこでコケてるのか追いかけるのが大変 ということがあります。

そんなわけで、ペリフェラル別にログをはく「PeripheralLogger」というクラスをつくりました。

出力例

このロガーを使用すると、サンドボックス配下の Caches/Logs に "{ペリフェラルのUUID}.log" というファイルがペリフェラル毎に生成されて、こんな感じで出力されます。

21:51:58 centralManager:didDiscoverPeripheral:advertisementData:RSSI: name:shuPhone6plus state:Disconnected
advertisementData:{
    kCBAdvDataHashedServiceUUIDs =     (
        "EB115BE0-A9E8-4E11-99E1-53E510FBA9E6"
    );
    kCBAdvDataIsConnectable = 1;
}, RSSI:-49

21:51:58 centralManager:didConnectPeripheral: name:shuPhone6plus state:Connected 

21:51:59 peripheral:didDiscoverServices: name:shuPhone6plus state:Connected
error:(null), services:(
    "<CBService: 0x174079380, isPrimary = YES, UUID = EB115BE0-A9E8-4E11-99E1-53E510FBA9E6>"
)

21:51:59 peripheral:didDiscoverCharacteristicsForService:error: name:shuPhone6plus state:Connected
error:(null), service:EB115BE0-A9E8-4E11-99E1-53E510FBA9E6, characteristics:(
    "<CBCharacteristic: 0x1700917b0, UUID = 28983C42-F64B-4DA2-8D93-C948C7B23247, properties = 0x2, value = <466f7244 6576656c 6f706d65 6e742054 73757473 756d69>, notifying = NO>",
    "<CBCharacteristic: 0x170091760, UUID = 28983C43-F64B-4DA2-8D93-C948C7B23247, properties = 0x2, value = (null), notifying = NO>",
    "<CBCharacteristic: 0x17008c6c0, UUID = 28983C44-F64B-4DA2-8D93-C948C7B23247, properties = 0x2, value = (null), notifying = NO>"
)

21:51:59 peripheral:didUpdateValueForCharacteristic:error: name:shuPhone6plus state:Connected
error:(null), characteristic:<CBCharacteristic: 0x1700917b0, UUID = 28983C42-F64B-4DA2-8D93-C948C7B23247, properties = 0x2, value = <466f7244 6576656c 6f706d65 6e742054 73757473 756d69>, notifying = NO>

21:51:59 centralManager:didDisconnectPeripheral:error: name:shuPhone6plus state:Disconnected
error:(null)

「ペリフェラルの発見〜接続〜サービス発見〜キャラクタリスティック発見〜Write成功〜切断」の一連の流れが他のログに邪魔されることなく見れて、いい感じではないでしょうか。上の例ではエラー出てませんが、どっかでエラー出ても一目瞭然かと思います。

一番簡単な使い方

下記のようにペリフェラルオブジェクトを PeripheralLog マクロに渡してやると、

objc
- (void)  centralManager:(CBCentralManager *)central
    didConnectPeripheral:(CBPeripheral *)peripheral
{
    // ↓↓↓↓これ↓↓↓↓
    PeripheralLog(peripheral);

    // (その他の処理)
}

サンドボックス配下の Caches/Logs に "{ペリフェラルのUUID}.log" というファイルが生成されて、次のように、日時、メソッド名、ペリフェラルの namestate(の値を文字列に直したもの)を出力 してくれます。

21:51:58 centralManager:didConnectPeripheral: name:shuPhone6plus state:Connected

フォーマット指定

当然エラーとか他の値とか諸々見たいときもあるので、NSLog とかと同様にフォーマット指定しての出力もできます。PeripheralLogF マクロを使用します。

objc
- (void)   centralManager:(CBCentralManager *)central
    didDiscoverPeripheral:(CBPeripheral *)peripheral
        advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
    // ↓↓↓↓これ↓↓↓↓
    PeripheralLogF(peripheral, @"advertisementData:%@, RSSI:%@", advertisementData, RSSI);

    // (その他の処理)
}
objc
- (void)     peripheral:(CBPeripheral *)peripheral
    didDiscoverServices:(NSError *)error
{
    // ↓↓↓↓これ↓↓↓↓
    PeripheralLogF(peripheral, @"error:%@, services:%@", error, peripheral.services);

    // (その他の処理)
}

それぞれこんな感じで出力されます。

21:51:58 centralManager:didDiscoverPeripheral:advertisementData:RSSI: name:shuPhone6plus state:Disconnected
advertisementData:{
    kCBAdvDataHashedServiceUUIDs =     (
        "EB115BE0-A9E8-4E11-99E1-53E510FBA9E6"
    );
    kCBAdvDataIsConnectable = 1;
}, RSSI:-49
21:51:59 peripheral:didDiscoverServices: name:shuPhone6plus state:Connected
error:(null), services:(
    "<CBService: 0x174079380, isPrimary = YES, UUID = EB115BE0-A9E8-4E11-99E1-53E510FBA9E6>"
)

その他

  • もちろん、debugビルドのときだけ(DEBUGプリプロセッサマクロが定義されているときだけ)動作するようにしてあります。(シングルトンの初回の初期化処理もDBUGプリプロセッサマクロが定義されてないと通りません)
  • 「PeripheralLog」という名前が長いので「PerLog」みたいに省略するか迷いましたが、補完で出てくるし、省略すると「何から始まるんだっけ?」ってなるのであえてこういう名前にしました。

ダウンロード&インストール

https://github.com/shu223/PeripheralLogger

今後の展望

実は今日(ついさっき)つくってみたばかりで、ほんとにデバッグに役立つのかまだ自分でもわかってません。これから実運用しつつ改善していきます。Cacheフォルダにあるファイル見るのが面倒なので、disconnect時にまとめてコンソールにはく、という挙動にした方がいいのかなーとか、まだ迷い中です。あと、Swiftで書きなおした方がいいかなとか。

おわりに

この記事と直接は関係ないのですが、konashi開発者の松村礼央さんと共著で、iOS x BLE な技術書籍を執筆させていただきました。

iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 1,106

iOS x BLE というニッチな内容で480ページ! つながらないとかサービス見つからないとかキャラクタリスティックの値がおかしい等々々々、Core Bluetooth のハマりどころとその対策方法 もまとめてあります。3/26発売です。どうぞよろしくお願いします!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away