その後のその後

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

Eddystone と iOS - その1: iBeacon と比較したメリット・デメリット

2015年7月にGoogleから発表されたビーコン規格、Eddystone。「Eddystoneとは?」という概要については既に多く出ている他の解説記事にお任せして、iOS アプリ開発者から見た、Eddystone を採用するメリット・デメリット や、仕様をパッと見ただけではわからなかった実装のポイント 等について書きたいと思います。



本記事ではまず「iOS アプリにおいて iBeacon ではなく Eddystone を採用するメリット・デメリット」について。


(Eddystoneの概要については次の記事がおすすめです)

「クロスプラットフォーム」「オープン」はどう嬉しいのか?

iBeacon との違いとしてまず挙げられるのが、

  • 「クロスプラットフォーム」(Android・iOS両サポート)
  • 「オープン」(Apache v2.0ライセンス、規格やサンプルコードも公開)

という点です。


ただ、これらについて、下記のような疑問を持った開発者の方は多いのではないのでしょうか。。

  • iBeacon 形式のビーコンモジュールも Android アプリから検出できたんじゃ・・・?」(結局BLEなので)
  • 「iBeaconの規格は一般公開はされてないものの、アドバタイズメントパケットのフォーマット以前から知られていたんじゃ・・・」

というあたりです。


で、個人的には「クロスプラットフォーム」という点については、iBeaconと比較して特筆すべきアドバンテージは感じられていません *1


「オープン」という点については、実際にさわってみて、メリット・デメリットの両面があると感じました。以下でそれについて説明したいと思います。

メリット: カスタマイズ性

とあるiOSアプリで「iBeaconのレンジングを使い、それに紐付けられたコンテンツのリストを近い順に並び替える」ということをやっていました。


これで困ったのが、Core Location の `locationManager:didRangeBeacons:inRegion:` が呼ばれる間隔が、1秒固定であること。


つまり、1秒より小さい間隔でコンテンツを並び替えることができません。屋内でiBeaconを使う場合、ビーコン間は 2、3メートルぐらいしか離れてないことも少なくないので、更新が1秒間隔だと、ビーコンAの近くからビーコンBの近くに移動した場合にちょっと間が空いてからビーコンBがトップに来る、みたいな感じになります。ユーザーからすると「もっさり」に感じられるわけです。


ただインターバルを変えるプロパティ等も用意されていないのでどうしようもありません。ビーコンモジュール側のアドバタイズインターバルは100msecぐらいまで細かくできるというのに・・・


で、じゃあ iBeacon モジュールのレンジングを Core Bluetooth で実装するか、と考えるわけですが、iBeaconのアドバタイズメントパケットを発見はできるものの、 `centralManager:didDiscoverPeripheral peripheral:advertisementData:RSSI:` で 肝心の Manufacturer Data を返してくれない、という壁にぶち当たります。

func centralManagerDidUpdateState(central: CBCentralManager) {
    NSLog("manufacturer data:%@", advertisementData[CBAdvertisementDataManufacturerDataKey])
}

(実行結果)

manufacturer data:(null)


同じビーコンモジュールのアドバタイズメントパケットを Bluetooth Explorer で見てみるとちゃんと Manufacturer Data が入っているので、間違いなくApple様が意図的にiOSに課した制約のようです。


