1. ホーム
  2. Android

Android Bluetooth接続

2022-02-17 01:14:26

I. 概要

Bluetoothは、固定機器、モバイル機器、ビルディングパーソナルネットワークの間で近距離のデータ交換を可能にする無線技術規格である。最大7台のBluetooth機器と同時に接続し、通信を行うことができる。Bluetoothは、従来のBluetooth(Bluetooth 3.0仕様以前)と低電力Bluetooth(Bluetooth 4.0仕様以降)に大別される。

Androidはバージョン4.3(API Level 18)からBluetooth Low Energy(BLE)通信に対応し、アプリがBluetooth機器のスキャン、ペアリング、接続、データ転送を行うためのAPIが提供されています。

Android BLE API には、いくつかの重要なクラスがあります。

1. BluetoothAdapter

ローカルのBluetoothアダプタです。すべての Bluetooth インタラクション操作のエントリポイントです。このクラスでは、他の Bluetooth デバイスの検出、ペアリング済みデバイスのリストの照会、既知の MAC アドレスによる BluetoothDevice のインスタンス化、および他のデバイスとの通信をリッスンするための BluetoothServerSocket の作成を行うことができます。

2. BluetoothDevice

リモートのBluetoothデバイスです。このクラスを使用して、リモートデバイスへの BluetoothSocket 接続を要求したり、デバイス名、アドレス、クラス、および接続ステータスなどのデバイス情報を問い合わせたりします。

3. BluetoothSocket

Bluetoothソケット(TCPソケットに類似)のインターフェイスを表します。アプリケーションがInputStreamとOutputStreamを介して他のBluetoothデバイスとデータを交換するための接続ポイントです。

4. BluetoothServerSocket

は、リクエストを受け付けるオープンなサーバーソケットを表します(TCP ServerSocketに似ています)。2つのAndroidデバイスを接続するには、デバイスがこのクラスを使ってサーバーソケットを開く必要があります。リモートのBluetoothデバイスがそのデバイスへの接続要求を開始すると、BluetoothServerSocketは、接続を受け入れる接続済みBluetoothSocketを返します。

III. Bluetoothの開発

1. プロセス

2. パーミッションをオンにする

<uses-permission android:name="android.permission.BLUETOOTH"/> 
//When Bluetooth is enabled, mBluetoothAdapter.enable() requires the following permissions
<use-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

3. Bluetoothをオンにする

public void isBluetoothEnable() {
        //Get the Bluetooth adapter
	mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
	if (mBluetoothAdapter ! = null){
		// Bluetooth is turned on
		if (mBluetoothAdapter.isEnabled()){			
		}else{// If not open, then open, here you can prompt user to open by popup box
            mBluetoothAdapter.enable()
        }
    }	
}

4. 近くのBluetoothデバイスを検索する

/**
 * Register to search for broadcasts of Bluetooth devices
 */
private void startDiscovery() {
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    registerReceiver(receiver, filter);
    IntentFilter filter1 = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    registerReceiver(receiver, filter1);
    startScanBluetooth();
}

private void startScanBluetooth() {
    // Determine if it is searching, if it is searching, cancel the search
    if (bluetoothAdapter.isDiscovering()) {
        bluetoothAdapter.cancelDiscovery();
    }
    // Start the search
    bluetoothAdapter.startDiscovery();
}

/**
 * Bluetooth radio reception
 */
private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
    public void onReceive(Context context, Intent intent) {

       String action = intent.getAction();
       if (BluetoothDevice.ACTION_FOUND.equals(action)) {
           BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

           // Bluetooth rssi parameter, represents Bluetooth strength
           short rssi = intent.getExtras().getShort(BluetoothDevice.EXTRA_RSSI);
           //Bluetooth device name
           String name = device.getName();
           //state of the device
           int status = device.getBondState();
           ...
        } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
           ...
        } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { ...
           Toast.makeText(context, "Bluetooth device search complete", Toast.LENGTH_SHORT).show();
        }
    }
};

Bluetoothの接続状態について。

BluetoothDevice.BOND_BONDED: ペアリング済み

BluetoothDevice.BOND_BONDING: ペアリング進行中

BluetoothDevice.BOND_NONE:ペアリングしていない、またはペアリングを解除している

Bluetoothの強度rssiについて。

単位はdbm、Bluetooth信号の強さRSSI = 10*log P、Pは受信信号電力を表します。Bluetoothはブロードキャストを送信し、距離の大きさは、信号の電力強度に影響を与えます。送信電力が最大値の1mwを取るとして、RSSIの値は0、つまりBluetoothに最も近づいた時に得られるRSSIの値は理想的な状態では0ですが、実際にはそのような理想的な状態は基本的にないので、RSSIの値は基本的に負の数になっています。

一般にBLEでは、信号強度を強、中、弱、弱の4段階に分けていると仮定すると、rssiの範囲は順に-60~0 , -70~60 , -80~70 , <~80となります。

5. ペアリング

//Get paired device information
public List<BluetoothDevice> getPairedBluetoothDevices() {
	List deviceList = new ArrayList<>();
	Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
	if (pairedDevices.size() > 0) {
		for (BluetoothDevice device : pairedDevices) {
			deviceList.add(device);
		}
	}
	return deviceList;
}
//If the number of paired devices is 0, jump to the phone system Bluetooth settings interface
Intent enableBtIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
mContext.startActivity(enableBtIntent);
//Manual pairing, just rescan when done
Method method = BluetoothDevice.class.getMethod("createBond");
method.invoke(itemlist.get(position).getDevice());


