[ Android ] Bluetooth受信

AndroidのBLEを使って受信してみる。(ビーコン受信とか向け)

・Android 7.1.1

1.受信コード

・AndroidManifest.xmlにパーミッション追記

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

bluetoothと位置情報の許可を出す(Androidのバージョンによって位置情報の許可は不要)

・activity_main.xmlにボタンを配置して、MainActivityのonCreateに追記する。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // ボタン押す
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(BLUETOOTH_SERVICE);
                BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
                bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() {
                    @Override
                    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
                        String str = "onLeScan name:"+device.getName()
                                + ", mac:"+device.getAddress()
                                + ", rssi:"+rssi
                                + ", len:"+scanRecord.length
                                + ", uuid:"+device.getUuids();
                        Log.d("test", str);
                    }
                });
            }
        });
    }

ボタンを押すと受信を開始して、ログに出力します。

2.受信コード2

上記の受信コードでは、BluetoothAdapterのstartLeScanにdeprecateの横線が入ります。別の方法としてBluetoothLeScannerを使います。

BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        BluetoothDevice bluetoothDevice = result.getDevice();
        Log.d("test", "onScanResult Name:"+bluetoothDevice.getName()+", Address:"+bluetoothDevice.getAddress()+", uuids:"+bluetoothDevice.getUuids());
        Log.d("test", "onScanResult str:"+result.getScanRecord().toString());
    }
});

これで受信が出来ます。

3.データ部について

1のコードでは、byte[] scanRecordにバイト配列で受信データが入ります。あとは独自でパースして使います。

2のコードでは、ScanResult resultの中にデータが入るのですが、パース後のデータになります。

ScanResult.getScanRecord().toString()するとこんな感じで入ってます。

mAdvertiseFlags = -1,
mServiceUuids = null,
mManufacturerSpecificData = {
    6 = [x, x, x, x, x...]
},
mServiceData = {},
mTxPowerLevel = -2147483648,
mDeviceName = null

mManufacturerSpecificDataがデータの部分なのですが、生データではなくパース後のデータになっており、ヘッダの一部が除かれています。

1のbyte[] scanRecordで下記のデータであれば、

1E FF 06 00 01 09 20 02 08 CE 21 AA 89 DC...

2のmManufacturerSpecificDataには、

{6=[1, 9, 32, 2, 8, -50, 33, -86, -119, -36,...

のようになります。(「6」は3バイト目)

「1E FF」の先頭部分を使うことはほぼないと思いますが。

あと、mManufacturerSpecificDataのデータはSparseArray<byte[]>になっています。
中身を表示例。

SparseArray<byte[]> sparseArray = result.getScanRecord().getManufacturerSpecificData();
for (int ii=0; ii<sparseArray.size(); ii++) {
    int key = sparseArray.keyAt(ii);
    byte[] buff = sparseArray.get(key);
    Log.d("test", "onScanResult key:"+key);

    StringBuilder sb = new StringBuilder();
    for (byte b : buff)
        sb.append(String.format("%02X ", b));
    Log.d("test", "onLeScan scanRecord:"+sb.toString());
}