Android 間での RFCOMM チャネルの Bluetooth 通信 1/2
ここでは二つの Android 端末間で、Bluetooth を用いた通信を行う方法を示します。
Bluetooth に必要なパーミッションの設定、 発見の方法、 ペアリング済みのデバイスの取得 など、 他の記事で書いた内容については、先に目を通しておくとよいと思います。
尚、念のため記載するとここのコードは Nexus 5X (Android 7.1.1) と Nexus 7 2012 (Android 5.1.1) で動作確認しました。
Bluetooth 接続概要
Bluetooth での通信は TCP/IP のソケット通信と同様に考えることができます。
接続を受け付ける「サーバー」側と、接続しにいく「クライアント」側という二つの役割があります。
全体像を図にするとおよそ次のようになります。
サーバー側の処理
上図のサーバー側の処理を切り出して説明します。
サーバー側は、BluetoothAdapter の getDefaultAdapter() メソッドで BluetoothAdapter のインスタンスを取得します。 BluetoothAdapter の listenUsingRfcommWithServiceRecord メソッドを呼び出し、サーバーソケット (BluetoothServerSocket) を作成します。
このとき、サービス名とサービスを識別するための UUID を指定します。
これにより Android の SDP (サービス発見プロトコル) サーバーに、 サービス名と UUID を元に SDP レコードが作成されます。
続いて、サーバーソケットの accept() メソッドを呼ぶとサーバーは、クライアントからの接続要求待ち状態になります。
accept() メソッドはブロッキングメソッドです。つまり、接続要求があるまで返りません。このため、accept は UI スレッドとは異なる ワーカースレッドにて呼び出す必要があります。
クライアントからの接続要求があると、要求に含まれる UUID を元に SDP レコードを探します。
指定した UUID を持つサービスが存在すれば、RFCOMM 通信チャネルが作成され、 関連付けされた Bluetooth ソケットが作成されます。
ここで accept メソッドは BluetoothSocket を返して戻ります。この BluetoothSocket でクライアントの通信を行います。
getInputStream() 及び getOutputStream() メソッドによって、それぞれ入力ストリーム、出力ストリームが取得できます。このストリームに対する入出力がクライアントのデータ通信となります。
同じ通信チャネルを複数の端末と共有しないので、サーバーソケット (BluetoothServerSocket) はクローズします。
クライアント側の処理
次はクライアント側について説明します。
クライアント側もまずは BluetoothAdapter を取得する所から始めます。BluetoothAdapter の getDefaultAdapter メソッドを呼びます。
次に、接続するサーバーデバイスを探します。あらかじめペアリングを行っているデバイスは、BluetoothAdapter の getBondedDevices メソッドで直ちに取得できます。
BluetoothDevice オブジェクトを、ペアリングデバイスリスト (Bonded リスト) もしくは発見によって取得したら、接続するサービスの UUID を指定して createRfcommSocketToServiceRecord メソッドを呼び出します。
UUID については独自のサービスであれば自前で作成した UUID を使えば OK です。 HC-06 等の Bluetooth UART アダプター等に接続する際には、 SPP (シリアルポートプロファイル) の UUID である 00001101-0000-1000-8000-00805F9B34FB を使います。
尚、認証及び暗号化通信を行わない通信チャネルを作成するときは createInsecureRfcommSocketToServiceRecord メソッドを使います。HC-05, HC-06 等はセキュアチャネルをサポートします。
さて、BluetoothSocket を取得したら、connect() メソッドで接続要求を行います。
サーバー側が起動しており、かつ指定した UUID にあたるサービスが提供されている場合、connect は成功します。connect は処理が完了するまで返らないブロッキングコールです。 失敗した場合は IOException が投げられます。
全て正常に完了したら、BluetoothSocket から取得できる I/O ストリームを用いて、サーバー側とデータ通信が可能になります。
上記を踏まえ、Android 端末間で Bluetooth 通信を行うコードを書いてみましょう。