public class BluetoothConnectThread extends Thread {

    private static final UUID BluetoothUUID = UUID.fromString("0000001101-0000-1000-8000-00805F9B34FB");
    BluetoothSocket bluetoothSocket;
    BluetoothDevice bluetoothDevice;

    private boolean connected = false;
    private Object lock = new Object();

    // Bluetooth connection callback interface
    private BluetoothConnectCallback connectCallback;

    public BluetoothConnectThread(BluetoothDevice device,
                                  BluetoothConnectCallback callback) {
        try {
            bluetoothDevice = device;
            bluetoothSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(BluetoothUUID);
            connectCallback = callback;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        if (bluetoothSocket ! = null) {
            if (connected) {
                cancel2();
                connected = false;
            }
        }

        new Thread() {
            @Override
            public void run() {
                connect();
                if (connected) {
                    if (connectCallback ! = null){
                        connectCallback.connectSuccess(bluetoothSocket);
                    }
                }
            }
        }.start();

    }

    public void connect() {
        try {
            synchronized (lock) {
                bluetoothSocket.connect();
                connected = true;
            connected = true; }
        } catch (Exception connectException) {
            connectException.printStackTrace();
            cancel();
            try {
                Method m;
                m = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                bluetoothSocket = (BluetoothSocket) m.invoke(bluetoothDevice, Integer.valueOf(1));
                bluetoothSocket.connect();
                connected = true;
            } catch (Exception ex) {
                ex.printStackTrace();
                if (connectCallback ! = null){
                    connectCallback.connectFailed(ex.getMessage());
                }
            }
        }
    }

    public void cancel() {
        try {
            synchronized (lock) {
                if (connected) {
                    bluetoothSocket.close();
                    connected = false;
                }
            }
        } catch (IOException e) {
        }
    }

    public void cancel2() {
        try {
            synchronized (lock) {
                bluetoothSocket.close();
                connected = false;
            }
        } catch (IOException e) {
        }
    }

}
public interface BluetoothConnectCallback {

    void connectSuccess(BluetoothSocket socket);

    void connectFailed(String errorMsg);

    void connectCancel();
}

//Get the output stream of BluetoothSocket
OutputStream outputStream = bluesocket.getOutputStream();
//then write the data to the output stream to complete the transfer
outputStream.write(data);
outputStream.flush();

6. 接続

Bluetooth接続はサブスレッドで行う必要があります。

public class BluetoothConnectThread extends Thread {

    private static final UUID BluetoothUUID = UUID.fromString("0000001101-0000-1000-8000-00805F9B34FB");
    BluetoothSocket bluetoothSocket;
    BluetoothDevice bluetoothDevice;

    private boolean connected = false;
    private Object lock = new Object();

    // Bluetooth connection callback interface
    private BluetoothConnectCallback connectCallback;

    public BluetoothConnectThread(BluetoothDevice device,
                                  BluetoothConnectCallback callback) {
        try {
            bluetoothDevice = device;
            bluetoothSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(BluetoothUUID);
            connectCallback = callback;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        if (bluetoothSocket ! = null) {
            if (connected) {
                cancel2();
                connected = false;
            }
        }

        new Thread() {
            @Override
            public void run() {
                connect();
                if (connected) {
                    if (connectCallback ! = null){
                        connectCallback.connectSuccess(bluetoothSocket);
                    }
                }
            }
        }.start();

    }

    public void connect() {
        try {
            synchronized (lock) {
                bluetoothSocket.connect();
                connected = true;
            connected = true; }
        } catch (Exception connectException) {
            connectException.printStackTrace();
            cancel();
            try {
                Method m;
                m = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                bluetoothSocket = (BluetoothSocket) m.invoke(bluetoothDevice, Integer.valueOf(1));
                bluetoothSocket.connect();
                connected = true;
            } catch (Exception ex) {
                ex.printStackTrace();
                if (connectCallback ! = null){
                    connectCallback.connectFailed(ex.getMessage());
                }
            }
        }
    }

    public void cancel() {
        try {
            synchronized (lock) {
                if (connected) {
                    bluetoothSocket.close();
                    connected = false;
                }
            }
        } catch (IOException e) {
        }
    }

    public void cancel2() {
        try {
            synchronized (lock) {
                bluetoothSocket.close();
                connected = false;
            }
        } catch (IOException e) {
        }
    }

}

public interface BluetoothConnectCallback {

    void connectSuccess(BluetoothSocket socket);

    void connectFailed(String errorMsg);

    void connectCancel();
}

上記に注意、BluetoothUUIDは概ね固定、connect()は接続成功率向上のためサブスレッドに配置(不明)、接続失敗はcreateRfcommSocket thisメソッドを反映する必要があるので注意、現状セルフチェックの方が接続成功率が高いです。

7. データ転送

//Get the output stream of BluetoothSocket
OutputStream outputStream = bluesocket.getOutputStream();
//then write the data to the output stream to complete the transfer
outputStream.write(data);
outputStream.flush();