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 通信手順

  1. BluetoothAdapterを取得します
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;

BluetoothAdapter mBluetoothAdapter;

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
    // エラー: Bluetooth なし.
}
  1. ペアリング済みのデバイス一覧を取得します
    getBondedDevices()はエラー時にnullを返すためエラー判定が必要です
  2. 取得したデバイス一覧から接続デバイスを検索します
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";
    }
}
  1. 接続前に Bluetooth デバイスの検索を停止します
mBluetoothAdapter.cancelDiscovery();
  1. SerialPortProfileConnectThreadを開始し、ソケットを接続します
connectTread.start();

// 接続完了を待つ.
// 下記は sleep() を使用した暫定処理です.
try {
    Thread.sleep(2000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
接続が完了したら、このスレッドは終了します。
Bluetooth 接続完了前に次項のBluetoothReceiveTaskでデータ読み出しを行うと例外が発生します。
  1. データ受信用のスレッドを生成・実行します
    この時、接続完了したソケットを使用します
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;
}
このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

関連コンテンツ

スポンサードリンク

Comment

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