2015.03.10

Android 5.0におけるBLE について – 受信編 –


こんにちは。次世代システム研究室のT.M. です。

はじめに

Android 4.3 からBLE (Bluetooth Low Energy) を用いてデータを受信することができるようになりました。このBLE の規格の一つとしてiBeacon があり、GMO チェックインで利用しております。Android 5.0 からはBLE で送受信できるようになり、BLE を扱うパッケージ (android.bluetooth.le) が導入されました。それに伴い、既存の受信実装が非推奨になりましたので、新実装を旧実装と比較しながら紹介していきたいと思います。

BLE のためのパーミッション

新旧実装方法ともにBluetooth のパーミッションの宣言が必要です。
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

BLE スキャンのコールバック

  • 旧実装方法
    android.bluetooth.BluetoothAdapter.LeScanCallback クラスを利用します。コールバックメソッドは onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) です。引数のscanRecord に、BLE で受信したデータが渡されています。iBeacon では、scanRecord の10 から25 バイト目が iBeacon のUUID を、26、 27 バイト目がMajorを、28、29 バイト目がMinor を示しています。以下では、iBeacon のUUID、Major、Minor をログに表示しております(ただし、16 進数表示への変換はしておりません)。
    private LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    		@Override
    		public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
    			byte[] msg_bytes = scanRecord;
    			String msg = "";
    			for (int i = 9; i < msg_bytes.length; i++) {
    				msg += Byte.toString(msg_bytes[i]) + " ";
    			}
    			Log.d("ibeacon msg", msg);
    		}
    };
    
  • 新実装方法
    android.bluetooth.le.ScanCallback クラスを利用します。コールバックメソッドは3 種類ありますが、基本的には onScanResult(int callbackType, ScanResult result) です。result に、BLE で受信した結果オブジェクトが渡されております。
    result.getScanRecord() で、BLE で受信したデータオブジェクトを取得することができます。iBeacon のManufacturerId が76 であるため、getManufacturerSpecificData(int ManufacturerId) を利用することでiBeacon に関するデータを取得することができます。このデータのうち、3 バイト目からUUID の情報が記述されております。今回の変更では、BLE に関して扱いやすくはなりましたが、iBeacon のデータ取得では、旧実装方法と同様にバイト列を変換する必要があります。以下では、先ほどと同様にiBeacon に関するデータをログに表示しております。
    private ScanCallback mScanCallback = new ScanCallback() {
    
    		public void onBatchScanResults(List<ScanResult> results) {
    		};
    
    		public void onScanFailed(int errorCode) {
    		};
    
                    // 通常このメソッドがコールバックされます
    		public void onScanResult(int callbackType, ScanResult result) {
    			byte[] msg_bytes = result.getScanRecord().getManufacturerSpecificData(76);
                 if (msg_bytes == null) return;
    			String msg = &quot;&quot;;
    			for (int i = 2; i &lt; msg_bytes.length; i++) {
    				msg += Byte.toString(msg_bytes[i]) + &quot; &quot;;
    			}
    			Log.d(&quot;ibeacon msg&quot;, msg);
    		};
    };
    

BLE のスキャン開始

  • 旧実装方法
    android.bluetooth.BluetoothAdapter.startLeScan(LeScanCallback callback) でBLE のスキャンを開始します。
    // Bluetooth Adapter の取得
    BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
    // BLE のスキャン開始
    mBluetoothAdapter.startLeScan(mLeScanCallback);
    
  • 新実装方法
    android.bluetooth.le.BluetootLeScanner.startScan(ScanCallback callback) でBLE のスキャンを開始します。
    // BLE Scanner の取得
    BluetoothManager mbluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    BluetoothAdapter mBluetoothAdapter = mbluetoothManager.getAdapter();
    BluetoothLeScanner mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
    // BLE のスキャン開始
    mBluetoothLeScanner.startScan(mScanCallback);
    

新しく追加されたオプション

ここまではBLE の受信の違いを比較してきましたが、Android 5.0 からBLE のフィルタリングオプションおよびスキャンモードの設定ができるようになりましたので、紹介します。ScanFilter.Builder において、サービスUUID (iBeacon のUUID とは異なる) などを設定することで、特定のBLE のみ受信する事ができます。ScanSettingBuiler において、BLE のスキャンモードを指定することができます。指定できるモードは、低遅延モード (SCAN_MODE_LOW_LATENCY)、低消費電力モード (SCAN_MODE_LOW_POWER)、バランスモード (SCAN_MODE_BALANCED) があります。以下では、低遅延モードでスキャンをしています。
// (何もフィルタリングしない) スキャンフィルタの作成
List<ScanFilter> mScanFilters = new ArrayList<ScanFilter>();
// スキャンモードの作成 
ScanSettings.Builder mScanSettingBuiler = new ScanSettings.Builder();
mScanSettingBuiler.setScanMode(android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY);
ScanSettings mScanSettings = mScanSettingBuiler.build();
// 作成したスキャンフィルタとモードでスキャン開始
mBluetoothLeScanner.startScan(mScanFilters, mScanSettings, mScanCallback);
実際に、各スキャンモードを指定して、スキャンの間隔を調べてみました。Nexus6 を利用し、各モードで1 分間スキャンを行い、コールバックが返ってくる間隔を計測しました。低遅延モードでは、約100 ms ごとにコールバックが返ってきたので、常にスキャンをしているということが推測されます。また、スキャンモードの指定なし、および低消費電力モードでは、約400 ms のスキャンと約4,600 ms の休みの繰り返しが行われていました。バランスモードでは、約 2,000 ms のスキャンと約 3,000 ms の休みの繰り返しが行われていました。このように、スキャンの消費電力を下げるためには、旧実装方法では、アプリ開発者が定期的にスキャン開始、停止を実行する必要がありましたが、オプションで指定するだけで、同様のことができるようになりました。

さいごに

以上のようにBLE を受信する方法が変更しております。Android 5.0 からは旧実装方法では実行できない、といった情報を見かけましたが、実際私の端末 (Nexus6, Android 5.0.1) で、実行することができました。(ただし、Nexus7 の一部端末ではハードウェアが対応していないため、すべてのAndroid 5.0 以上の端末でBLE が利用可能というわけではありません。) つまり、旧実装方法が利用不可能になったわけではないため、現在、旧実装方法を行っているサービスはしばらくは変更の必要がないと思います。
次回はAndroid 5.0 から可能になった、BLE の送信について実装方法を紹介していきたいと思います。

参考




次世代システム研究室では、アプリケーション開発や設計を行うアーキテクトを募集しています。アプリケーション開発者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。

皆さんのご応募をお待ちしています。