Raspberry piでiBeacon受信」でRaspberry pi 3を使用してiBeaconを受信しましたが、今回はAndroid携帯を使用してiBeaconを受信します。

iPhoneアプリ「 Beacon入門」の設定

iPhoneアプリ「 Beacon入門」を使って次のiBeaconを発生します。

uuid: 48534442-4C45-4144-80C0-1800FFFFFFFF
major: 100
minor: 1
power: -56

micro:bitでiBeaconの作成」で使ったAndroidアプリ「Beacon Scanner」により、iPhoneアプリ「 Beacon入門」で発生したiBeaconを確認します。

BeaconScannerアプリの作成

BeaconScannerアプリは、「Android携帯を使ってBLEモジュールのスキャン」で作成したスキャンアプリをベースに、次のように作成します。99行目で受け取ったスキャンレコードを「Raspberry piでiBeacon受信」で示すiBeaconの仕様に従って編集します。

MainActivity.java

package com.tomosoft.beaconapplication;

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.bluetooth.le.ScanRecord;


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;
    private final String TAG = "Beacon";

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

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

        //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) {
            super.onScanResult(callbackType, result);
            // スキャン結果が返ってきます
            // このメソッドかonBatchScanResultsのいずれかが呼び出されます。
            // 通常はこちらが呼び出されます。
            if (result == null){
                return;
            }
            BluetoothDevice bDevice = result.getDevice();
            ScanRecord record = result.getScanRecord();
            byte[] bytes = record != null ? record.getBytes() : new byte[0];

            Log.d(TAG, bDevice.getAddress());
            Log.d(TAG, bDevice.toString());
            Log.d(TAG, getUUID(bytes));
            Log.d(TAG, getMajor(bytes));
            Log.d(TAG, getMinor(bytes));
            Log.d(TAG, String.valueOf(bytes[29]));
            Log.d(TAG, String.valueOf(result.getRssi()));
            textView.append("UUID: "+getUUID(bytes)+" major: "+getMajor(bytes)+" minor: "+getMinor(bytes)+
                    " Power: "+String.valueOf(bytes[29])+" Rssi: "+String.valueOf(result.getRssi())+"\n");

        }
        private String getUUID(byte[] scanRecord) {
            String uuid = IntToHex2(scanRecord[9] & 0xff)
                    + IntToHex2(scanRecord[10] & 0xff)
                    + IntToHex2(scanRecord[11] & 0xff)
                    + IntToHex2(scanRecord[12] & 0xff)
                    + "-"
                    + IntToHex2(scanRecord[13] & 0xff)
                    + IntToHex2(scanRecord[14] & 0xff)
                    + "-"
                    + IntToHex2(scanRecord[15] & 0xff)
                    + IntToHex2(scanRecord[16] & 0xff)
                    + "-"
                    + IntToHex2(scanRecord[17] & 0xff)
                    + IntToHex2(scanRecord[18] & 0xff)
                    + "-"
                    + IntToHex2(scanRecord[19] & 0xff)
                    + IntToHex2(scanRecord[20] & 0xff)
                    + IntToHex2(scanRecord[21] & 0xff)
                    + IntToHex2(scanRecord[22] & 0xff)
                    + IntToHex2(scanRecord[23] & 0xff)
                    + IntToHex2(scanRecord[24] & 0xff);
            return uuid;
        }

        private String getMajor(byte[] scanRecord) {
            String hexMajor = IntToHex2(scanRecord[25] & 0xff) + IntToHex2(scanRecord[26] & 0xff);
            return String.valueOf(Integer.parseInt(hexMajor, 16));
        }

        private String getMinor(byte[] scanRecord) {
            String hexMinor = IntToHex2(scanRecord[27] & 0xff) + IntToHex2(scanRecord[28] & 0xff);
            return String.valueOf(Integer.parseInt(hexMinor, 16));
        }

        private String IntToHex2(int i) {
            char hex_2[]     = { Character.forDigit((i >> 4) & 0x0f, 16), Character.forDigit(i & 0x0f, 16) };
            String hex_2_str = new String(hex_2);
            return hex_2_str.toUpperCase();
        }
    }
}

BeaconScannerアプリの実行

Android携帯を使ってBLEモジュールのスキャン」の「Android携帯の設定」に従って次の設定を行います。

  • スマホ側のアプリ実機テスト環境を設定
  • Android携帯でアプリの権限設定

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

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

