Bluetooth通信の実装|Android開発
AndroidアプリでBluetooth通信を実装する方法です。
Bluetooth接続では、受信側と送信側で同一のUUIDを使用します。下記はシリアルポートプロファイル(SPP)でデータを送信するBluetooth機器との通信サンプルです。
前提条件
- 接続デバイスとはペアリング済みにしておきます
- AndroidManifest.xmlに以下の権限を追加しておきます
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
Bluetooth 通信手順
BluetoothAdapter
を取得しますimport android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; BluetoothAdapter mBluetoothAdapter; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { // エラー: Bluetooth なし. }
- ペアリング済みのデバイス一覧を取得します
getBondedDevices()
はエラー時にnull
を返すためエラー判定が必要です - 取得したデバイス一覧から接続デバイスを検索します
String deviceName = "接続デバイス名"; // 対象 Bluetooth デバイスのシリアルポートプロファイルに接続する. SerialPortProfileConnectThread connectTread = null; Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); // getBondedDevices() はエラー時に null を返すのでチェックが必要. if (pairedDevices != null) { for (BluetoothDevice device : pairedDevices) { if (deviceName.equals(device.getName())) { connectTread = new SerialPortProfileConnectThread(device); break; } } } if (connectTread == null) { // エラー: 接続デバイスなし. }
SerialPortProfileConnectThread
クラスはシリアルポートプロファイルを使ってBluetooth接続するクラスです。
実際の接続処理は親のBluetoothConnectThread
クラスで実装しています。import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import java.util.UUID; public class BluetoothConnectThread extends Thread { protected String TAG = "BluetoothConnectThread"; protected final BluetoothSocket mmSocket; public BluetoothSocket getSocket() { return mmSocket; } public BluetoothConnectThread(BluetoothDevice device, UUID uuid) { BluetoothSocket tmp = null; try { tmp = device.createRfcommSocketToServiceRecord(uuid); } catch (IOException e) { e.printStackTrace(); // NOP. } mmSocket = tmp; } public void run() { if (mmSocket == null) { return; } try { mmSocket.connect(); } catch (IOException e) { e.printStackTrace(); try { mmSocket.close(); } catch (IOException e1) { e1.printStackTrace(); } return; } Log.i(TAG, "Bluetooth connecting."); } }
import android.bluetooth.BluetoothDevice; import java.util.UUID; public class SerialPortProfileConnectThread extends BluetoothConnectThread { // "00001101-0000-1000-8000-00805f9b34fb" = SPP (シリアルポートプロファイル) の UUID. public static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); public SerialPortProfileConnectThread(BluetoothDevice device) { super(device, SPP_UUID); TAG = "SerialPortProfileConnectThread"; } }
- 接続前に Bluetooth デバイスの検索を停止します
mBluetoothAdapter.cancelDiscovery();
SerialPortProfileConnectThread
を開始し、ソケットを接続しますconnectTread.start(); // 接続完了を待つ. // 下記は sleep() を使用した暫定処理です. try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
接続が完了したら、このスレッドは終了します。
Bluetooth 接続完了前に次項のBluetoothReceiveTask
でデータ読み出しを行うと例外が発生します。- データ受信用のスレッドを生成・実行します
この時、接続完了したソケットを使用しますprivate BluetoothReceiveTask mReceiveTask; mReceiveTask = new BluetoothReceiveTask(connectTread.getSocket()); mReceiveTask.start();
BluetoothReceiveTask
では接続機器の仕様に合わせて受信したデータを処理します。import android.bluetooth.BluetoothSocket; import java.io.IOException; import java.io.InputStream; class BluetoothReceiveTask extends Thread { public static final String TAG = "BluetoothReceiveTask"; protected InputStream mInputStream; protected BluetoothSocket mSocket; protected volatile boolean mIsCancel; public BluetoothReceiveTask(BluetoothSocket socket) { mIsCancel = false; mSocket = null; mInputStream = null; if (socket == null) { Log.e(TAG, "parameter socket is null."); return; } try { mInputStream = socket.getInputStream(); mSocket = socket; } catch (IOException e) { e.printStackTrace(); } } public void run() { byte[] buffer = new byte[64]; int readSize; Log.i(TAG, "start read task."); while (mInputStream != null) { if (mIsCancel) { break; } try { readSize = mInputStream.read(buffer); if (readSize == 64) { // 処理. } else { Log.e(TAG, "NG " + readSize + "byte"); } Thread.sleep(0); } catch (IOException e) { e.printStackTrace(); break; } catch (InterruptedException e) { Log.e(TAG, "InterruptedException!!"); // NOP. break; } } Log.i(TAG, "exit read task."); } public void cancel() { mIsCancel = true; } public void finish() { if (mSocket == null) { return; } try { mSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }
以上で Bluetooth 機器とシリアルポートプロファイルを使ったデータ通信が可能です。
Bluetooth通信終了処理
Bluetooth通信終了時はデータ受信のスレッドを終了させます。
if (mReceiveTask != null) {
mReceiveTask.cancel();
}
// キャンセル完了を待つ処理など.
if (mReceiveTask != null) {
mReceiveTask.finish();
mReceiveTask = null;
}