はじめに
今回は、iOS の CoreBluetooth の一機能である iBeacon を Android でより実践的に使用する方法をお伝えしようと思います。 そこで使用するのが、AltBeacon と呼ばれるライブラリです。今回はこのライブラリを使用することになった経緯と共に使い方をまとめたいと思います。
やりたかったこと
そもそも Android で iBeacon を使用することで実現したかった機能があります。それが以下の項目になります。
- iBeacon のフォーマットをそのまま扱いたい
- 距離を計りたい
- 電力消費をコントロールしておいてもらいたい
もしくは、そのためのチューニングが容易にできるにしたい - Service で廻しやすい実装にしたい
ライブラリの選定
先程あげた iBeacon を使用するための機能を実装しようとしてライブラリを色々と試した結果、以下の経緯で一つのライブラリにたどり着きました。
- DBasS拡張ライブラリ「Contents Trigger Library」
Kii Object に強く依存するので使いづらいという問題が発覚し、採用見送り。 - aBeacon (Gaprot で公開していたライブラリ) 今回実践的な使い方をしてみて、バグや設計の見直しが発覚。採用見送り。
- AltBeacon
これだ!
AltBeacon
それではここから AltBeacon の特徴や使い方についてまとめます。
スペック
基本的な情報は以下になります。 詳しい情報については公式ページの方に載っていますのでそちらをご覧ください。
- Radius Networks社製
- フリー
- Apache License V2
- git
https://github.com/AltBeacon - 公式
http://altbeacon.org/ - Android専用
特徴
AltBeacon の特徴は以下になります。ちなみに、この特徴こそが今回このライブラリを採用した理由でもあります。
- フォーマットを指定することで、世にあるほとんどのBeacon規格に対応
AppleのiBeaconにも対応 - iOSのiBeaconと同じようなコード記述で実装できる
Regionをあらかじめ設定する、RegionのIN/OUTのイベントなどが予め備わっている - iOSのiBeaconと同じように、おおまかな距離計測ができる
手順
ここからは Android Studio で実際に AltBeacon を使用するための手順について説明したいと思います。
gradele にライブラリの導入の記述
まずは build.gradle ファイルを開き、その dependencies に以下の文を書き加えます。
compile 'org.altbeacon:android-beacon-library:2+@aar'
これを書いておくことで、この AltBeacon 内の Api を使用することができます。
必要な Permisssion の記述
次に AndroidManifest.xml に今回の AltBeacon を使用するにあたって必要なパーミッションを記述します。 AltBeacon は Bluetooth を使用した機能なので、Bluetooth を利用するためのパーミッションが必要になります。 また、iBeacon は Bluetooth LE を利用した機能になっているため、それを使用することのできる端末のみにインストールされるように feature も追加します。
具体的な記述は以下になります。
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
Service クラスの作成
次に、領域を監視するための Service クラスを新しく作成します。 バックグラウンドで領域監視するために、BootstrapNotifier クラスを implements しておきましょう。 一例としては以下の様なクラスになると思います。
class BeaconService extends Service implements BootstrapNotifier{ ...
この他にも Service を使用するためには、マニフェストファイルにこの作成した Service を使用することを宣言しておく必要があります。
監視領域 ( Region ) の設定
iBeacon では、Region と呼ばれる監視領域というものを設定することで、設置してある Beacon を検知できるようになります。 AltBeacon でも同じように Region を設定する必要があります。
設定の仕方として、まず始めに Region のインスタンスを作成しますがいくつか注意点があります。 それが以下になります。
- UUID, Major, Minor は直接文字列をメソッドに食わせるのではなくて、Identifier クラスのインスタンス化が必要
- インスタンス化の際に、UUID, Major, Minor の各々のフォーマットにマッチしないときは例外が吐かれるので対応が必要
- new Region() の第一引数は必ず識別子になる一意な文字列を入れること。でないと、複数のRegionを設定しても全て同じRegionの扱いになってしまう
この注意点を踏まえて Region を作成する具体例が以下になります。
Identifier identifier; //UUIDの作成 try { identifier = Identifier.parse(spot.beacon_uuid.toUpperCase()); }catch (Exception e){ continue; } //今回はmajor, minorの指定はしない Region region = new Region(this.getPackageName() + i, identifier, null, null); list.add(region); i++;
領域の監視を行う
RegionBootstrap クラスのインスタンスを作る事で、先程作成した Region の監視を行います。 インスタンスの作成には以下のコンストラクタを使用します。
mRegionBootstrap = new RegionBootstrap(this, list);
引数 | 内容 |
---|---|
this | BootstrapNotifier のインターフェイスを持ったクラス(今回は作成した Service) |
list | 監視する Region のリスト |
BeaconManager の設定
BeaconManager のインスタンスを作成し、そこに設定を行います。 フォアグラウンドの時やバックグラウンドの時のスキャン感覚、どのフォーマットの Beacon を探すかなど、細かい設定ができます。 以下がその一例になります。
mBeaconManager = BeaconManager.getInstanceForApplication(this); mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(IBEACON_FORMAT)); mBeaconManager.setForegroundBetweenScanPeriod(1000); mBeaconManager.setBackgroundBetweenScanPeriod(1000);
今回は IBEACON_FORMAT という iBeacon のフォーマットを指定するための文字列を与えています。 この文字列の具体的な内容は以下になります。
public static final String IBEACON_FORMAT = "m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24";
BeaconManager からのイベントを受け取る
先程作成した BeaconManager に様々なイベントを受け取るための設定を行います。 今回は、Beacon を検知した際のイベントについて説明します。 以下が今回やろうとしていることです。
- 「今領域内か?」のイベントを取得するため、RangeNotifier インターフェースを実装したインスタンスを作成し、それを BeaconManager に設定する
- RangeNotifier インスタンスに来る通知である didEnterRegion では検知が敏感にならなかったので、代わりに didRangeBeaconsInRegion で以下のような処理をする
- 最も自位置に近い Beacon を一つ選ぶ
- その Beacon が、直近に検知した Beacon で無い( matchBeacon メソッド内で判別している )なら、通知を出す
これを元に実装したものが以下になります。
mBeaconManager.setRangeNotifier(new RangeNotifier() { @Override public void didRangeBeaconsInRegion(Collectionbeacons, Region region) { // 検出したビーコンの情報を全部みる double lastDistance = Double.MAX_VALUE; Beacon nearBeacon = null; for (Beacon beacon : beacons) { if (lastDistance > beacon.getDistance()) { nearBeacon = beacon; } Log.d(TAG, "UUID:" + beacon.getId1() + ", major:" + beacon.getId2() + ", minor:" + beacon.getId3() + ", Distance:" + beacon.getDistance() + ",RSSI" + beacon.getRssi() + ", TxPower" + beacon.getTxPower()); } if( nearBeacon!= null && matchBeacon(nearBeacon) == false){ mLastBeacon = new Beacon.Builder().copyBeaconFields(nearBeacon).build(); showNotification(); } } });
ここで上げた didEnterRegion や didRangeBeaconsInRegion 以外にもイベントハンドリング用のメソッドは色々と用意されているので、自分の用途に合ったメソッドを探してみてください!
BootstrapNotifier からのイベントに対する処理
RegionBootstrap クラスに設定した Beacon に対して変化があった(領域に入ったり出たりした)場合に、BootstrapNotifier インターフェースのメソッドが呼ばれるようになります。
今回は領域に入ったら距離計測を始め、領域を出たら距離計測を停止するような処理にしています。 距離計測( startRangingBeaconsInRegionメソッド ) を始めると、前述の didRangeBeaconsInRegion イベントが呼ばれるようになります。
以下が実装例です。
@Override public void didEnterRegion(Region region) { // 領域侵入 Log.d(TAG, "Enter Region"); try { // レンジング開始 mBeaconManager.startRangingBeaconsInRegion(region); } catch (RemoteException e) { // 例外が発生した場合 e.printStackTrace(); } } @Override public void didExitRegion(Region region) { // 領域退出 Log.d(TAG, "Exit Region"); mLastBeacon = null; try { // レンジング停止 mBeaconManager.stopRangingBeaconsInRegion(region); } catch (RemoteException e) { // 例外が発生した場合 e.printStackTrace(); } } @Override public void didDetermineStateForRegion(int i, Region region) { // 領域に対する状態が変化 Log.d(TAG, "Determine State: " + i); }
終わりに
今回は AltBeacon について説明をしてきましたが、いかがでしたでしょうか。 この記事で紹介している使い方はあくまで一例です。それぞれの用途に合わせてメソッドなどを適宜変更することで、汎用的に使用可能なライブラリだと思います。
みなさんもこれを機に Android で iBeacon と連携するアプリの作成を行ってみてはいかがでしょうか!