[Android 5.0] BLEのBluetoothLeScannerについて

こんにちはKID.Aです。

 

今回もBLEの記事になります。

Android 5.0からBluetoothLeScannerというクラスが追加になり、BLEデバイスの検索やフィルターが簡単に実装できるようになりましたので実装方法を紹介していこうとおもいます。

 

下記はBluetoothLeScannerのAPIのリンクになります。
・開発サイトのAPI
http://developer.android.com/intl/ja/reference/android/bluetooth/le/BluetoothLeScanner.html

 

それでは実装をしていきます。

 

マニフェストに追加

AndroidManifest.xmlに以下を追加します。

<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

 

実装

BluetoothLeScannerで周辺のデバイスを検索、フィルターするソースを記載します。
※ソースはシンプルにしています。start_buttonでスキャンを開始して、stop_buttonでスキャンを終了しています。

package jp.co.bluetoothle;

import android.Manifest;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.Context;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        BluetoothAdapter adapter = manager.getAdapter();
        final BluetoothLeScanner bluetoothLeScanner = adapter.getBluetoothLeScanner();

         // 6.0以降はコメントアウトした処理をしないと初回はパーミッションがOFFになっています。
         // requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 0);

        final ScanCallback scanCallback = new ScanCallback() {
            @Override
            public void onScanResult(int callbackType, ScanResult result) {
                super.onScanResult(callbackType, result);
                Log.d(MainActivity.class.getName(), "callbackType = " + callbackType);
                BluetoothDevice bluetoothDevice = result.getDevice();
                Log.d(MainActivity.class.getName(), "address:" + bluetoothDevice.getAddress());
                Log.d(MainActivity.class.getName(), "name:" + bluetoothDevice.getName());
            }

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

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

        findViewById(R.id.start_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ScanFilter scanFilter =
                        new ScanFilter.Builder()
                                .setDeviceName("DeviceName")
                                .build();
                ArrayList scanFilterList = new ArrayList();
                scanFilterList.add(scanFilter);

                ScanSettings scanSettings =
                        new ScanSettings.Builder()
                        .setScanMode(ScanSettings.SCAN_MODE_BALANCED)

                bluetoothLeScanner.startScan(scanFilterList, scanSettings, scanCallback);
            }
        });

        findViewById(R.id.stop_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bluetoothLeScanner.stopScan(scanCallback);
            }
        });

    }
}

 

BluetoothLeScanner#startScanでスキャンを開始できます。
BluetoothLeScanner#startScanにScanFilterのリストとScanSettingsを引数に追加することで検索条件のフィルターを設定できます。
ソースでは、ScanFilterでデバイス名が”DeviceName”と一致する検索結果をフィルターしています。またScanSettingsでScanModeの設定をしています。

 

スキャン結果はScanCallBack#onScanResultにcallbackType(CALLBACK_TYPE_ALL_MATCHES、CALLBACK_TYPE_FIRST_MATCH、CALLBACK_TYPE_MATCH_LOST)とScanResultが通知されます。
BluetoothAdapter.LeScanCallback#onLeScanはデバイスを取得できた(アドバタイジングをうけた)タイミングで呼ばれます。アドバタイジングは一定間隔で常に発行されているため一定間隔でBluetoothAdapter.LeScanCallback#onLeScanが呼ばれ続ける挙動になります。これと同じくBluetoothLeScanner#startScanの後、デバイスを取得できたタイミングでScanCallBack#onScanResultが呼ばれ続けます。

 

ScanResult#getDeviceでBluetoothDeviceを取得します。
BluetoothDeviceが取得できれば、この記事と同じBluetoothAdapter.LeScanCallback#onLeScanが呼ばれたあとの処理と同じに実装すればペリフェラル側と接続できます。

 

BluetoothLeScanner#stopScanでスキャンを停止できます。引数のBluetoothAdapter.LeScanCallbackはBluetoothLeScanner#startScanで設定した変数を渡さないと停止しないので注意してください。

 

4.4まではstartActivityForResultを行ったり、スキャン条件を自分で実装しなければいけなかったのですが、BluetoothLeScannerになってこのへんが簡単になりました。

 

以上です。

 

 

KID.A

KID.A の紹介

楽して生きることと一発逆転を夢見ている、ちゃきちゃきのAndroiderです。 いろいろアプリを出しているのですが、いつもリリース後にターゲットユーザ数を2桁見誤っていたことに気付くので、残念でなりません。下方修正で、ヒットがでません。おしいです。 明日から本気出します。 よろしくお願いします。
カテゴリー: Android タグ: , , , , パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です