Android携帯を使ってBLEモジュールをスキャンします。スキャンアプリはWindowsパソコン上のAndroid Studioで開発し、作成したスキャンアプリをUSB経由でAndroid携帯に転送して実行します。

Android携帯の設定

現在のAndroid携帯のBLE対応は次のようになっています。

  • 「API18 : Android 4.3」以前は、BLE非対応です。
  • 「API23 : Android 6.0」以降は、BLEを使用するために、位置情報機能(≒GPS機能)を有効にする必要があります。

スマホ側のアプリ実機テスト環境を設定

次の手順で、スマホ側のアプリ実機テスト環境を設定します。

  1. スマホの設定画面を開き、一番下の方にある「端末情報」をタップします。
  2. 端末情報画面の下の方にある「ソフトウェア情報」をタップします。
  3. 「ビルド番号」の文字の上をタップ連打すると、先ほどの設定画面にはなかった「開発者向けオプション」が表示されます。
  4. ここで「USB デバッグ」を設定します。
  5. PC とスマホを USB ケーブルでつなぐと、スマホ画面にデバッグ・アイコンが表示され、これでスマホ側の設定は 完了します。

Android携帯でアプリの権限設定

Android携帯でスキャンアプリの動作権限を設定します。

  1. スマホの設定画面を開き、「App Info 」よりスキャンアプリをタップします。
  2. 「Permissions」を開き「Location」を「許可」にします。

Android携帯でアプリ「LightBlue」によるスキャン

BLEモジュール「CC2541 SensorTag」「アルプスIoT Smart Module」をアプリ「LightBlue」でスキャンした結果を次に示します。

BLEモジュール「CC2541 SensorTag」の「CONNECT」ボタンを押すと次の内容が表示されます。

スキャンアプリの作成

次のようにスキャンアプリを作成します。

  • 48行目で、「Android端末がBLEをサポートしてるか」の確認を行います。
  • 57行目で、「Android端末がBluetoothをサポートしているか」、「Android端末のBluetooth機能が有効になっているか」の確認を行います。
  • 58-59行目で、Android端末のBluetooth機能が有効になっていない場合は、以下の処理により、「Bluetooth機能の有効化要求」ダイアログを表示します。
  • 79行目のonActivityResult関数で、「Bluetooth機能の有効化要求」ダイアログの結果(許可する/許可しない)を確認します。
  • 75行目でスキャンを開始します。デバイスを検出すると、92行目でアドレスとデバイス名を表示します。

MainActivity.java

package com.tomosoft.blescan;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;


import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.widget.Toast;
import android.widget.TextView;

import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private BluetoothAdapter adapter;
    private BluetoothLeScanner scanner;
    private MyScancallback scancallback;

    private final int PERMISSION_REQUEST = 100;

    private Handler handler;
    private final int SCAN_PERIOD = 10000;

    private BluetoothDevice device;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // text_view: activity_main.xml の TextView の id
        textView = findViewById(R.id.text_view);

        // テキストを設定
        textView.setText("");

        //BLE対応端末かどうかを調べる。対応していない場合はメッセージを出して終了
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
            finish();
        }
        //Bluetoothアダプターを初期化する
        BluetoothManager manager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
        adapter = manager.getAdapter();

        //bluetoothの使用が許可されていない場合は許可を求める。
        if( adapter == null || !adapter.isEnabled() ){
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent,PERMISSION_REQUEST);
        }
        else{
            scanner = adapter.getBluetoothLeScanner();
            scancallback = new MyScancallback();

            //スキャニングを10秒後に停止
            handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scanner.stopScan(scancallback);
                    finish();
                }
            }, SCAN_PERIOD);
            //スキャンの開始
            scanner.startScan(scancallback);
        }
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d("onActivityResult","start");
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PERMISSION_REQUEST) {
            Log.d("onActivityResult","permission");
        }
    }

    class MyScancallback extends ScanCallback{
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            Log.d("scanResult","start");
            if( result.getDevice() == null ) return;
            textView.append(result.getDevice().getAddress()+" - "+result.getDevice().getName()+"\n");
        }
    }
}

マニフェストファイル「AndroidManifest.xml」で、9行目でBLEの機能を使用する宣言、5-6行目でBLEの機能を使用するためのパーミッションの宣言、7行目で位置のパーミッションの宣言を行います。

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomosoft.blescan">

    <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-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

画面表示設定ファイル「activity_main.xml」を次に示します。10行目でTextViewのid「text_view」を示します。「@+id/」はidを示します。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

文字列リソースを「strings.xml」に追加します。

strings.xml

<resources>
    <string name="app_name">BleScan</string>
    <string name="ble_not_supported">xxBLEに対応していません</string>
    <string name="text">Test TextView</string>
</resources>

スキャンアプリの実行

Android Studio でスキャンアプリを作成し、ツールバーにある「Run」をクリックします。2,30秒でスキャンアプリがAndroid携帯にロードされて実行され、次のように表示されます。

次のようにAndroid Studio上の「logcat」ビューで出力されたログを確認します。

     ・・・
2021-05-27 06:10:22.613 6691-6704/com.tomosoft.blescan D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=9 mClientIf=0
2021-05-27 06:10:22.669 6691-6714/com.tomosoft.blescan I/Adreno-EGL: : EGL 1.4 QUALCOMM build:  (I909a4398ad)
    OpenGL ES Shader Compiler Version: XE031.09.00.04
    Build Date: 05/30/17 Tue
    Local Branch: 
    Remote Branch: 
    Local Patches: 
    Reconstruct Branch: 
2021-05-27 06:10:22.671 6691-6714/com.tomosoft.blescan I/OpenGLRenderer: Initialized EGL, version 1.4
2021-05-27 06:10:22.671 6691-6714/com.tomosoft.blescan D/OpenGLRenderer: Swap behavior 1
2021-05-27 06:10:22.673 6691-6714/com.tomosoft.blescan W/Adreno-ES20: : open failed: errno 13
2021-05-27 06:10:23.720 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:23.744 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:24.864 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:24.881 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:26.030 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:28.225 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:28.235 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:30.451 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:31.479 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:31.514 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:32.569 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:32.579 6691-6691/com.tomosoft.blescan D/scanResult: start
2021-05-27 06:10:32.607 6691-6691/com.tomosoft.blescan D/BluetoothAdapter: isLeEnabled(): ON

Bluetooth機能を無効にして、ソフトを起動すると、次のように有効化要求ダイアログが表示されます。「許可する」にすると、ソフトは起動します。「許可しない」にすると、ソフトは起動しません。