その後のその後

iOSエンジニア 堤 修一のブログ github.com/shu223

殺しても死なないアプリ 〜Core Bluetooth の「状態の保存と復元」機能〜 #potatotips

昨日、第17回 potatotips という iOS / Android の開発Tips共有会(勉強会)で標題の発表をしてきました。


概要

Core Bluetooth のバックグラウンド実行モードについて。内訳としては、

  • 対応方法
  • バックグラウンドでできること
  • バックグラウンドにおける制約
  • 「状態の保存と復元」機能について

という感じです。


発表時間はきっちり5分しかなかったので結局デモはできず、なんとなく様子がわかる(かもしれない)スクショを貼り付けてあります。

Core Bluetooth の「状態の保存と復元」

この Core Bluetooth の「状態の保存と復元」(State Preservation and Restoration)機能、アプリが停止しても(プロセスが殺されても)システムがバックグラウンドでの処理を引き継いでくれて、必要に応じてアプリをバックグラウンドで起こしてくれるという超画期的なもの。BLEをバックグラウンドで利用する場合には必ずおさえておきたい機能です。


対応方法としては、セントラルマネージャ、ペリフェラルマネージャ初期化時にオプションを渡すだけ。

let options: Dictionary = [
    CBCentralManagerOptionRestoreIdentifierKey: "myKey"
]

self.centralManager = CBCentralManager(
    delegate: self,
    queue: nil,
    options: options)
let options: Dictionary = [
    CBPeripheralManagerOptionRestoreIdentifierKey: "myKey",
]

self.peripheralManager = CBPeripheralManager(
    delegate: self,
    queue: nil,
    options: options)


基本的にはこれだけなのですが、システムがバックグラウンドでアプリケーションを起こしてくれる際に、そのアプリのすべてが復元されるわけではないので、必要に応じてプロパティの中身等を `centralManager:willRestoreState:` 及び `peripheralManager:willRestoreState:` で復元してやる必要があります。そのあたりの詳細は、拙著もご参考にしていただけると幸いです。(バックグラウンドでの制約についても詳しく書いています。)


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


【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF


紹介記事:
http://d.hatena.ne.jp/shu223/20150323/1427067357

Apple Watch 対応とバックグラウンド処理

これはスライドには書いてない話ですが、たとえば、(スライド内にあるスマートロックのケースのように)直接的にバックグラウンドで外部デバイスとBLE通信する必要があるアプリ「ではない」としても、下記記事に書いたように、WatchKit アプリでもBLE機能を利用したいとなると、(現状だと)親アプリがバックグラウンドで動けるようにしておく必要があるかと思います。

WatchKit App をトリガとして Parent App にBLE関連処理を行わせる際のポイントとなるのは、BLEはスキャン、接続、サービス/キャラクタリスティック探索、Read/Write 等々、基本的には非同期的にレスポンスが返ってくる処理ばかりである、というところです。


`openParentApplication:reply:` は同期処理だし、非同期処理完了後にバックグラウンドの親アプリ側から WatchKit App を起こしたりデータを渡したりするAPIはありません。プッシュ通知やローカル通知を使う方法はありますが、プッシュ通知はタイムラグもありますし、ローカル通知は上で行った検証の通りウォッチ側で受け取れないケースが多すぎます。

そんなわけで、BLE利用アプリで WatchKit app も用意する場合にも、この「状態の保存と復元」はかなり大事かと。

ユーザーが明示的にアプリを停止させた場合

「殺しても死なない」と書きましたが、何度か試したところ、ホームボタン2回押しの状態から強制終了させた場合は、復元してくれないようです。(iOS 8.3 で確認。Appleのドキュメント類でそう明記してあるものは見つからず。。)


とはいってもシステムによるアプリの停止を意図的に起こすことは難しいので(メモリをあふれさせるとかしないといけない)、僕が復元機能を確認するときは、以下の手順でやっています。

  • Xcode からアプリを Run する
  • アプリを操作して、ペリフェラルと接続するなり、復元を試したい状態まで持っていく
  • Xcode の Run を止める(アプリのプロセスも消える)
  • ホームボタン2回押しでアプリを消す(プロセスはもう死んでるので、これは履歴を消してるだけ)
  • 復元されるか試す(ペリフェラル側でキャラクタリスティックを更新してNotification飛ばすとか)

おわりに

自分にとってこの話は Core Bluetooth 周りのとっておきの話ではあったのですが、なにぶん5分しかなく「BLE(Bluetooth Low Energy)とは?」という説明をする時間もなかったため、普段さわってない方々にはイマイチ良さが伝わらない発表になってしまったかもしれません。まぁでもどこかで話したいと思ってたことなので機会があってよかったです。


いろいろな方のTipsを聞けて刺激になりましたし、久々にお会いする方も多く、とても楽しかったです。主催の Wantedly さん、発表者・参加者のみなさまどうもありがとうございました!