やりかた
- BluetoothAdapter.getDefaultAdapter()を使って、アダプタを得る。
- アダプタにisEnabled()を呼び出して、Bluetooth設定が有効なことを確認する。
- インテントを出してユーザーに有効にしてもらうことも可能だけど、ここではしない。
- アダプタにgetBondedDevices()を呼び出して、ペアリングされたデバイスの一覧を得る。
- 探索してペアリングされたデバイス以外から探すことも可能だけど、ここではしない。
- デバイスのプロパティを見て、欲しいデバイスを探し出す。
- 本当はUI出して選んでもらうのがいいと思うけど、ここではしない。
- 欲しいデバイスにcreateRfcommSocketToServiceRecord()を呼び、必要なサービスのBluetoothSocketを得る。
- SPP (Serial Port Profile)のUUID(00001101-0000-1000-8000-00805F9B34FB)を渡す必要があるので、定数定義しておく。
- BluetoothSocketにconnect()を呼ぶ。
- BluetoothSocketにgetInputStream() / getOutputStream()を呼んで、適当に操作する。
- BluetoothSocketにclose()を呼ぶ。
このへんのページのほうが詳しいので、「ここではしない」ことがしたければこちらを参考に...
- ソフトウェア技術ドキュメントを勝手に翻訳 - Android 開発ガイド > フレームワークトピック > h. Bluetooth
- Androidアプリ開発 ~Bluetooth SPP による無線通信~
罠
罠1) getDefaultAdapter()は、Gingerbread (2.3)では、UIスレッドでしか呼べない。
いかにもUIなんか関係なさげなメソッドなのに、Handlerが取れなくて例外が出る。4.1では起きないらしいけど、2.3じゃダメだと…ねぇ?
cf: https://groups.google.com/forum/#!msg/android-developers/wFbD5V2DWRc/gv0VF4Y6ICwJ
罠2) BluetoothSocket#connect()は「Service discovery failed」でたまに失敗する
Webを見るとよくある話のようで、ウエイトを入れたり、アダプタにcancelDiscoveryをさせろとか、リフレクションで中のメソッドを呼び出せとか、いろいろある。どうにもすっきりしないし、時間がかかってNGなので、何かのタイムアウトなんだと思う。なので、とりあえずリトライすることにした(リトライの条件はもう少ししっかりしたほうがいいかも)cf: http://stackoverflow.com/questions/3397071/service-discovery-failed-exception-using-bluetooth-on-android
コード
ASCIIで1行書き込むと、1行返ってくる感じのサンプル。本当はすべてUIじゃないスレッドの中でのコードにしたかったのだけど、上述の罠があって、getDefaultAdapter()だけUIスレッドで渡すようにしているので、コピペでは現実的に動かない。
close()漏れとかあるので、ためしに書いてみるてな感じの参考程度に。sendLogMessage()は、適当なTextViewにログを出すためのメソッドなので、Log.dとかでよいです。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final String command = "HELO\n"; | |
final UUID sppUuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); | |
BluetoothAdapter.getDefaultAdapter(); | |
if (btAdapter == null) { | |
sendLogMessage("Bluetooth adapter is not available."); | |
return; | |
} | |
sendLogMessage("Bluetooth adapter is found."); | |
if (!btAdapter.isEnabled()) { | |
sendLogMessage("Bluetooth is disabled. Check configuration."); | |
return; | |
} | |
sendLogMessage("Bluetooth is enabled."); | |
BluetoothDevice btDevice = null; | |
Set<BluetoothDevice> bondedDevices = btAdapter.getBondedDevices(); | |
for (BluetoothDevice dev : bondedDevices) { | |
sendLogMessage("Paired device: " + dev.getName() + " (" + dev.getAddress() + ")"); | |
if (dev.getName().equals("MyDeviceName")) { | |
btDevice = dev; | |
} | |
} | |
if (btDevice == null) { | |
sendLogMessage("Target Bluetooth device is not found."); | |
return; | |
} | |
sendLogMessage("Target Bluetooth device is found."); | |
BluetoothSocket btSocket; | |
try { | |
btSocket = btDevice.createRfcommSocketToServiceRecord(sppUuid); | |
} catch (IOException ex) { | |
sendLogMessage("Failed to create RfComm socket: " + ex.toString()); | |
return; | |
} | |
sendLogMessage("Created a bluetooth socket."); | |
for (int i = 0; ; i++) { | |
try { | |
btSocket.connect(); | |
} catch (IOException ex) { | |
if (i < 5) { | |
sendLogMessage("Failed to connect. Retrying: " + ex.toString()); | |
continue; | |
} | |
sendLogMessage("Failed to connect: " + ex.toString()); | |
return; | |
} | |
break; | |
} | |
sendLogMessage("Connected to the bluetooth socket."); | |
try { | |
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(btSocket.getOutputStream(), "ASCII")); | |
writer.write(command); | |
writer.flush(); | |
} catch (IOException ex) { | |
sendLogMessage("Failed to write a command: " + ex.toString()); | |
return; | |
} | |
sendLogMessage("Command is sent: " + command); | |
String output; | |
try { | |
BufferedReader reader = new BufferedReader(new InputStreamReader(btSocket.getInputStream(), "ASCII")); | |
output = reader.readLine(); | |
} catch (IOException ex) { | |
sendLogMessage("Failed to write a command: " + ex.toString()); | |
return; | |
} | |
sendLogMessage("Result: " + output); | |
try { | |
btSocket.close(); | |
} catch (IOException ex) { | |
sendLogMessage("Failed to close the bluetooth socket."); | |
return; | |
} | |
sendLogMessage("Closed the bluetooth socket."); |
0 件のコメント:
コメントを投稿