2021-06-03 14:32:29.609 2620-2911/? I/A: Setting = NOW_CARDS, optedInt = true
2021-06-03 14:32:29.611 1494-1538/? D/ActivityManager: cleanUpApplicationRecord -- 5389
2021-06-03 14:32:29.715 1494-1540/? I/DeviceIdleController: handleMessage(7)
2021-06-03 14:32:29.715 1494-1540/? I/DeviceIdleController: handleMessage(7)
2021-06-03 14:32:30.084 2738-2738/? D/wpa_supplicant: wlan0: Control interface command 'SIGNAL_POLL'
2021-06-03 14:32:30.095 2738-2738/? D/wpa_supplicant: CTRL-DEBUG: global_ctrl_sock-sendto: sock=9 sndbuf=212992 outq=0 send_len=48
2021-06-03 14:32:30.220 6085-6085/com.tomosoft.beaconapplication D/Beacon: 5B:9F:C4:D3:1A:E6
2021-06-03 14:32:30.220 6085-6085/com.tomosoft.beaconapplication D/Beacon: 5B:9F:C4:D3:1A:E6
2021-06-03 14:32:30.221 6085-6085/com.tomosoft.beaconapplication D/Beacon: 48534442-4C45-4144-80C0-1800FFFFFFFF
2021-06-03 14:32:30.221 6085-6085/com.tomosoft.beaconapplication D/Beacon: 100
2021-06-03 14:32:30.221 6085-6085/com.tomosoft.beaconapplication D/Beacon: 1
2021-06-03 14:32:30.221 6085-6085/com.tomosoft.beaconapplication D/Beacon: -56
2021-06-03 14:32:30.221 6085-6085/com.tomosoft.beaconapplication D/Beacon: -36
2021-06-03 14:32:30.233 6085-6085/com.tomosoft.beaconapplication D/Beacon: 5E:B9:80:02:D6:E6
2021-06-03 14:32:30.233 6085-6085/com.tomosoft.beaconapplication D/Beacon: 5E:B9:80:02:D6:E6
2021-06-03 14:32:30.233 6085-6085/com.tomosoft.beaconapplication D/Beacon: 00100503-1C13-A5C9-0000-000000000000
2021-06-03 14:32:30.234 6085-6085/com.tomosoft.beaconapplication D/Beacon: 0
2021-06-03 14:32:30.234 6085-6085/com.tomosoft.beaconapplication D/Beacon: 0
2021-06-03 14:32:30.234 6085-6085/com.tomosoft.beaconapplication D/Beacon: 0
2021-06-03 14:32:30.234 6085-6085/com.tomosoft.beaconapplication D/Beacon: -98
2021-06-03 14:32:30.250 6085-6085/com.tomosoft.beaconapplication D/Beacon: 5B:9F:C4:D3:1A:E6
2021-06-03 14:32:30.250 6085-6085/com.tomosoft.beaconapplication D/Beacon: 5B:9F:C4:D3:1A:E6
2021-06-03 14:32:30.250 6085-6085/com.tomosoft.beaconapplication D/Beacon: 48534442-4C45-4144-80C0-1800FFFFFFFF
2021-06-03 14:32:30.251 6085-6085/com.tomosoft.beaconapplication D/Beacon: 100
2021-06-03 14:32:30.251 6085-6085/com.tomosoft.beaconapplication D/Beacon: 1
2021-06-03 14:32:30.251 6085-6085/com.tomosoft.beaconapplication D/Beacon: -56
2021-06-03 14:32:30.251 6085-6085/com.tomosoft.beaconapplication D/Beacon: -36
2021-06-03 14:32:30.281 6085-6085/com.tomosoft.beaconapplication D/Beacon: 5B:9F:C4:D3:1A:E6
2021-06-03 14:32:30.281 6085-6085/com.tomosoft.beaconapplication D/Beacon: 5B:9F:C4:D3:1A:E6
2021-06-03 14:32:30.282 6085-6085/com.tomosoft.beaconapplication D/Beacon: 48534442-4C45-4144-80C0-1800FFFFFFFF
2021-06-03 14:32:30.282 6085-6085/com.tomosoft.beaconapplication D/Beacon: 100
2021-06-03 14:32:30.282 6085-6085/com.tomosoft.beaconapplication D/Beacon: 1
2021-06-03 14:32:30.282 6085-6085/com.tomosoft.beaconapplication D/Beacon: -56
2021-06-03 14:32:30.282 6085-6085/com.tomosoft.beaconapplication D/Beacon: -36
2021-06-03 14:32:30.292 6085-6090/com.tomosoft.beaconapplication I/art: Do partial code cache collection, code=20KB, data=28KB
2021-06-03 14:32:30.293 6085-6090/com.tomosoft.beaconapplication I/art: After code cache collection, code=20KB, data=28KB