(iBeacon + Android) × Android Wear = (^ω^)

 

こんにちは株式会社ドラプロの「おひろ」といいます。
iOS/Androidエンジニアやってます。
初ブログです。今後ともよろしくお願いいたします。

 

研究のために先日会社でiBeaconを購入しました。
こちら

Androidでも4.3以降であればビーコンの信号を受信できるみたいだったので、
試しにコードを書いてみました。その概要をまとめましたので公開します。
さらに最近Android Wearも手に入れたので、それとも連携させてみました。

iBeaconからの信号→Android端末で受け取る→Wearに通知してWear上でメッセージ表示、
という流れの簡単なサンプルアプリを作りました。
WearでiBeaconからの信号を直接受けることも可能みたいですが、
あまりやらない方がいい的な記事を見かけたりしたのでAndroid端末をかましています。

まずiBeaconからの信号を受信する方法ですが、Manifestファイルに
Bluetooth通信を許可するパーミッションの設定を行います。

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

次にソースコード側で以下のパッケージをimportします。

import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;

これらのAPIが4.3以降に導入されたものなので、それ以前では実装できないようです。

次に監視を開始したいタイミングで以下のコードを書きます。
今回はひとまずonCreateで呼びました。

BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
bluetoothAdapter.startLeScan(this);

ビーコンを発見したときに通知を受け取るために、BluetoothAdapter.LeScanCallbackを実装します。

public class MyActivity extends Activity implements BluetoothAdapter.LeScanCallback {
    :
    :

    @Override
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
        // ビーコンが発見されるたびにこのメソッドがコールされるので、
        // 受信したデータをもとにやりたいことをここに書く
    }

    :
    :
}

第三引数のscanRecordのbyte配列に受信したデータが以下の並びで入っています。

Byte 数 説明
1 1 ブロック目のバイト数
2,3 flag
4 2 ブロック目のバイト数
5 メーカー固有の AD type データ
6,7 会社コード(0x004C が Apple の会社コード)
8 データのタイプ(0×02 が iBeacon)
9 連なる iBeacon データのバイト数
10~25 UUID
26,27 major
28,29 minor
30 校正された電波強度(距離を求めるときの基準値、2 の補数)

これを元にUUIDやmajar値などを取り出して、ビーコンの判別をすることができます。
*データの並びや、取り出し方に関しては、このページを参考にさせていただきました。

ひとまずAndroid端末にいくつか受信したパラメータを表示してみました。

20140905_1

画像のintensityと表示されている部分は第二引数のrssiの値を表示したものです。
rssiは受信した電波の強度を表す数値で、ビーコンとの距離が近くなるほど数値が大きくなります。
今回は閾値を設け、このrssiがその閾値を超えたときにWearに通知を送りました。
つまり、閾値を超えた=ビーコンのあるエリアに入った、と見なして通知を送る訳です。

Wearへ通知メッセージを送るために、以下のパッケージをimportします。

import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;

通知を行いたい箇所で以下のコードを書きます。

// 通知する内容を構築するビルダー生成
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this);

// ----- 最低限必要な情報 -------
notificationBuilder.setSmallIcon(R.drawable.dorapro); // アイコン画像
notificationBuilder.setContentTitle("通知"); // タイトル
notificationBuilder.setContentText("ビーコン発見!"); // メッセージ内容
// ----------------------------

// バイブレーションさせたい場合に設定する
notificationBuilder.setDefaults(Notification.DEFAULT_VIBRATE);

// 通知を送るためのノティフィケーションマネージャーの生成
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(this);

// 通知を送る
int notificationId = 1;
notificationManager.notify(notificationId, notificationBuilder.build());

これでこんな感じにWearに通知が表示されます。

20140905_2

実際の場面ではWearに通知を送るだけでなく、端末で詳細な情報を見たいことがあると思います。
例えば、お店でクーポンを配布したい時。
お店に入ったときにクーポンが配信されたことのみをWearに通知して、
クーポンの詳細な情報(内容、利用場所、有効期限など)を見たい場合には端末で開く、といったケースが考えられます。

その場合には通知を送る前に以下のコードを追加します。

// Wearから「端末で開く」をタップしたときに開きたいActivityを設定する
Intent viewIntent = new Intent(this, MyActivity.class); // 「MyActivity」を開く
PendingIntent viewPendingIntent =
PendingIntent.getActivity(this, 0, viewIntent, 0);
notificationBuilder.setContentIntent(viewPendingIntent);

PendingIntentという特別なIntentを仕込んでおくと、通知したときに以下のように
通知をスワイプすると「端末で開く」という項目が出てきます。

20140905_3

これをタップするとIntent生成時に指定したActivityが開く、という仕組みです。

実装の流れは以上です。結構簡単に実装できるようになってるかと思います。
あとはiBeaconやWearを効果的に使うアイデアがあれば面白いものが作れそうです。

そんなアイデアをお持ちのアナタ。
ドラプロまでお気軽にご連絡ください、お待ちしております(笑)

ではでは。

Pocket