この Manufacturer Data の中に Proximity UUID, Major, Minor という iBeacon の iBeacon たる情報が入っている ので、これにより Core Location の iBeacon 関連実装を Core Bluetooth 使って自前でやる、ということは実質不可能である、といえます。(というわけで提唱されたのが AltBeacon


で、ここで Eddystone の「オープン」という点が生きてきます。公開されている仕様に則って好きなように実装することができます。冒頭のケースでは、最小100msec間隔でレンジングできるように実装しました。

デメリット: 自前実装の大変さ・怪しさ

好きなように自前実装できる、というメリットとは裏腹に、自前実装しないといけない、というのはデメリットでもあります。


Eddystone を検出する、ということ自体は Core Bluetooth に慣れていれば一瞬でできますし、そのアドバタイズメントパケットをパースするコードは Googleのサンプル や、こちらの実装 が参考になるのですが、困ったのは、RSSI / TxPower からの距離推定の実装です。計算式はググれば見つかるものの、細かい最適化のところで(専門家じゃないので)あまり自信がありません。


そしてやっているうちに、

  • RSSIはガンガンいろんな要因でぶれるので細かい差は信用できない、そう考えるとAppleのProximityの3段階ぐらいが妥当
  • 推定距離のブレを減らすために移動平均しよう
  • その際のどれぐらいブレがあるのかも評価しよう(Core Location の `accuracy`)

といった感じで、結局 Core Location の実装に近づいていく というジレンマもありました。


この辺り、iOS向けEddystoneサポート実装の決定版みたいなOSSが出てくることを期待します。


ちなみに Google による iOS 実装はあくまでサンプルという感じで、あんまり綺麗な実装とは思えなかったし、Eddystone-URLをサポートしてない、という状況です。(対応して Pull Request 送った ものの、それに対するレスポンスも遅い。。)

フレームタイプ Eddystone-URL の利点

3つあるフレームタイプのひとつ、Eddystone-URL では URL を直接アドバタイズメントパケットに含めることができるため、

これによってユーザーはGoogle Chromeが備わってさえいれば、iBeaconのようにわざわざ店舗毎に専用アプリをインストールせずともEddystoneからの情報を取得できるようになります。(beaconlabo.com - このウェブサイトは販売用です! - 活用 ビーコン アプリ ティング マーケ システム 位置情報 開始 リソースおよび情報

という点も Eddystone のわかりやすい iBeacon との違いとしてよく挙げられます。


が、逆に言えば、専用アプリのダウンロードを前提としているサービス・プロダクトにとってはアドバンテージにならない、ともいえます。


とくに、(個人的な話で恐縮ですが、)iOS専業エンジニアである自分はそもそも専用アプリの開発プロジェクトにしか呼ばれないので、自分にはずっと関係ないかなと。。


それと、iBeacon では、監視領域内に入りつつもアプリがインストールされていない場合にはストアへのリンクがロック画面に表示される、という機能もあります。URLの代わりにはなっていないですが。

フレームタイプ Eddystone-TLM の利点

このフレームタイプのパケットからは以下のようなメンテナンス用情報を取得することができます。

  • バッテリー電圧(mV/bit)
  • ビーコンの温度
  • アドバタイズ回数(前回起動時からの総数)
  • 起動時間(前回起動時から)

公式仕様


これらはiBeaconでは取得できないデータなので、何か非常におもしろそうではあります。


・・・が、具体的な活かし方がまだあまり思いついていません。


バッテリー電圧については、これにより TxPower & RSSI から算出した推定距離を補正できるかなと思ったのですが(バッテリー電圧が下がると同じ TxPower を設定していても観測される RSSI は下がる?と考えた)、ビーコンモジュールのメーカーに問い合わせたところ、バッテリー電圧が電波の強さに(大きくは)影響しないようなバッテリーを使用しており、かつ回路も工夫してある、とのこと。じゃあ他のビーコンモジュールはどうなのか、というのはわからないのですが、影響するとして、どんな計算式で補正可能なのかがわかりません。


ビーコンの温度は、バッテリー消費量に影響する らしいので活かせそうな気もしますが、その点についてはバッテリーレベルを直接見たほうがいい気がします。


アドバタイズ回数や起動時間も、電池交換のタイミングを知りたいならやはりバッテリーレベルを直接見たほうがいいし、アドバタイズ間隔なら設定値として知っているし、というところでやはり具体的な使いどころが思いつかない。。

バックグラウンドでも監視可能?

iBeaconはバックグラウンドでも領域監視可能ですが、Eddystoneもバックグラウンドで監視可能です。Core Bluetooth では、「バックグラウンドでのスキャン時には対象とする Service UUID を明示的に指定しないといけない」という制約がありますが、Eddystone としての Service UUID が定義されているので、スキャン開始時に明示的に指定することができます。

let services = [CBUUID(string: "FEAA")]
centralManager.scanForPeripheralsWithServices(services, options: nil)

というわけでこの点については iBeacon と比較してもデメリットにはならないかと。ただ、ロックスクリーンへのアイコン表示は iBeacon を用いないとできない機能です。

まとめ

かなりざっくばらんに書きましたが、結論として、"iOSアプリ開発者からみた" Eddystone を採用するメリットというのは、今のところ「カスタマイズ性」というところに尽きるかなと。他にもTLMパケットのように「Eddystone にあって iBeacon にないもの」は色々とあるものの、様々な代替手段を考えると、具体的な使いどころが個人的にはまだピンと来ていません。


とはいえ、レンジングの件含め、自分で好きなように実装できる、というのは十分に Eddystone 採用の理由に足るメリットかと思います。実際のサービスやプロダクトでiBeaconを使おうとするとそのブラックボックスに踏み込みたい場面は結構あるのではないでしょうか。


「その2」では、実装してみて色々と気づいた点を書いてみようと思います。


*1:ただ当方Androidアプリを書かないので、そちらの視点に立つと何かあるのかもしれません