せっかなくので、やってみた。

日々のあんなこと、こんなこと、せっかくなのでやってみた

androidでbluetoothのiBeaconのデータを取得したい件

bluetooth難しいです。タイトルの日本語が正しいのかすら分かりません...

androidでは、標準のライブラリとして、android 4.3 (API level 18)以降から利用できるBluetooth low energy(BLE) APIが提供されています。
developer.android.com

ただし、Bluetooth機器全般を制御する為のAPIで、iBeacon対応デバイスの仕様書に書かれているようなデータを簡単に取得する事はできない。
で、AltBeaconライブラリを使えば簡単に取得できるのだけど、BLEのAPIと比べて若干機器検出の反応が鈍い気がする。(個人の感想です。)
github.com

じゃあやっぱりBLEのAPIで取得したいところですが、なかかな仕様が複雑です。 bluetoothの機器からは一定間隔でアドバタイズパケットが送信されているのですが、そのペイロード(データ?)の中身を解析し、 iBeaconをはじめとするいくつかのデータフォーマットに合わせて取得する必要があります。

この記事に全てが集約されています。

qiita.com

うれしいことに、記事の作者さんが公開されている nv-bluetooth を使用することにより、 BLE APIを使用してiBeaconのデータを簡単に取得することができます。
ありがたく使わせていただきます。
GitHub - TakahikoKawasaki/nv-bluetooth: Bluetooth utility library, mainly for Android.

使い方はREADMEに書かれていまます。

機器にもよりますが、ローバッテリーなどの情報は、iBeaconのデータから取得することができます。 ちなみに、iBeaconのデータを拾うだけならGATT接続する必要はありません。 こんな感じで取得できます。

ArrayList scanFilterList = new ArrayList();
// フィルターで色々な条件を指定できる。
scanFilterList.add(new ScanFilter.Builder().setDeviceName("機器名など").build()); 
// スキャンモードの作成
// SCAN_MODE_LOW_POWER     0.5秒スキャン→4.5秒待つを繰り返します。アプリがフォアグラウンドにいない場合、このモードが強制される。(default)
// SCAN_MODE_BALANCED      2秒スキャン→3秒待つを繰り返します。
// SCAN_MODE_LOW_LATENCY   ずっとスキャンします。アプリがフォアグラウンドにいるときのみの利用が推奨されている。
// SCAN_MODE_OPPORTUNISTIC 特別なモードです。他のアプリがBLEスキャンを実行するとスキャン結果が通知されます。
ScanSettings scanSettings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_POWER).build();

// スキャン開始(mBluetoothLeScannerのインスタンスは取得済みの前提)
mBluetoothLeScanner.startScan(scanFilterList, scanSettings, new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);

        // アドバタイズパケットをパースしたADStructureから、iBeaconのデータのみ取得する。
        List<ADStructure> structures = ADPayloadParser.getInstance().parse(result.getScanRecord().getBytes());
        IBeacon iBeacon = null;
        for (ADStructure structure : structures) {
            if (structure instanceof IBeacon) {
                iBeacon = (IBeacon)structure;
                break;
            }
        }
        if (iBeacon == null) {
            Log.d(TAG, "No iBeancon data found");
        } else {
            Log.d(TAG, "iBeacon data: "
                    + "major:" + iBeacon.getMajor() + "\n"
                    + "minor:" + iBeacon.getMinor() + "\n"
                    + "uuid:" + iBeacon.getUUID() + "\n"
                    + "power:" + iBeacon.getPower());
        }
    }

    @Override
    public void onBatchScanResults(List<ScanResult> results) {
        super.onBatchScanResults(results);
    }

    @Override
    public void onScanFailed(int errorCode) {
        super.onScanFailed(errorCode);
    }
});