昨日、「【Java】Android端末でBluethoothデバイスを検出する方法」という記事を投稿しましたが、今日はその続きで、検出した Bluetooth デバイスと Android 端末を接続する方法についてです。
ただし、実はまだ動いていません…。
今回参考にさせていただいた記事はこちらから。
03.Bluetoothデバイスとの接続・切断の処理を作る
https://www.hiramine.com/programming/bluetoothcommunicator/03_connect_disconnect.htmlAndroidからBluetooth機器にSPP (Serial Port Profile) で接続する|d.sunnyone.org
http://d.sunnyone.org/2013/09/androidbluetoothspp-serial-port-profile.html
実装にはまず、BluetoothService
という Class を定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | static public class BluetoothService { // 定数(Bluetooth UUID) private static final UUID UUID_SPP = UUID.fromString( "00001101-0000-1000-8000-00805F9B34FB" ); // 定数 static final int MESSAGE_STATECHANGE = 1 ; static final int STATE_NONE = 0 ; static final int STATE_CONNECT_START = 1 ; static final int STATE_CONNECT_FAILED = 2 ; static final int STATE_CONNECTED = 3 ; static final int STATE_CONNECTION_LOST = 4 ; static final int STATE_DISCONNECT_START = 5 ; static final int STATE_DISCONNECTED = 6 ; // メンバー変数 private int mState; private ConnectionThread mConnectionThread; private Handler mHandler; // 接続時処理用のスレッド private class ConnectionThread extends Thread { private BluetoothSocket mBluetoothSocket; // コンストラクタ ConnectionThread(BluetoothDevice bluetoothdevice) { try { // mBluetoothSocket = bluetoothdevice.createRfcommSocketToServiceRecord(UUID_SPP); mBluetoothSocket = bluetoothdevice.createInsecureRfcommSocketToServiceRecord(UUID_SPP); } catch ( IOException e ) { Log.e( "BluetoothService" , "failed : bluetoothdevice.createRfcommSocketToServiceRecord( UUID_SPP )" , e ); } } // 処理 public void run() { while ( STATE_DISCONNECTED != mState ) { switch ( mState ) { case STATE_NONE: break ; case STATE_CONNECT_START: // 接続開始 for ( int i = 0 ; ; i++) { try { mBluetoothSocket.connect(); } catch (IOException ex) { if (i < 5 ) { Log.d( "BluetoothService" , "Failed to connect. Retrying: " + ex.toString()); continue ; } Log.d( "BluetoothService" , "Failed to connect: " + ex.toString()); setState(STATE_DISCONNECT_START); return ; } break ; } // 接続成功 setState( STATE_CONNECTED ); break ; case STATE_CONNECT_FAILED: // 接続失敗 Log.d( "BluetoothService" , "STATE_CONNECT_FAILED" ); // 接続失敗時の処理の実体は、cancel()。 break ; case STATE_CONNECTED: // 接続済み(Bluetoothデバイスから送信されるデータ受信) break ; case STATE_CONNECTION_LOST: // 接続ロスト // 接続ロスト時の処理の実体は、cancel()。 break ; case STATE_DISCONNECT_START: // 切断開始 // 切断開始時の処理の実体は、cancel()。 break ; case STATE_DISCONNECTED: // 切断完了 // whileの条件式により、STATE_DISCONNECTEDの場合は、whileを抜けるので、このケース分岐は無意味。 break ; } } synchronized ( BluetoothService. this ) { // 親クラスが保持する自スレッドオブジェクトの解放(自分自身の解放) mConnectionThread = null ; } } // キャンセル(接続を終了する。ステータスをSTATE_DISCONNECTEDにすることによってスレッドも終了する) void cancel() { try { mBluetoothSocket.close(); } catch ( IOException e ) { Log.e( "BluetoothService" , "Failed : mBluetoothSocket.close()" , e ); } setState( STATE_DISCONNECTED ); } } // コンストラクタ BluetoothService(Context context, Handler handler, BluetoothDevice device) { mHandler = handler; mState = STATE_NONE; // 接続時処理用スレッドの作成と開始 mConnectionThread = new ConnectionThread(device); mConnectionThread.start(); } // ステータス設定 private synchronized void setState( int state ) { mState = state; mHandler.obtainMessage( MESSAGE_STATECHANGE, state, - 1 ).sendToTarget(); } // 接続開始時の処理 synchronized void connect() { if ( STATE_NONE != mState ) { // 1つのBluetoothServiceオブジェクトに対して、connect()は1回だけ呼べる。 // 2回目以降の呼び出しは、処理しない。 return ; } // ステータス設定 setState( STATE_CONNECT_START ); } // 接続切断時の処理 synchronized void disconnect() { if ( STATE_CONNECTED != mState ) { // 接続中以外は、処理しない。 return ; } // ステータス設定 setState( STATE_DISCONNECT_START ); mConnectionThread.cancel(); } } |
この関数内で、BluetoothSocket
の設定から接続時の処理などを指定します。
次に、BluetoothService
から情報を取得するためのハンドラを定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // Bluetoothサービスから情報を取得するハンドラ @SuppressLint ( "HandlerLeak" ) private final Handler mHandler = new Handler() { // ハンドルメッセージ // UIスレッドの処理なので、UI処理について、runOnUiThread対応は、不要。 @Override public void handleMessage( Message msg ) { if (msg.what == BluetoothService.MESSAGE_STATECHANGE) { switch (msg.arg1) { case BluetoothService.STATE_NONE: // 未接続 break ; case BluetoothService.STATE_CONNECT_START: // 接続開始 Log.d( "MainActivity" , "STATE_CONNECT_START" ); break ; case BluetoothService.STATE_CONNECT_FAILED: // 接続失敗 Toast.makeText(MainActivity. this , "Failed to connect to the device." , Toast.LENGTH_SHORT).show(); Log.d( "MainActivity" , "STATE_CONNECT_FAILED" ); break ; case BluetoothService.STATE_CONNECTED: // 接続完了 Log.d( "MainActivity" , "STATE_CONNECTED" ); break ; case BluetoothService.STATE_CONNECTION_LOST: // 接続ロスト //Toast.makeText( MainActivity.this, "Lost connection to the device.", Toast.LENGTH_SHORT ).show(); break ; case BluetoothService.STATE_DISCONNECT_START: break ; case BluetoothService.STATE_DISCONNECTED: // 切断完了 mBtAdapter = null ; // BluetoothServiceオブジェクトの解放 break ; } } } }; |
なお、こちらもサンプルコードからほぼそのままコピーしてきたものですが、ボタンの無効化などの一部不要な処理を削除しておりますので、ご注意ください。
そして、デバイスと接続/切断するための関数を定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 端末と接続 private void connectDevice(BluetoothDevice device) { Log.d( "MainActivity" , "device.name : " +device.getName()+ ", device.address : " +device.getAddress()); if ( null != mBluetoothService ) { // mBluetoothServiceがnullでないなら接続済みか、接続中。 return ; } // 接続 BluetoothDevice connectDevice = mBtAdapter.getRemoteDevice(device.getAddress()); mBluetoothService = new BluetoothService( this , mHandler, connectDevice); mBluetoothService.connect(); } // 端末との接続を切断 private void disconnectDevice() { if ( null == mBtAdapter ) { // mBluetoothServiceがnullなら切断済みか、切断中。 return ; } // 切断 mBluetoothService.disconnect(); mBluetoothService = null ; } |
なお、これらを追加すると恐らく変数などの定義でエラーが発生するため、onCreate
よりも上の階層で下記を定義してください。
1 | private BluetoothService mBluetoothService; |
あとは任意のタイミングで、connectDevice(BluetoothDevice)
を呼び出せば、接続処理が実行されます。
私は、デバイスが見つかったタイミングで実行しています。
そのタイミングでなら、デバイス情報も取得できますしね。
…が、こちらを実行すると、java.io.IOException: read failed, socket might closed or timeout, read ret: -1
というエラーが発生しました…。
ソケットが閉じているか、接続にかかる時間が長すぎてタイムアウトしているようですが、どう直せばいいのかまだわかっていません。
エラーメッセージで検索しているのですが、有益な記事にはたどり着けずにいます。
UUID が悪さをしているのかもしれませんので、このあたりから攻め直してみたいと思います!
以上、まだ完成していませんが、Android 端末と Bluetooth デバイスを接続する方法(途中)でした。
解決方法が分かったら、またまとめたいと思います。