做者:BruceZhangandroid
出處:http://blog.csdn.net/dlutbrucezhang/article/details/8955104web
一般狀況下,咱們對藍牙的操做主要有:開啓和關閉藍牙、搜索周邊設備、能被周邊設備所發現、獲取配對設備、藍牙設備間的數據傳輸。編程
藍牙設備主要分爲兩部分,一部分爲本地設備,另外一部分爲遠程設備。服務器
它所包含的方法和BluetoothAdapter同樣,再也不累述。網絡
// 獲取本地的藍牙適配器實例 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if(adapter!=null) { if(!adapter.isEnabled()) { //經過這個方法來請求打開咱們的藍牙設備 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivity(intent); } } else { System.out.println("本地設備驅動異常!"); }
對於Android查找發現藍牙設備使用BluetoothAdapter類的startDiscovery()方法就能夠執行一個異步方式獲取周邊的藍牙設備,由於是一個異步的方法因此咱們不須要考慮線程被阻塞問題,整個過程大約須要12秒時間,這時咱們能夠註冊一個 BroadcastReceiver 對象來接收查找到的藍牙設備信息,咱們經過Filter來過濾ACTION_FOUND這個 Intent動做以獲取每一個遠程設備的詳細信息,經過Intent字段EXTRA_DEVICE 和 EXTRA_CLASS能夠得到包含了每一個BluetoothDevice 對象和對象的該設備類型 BluetoothClass。多線程
實現一個本身的BroadCastReceiver類,並註冊這個類。app
private class BluetoothReciever extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); System.out.println(device.getAddress()); } } }
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND); bluetoothReceive = new BluetoothReciever(); registerReceiver(bluetoothReceive, intentFilter);
由於在註冊一個Receiver後,程序並不知道該什麼時候去回收它,因此須要咱們本身重寫Activity類的onDestroy()方法。異步
protected void onDestroy() { // TODO Auto-generated method stub unregisterReceiver(bluetoothReceive); super.onDestroy(); }
若是須要用戶確認操做,不須要獲取底層藍牙服務實例,能夠經過一個Intent來傳遞ACTION_REQUEST_DISCOVERABLE參數, 這裏經過startActivity來請求開啓。socket
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); //50這個參數表明的是藍牙設備能在多少秒內被發現 discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 50); startActivity(discoverableIntent);
配對操做呢,通常都是發現設備後,由咱們人工來進行選擇後系統自動去配對。咱們能夠經過下面的方法來得到配對的設備:ide
//經過getBondedDevices方法來獲取已經與本設備配對的設備 Set<BluetoothDevice> device= adapter.getBondedDevices(); if(device.size()>0) { for(Iterator iterator=device.iterator();iterator.hasNext();) { BluetoothDevice bluetoothDevice=(BluetoothDevice)iterator.next(); System.out.println(bluetoothDevice.getAddress()); } }
在看過前面的啓動、發現/搜索、配對這些操做後,下面來講說數據傳輸的問題。
在Android系統中,藍牙設備間的數據傳輸問題和咱們在PC上的網絡編程頗爲相似,有一端做爲Server端監聽Client端的鏈接請求,在兩者創建了鏈接後,就可使用普通的數據傳輸方式進行數據交換操做了。在這個過程當中,我須要使用到BluetoothServerSocket和BluetoothSocket兩個類來創建Server端和Client端,還須要使用到一些關於流(Stream)的知識。
能夠看到,Accept方法是一個阻塞方法,因此在進行開發的時候,通常都須要用到多線程的知識。JAVA的多線程知識,能夠在JAVA的JDK幫助文檔中查看,就單純的應用來講仍是比較簡單的。
在瞭解了這兩個類後,能夠着手來創建咱們本身的Server端和Client端了。
若是一個設備須要和兩個或多個設備鏈接時,就須要做爲一個server來傳輸,服務器端套接字在接受(accepted) 一個客戶發來的BluetoothSocket鏈接請求時做出相應的響應。服務器socket將監聽進入的鏈接請求,一旦鏈接被接受,將產生一個BluetoothSocket。
使用BluetoothAdapter類的listenUsingRfcommWithServiceRecord方法來新建一個ServerSocket。在listenUsingRfcommWithServiceRecord中有一個參數叫作UUID,UUID(Universally Unique Identifier)是一個128位的字符串ID,被用於惟一標識咱們的藍牙服務。你可使用web上的任何一款UUID產生器爲你的程序獲取一個UUID,而後使用fromString(String)初始化一個UUID。
使用ServerSocket實例的accept方法進行監聽,當監聽到帶有咱們初始化的UUID參數的鏈接請求後做出響應,鏈接成功後返回一個BluetoothSocket對象。鏈接完成後,調用close方法關閉該Socket監聽。
// Bluetooth的ServerSocket包裝類 class BluetoothServer { public BluetoothServer() throws IOException { } // 要創建一個ServerSocket對象,須要使用adapter.listenUsingRfcommWithServiceRecord方法 // UUID能夠在網上去申請 private BluetoothServerSocket serverSocket = adapter.listenUsingRfcommWithServiceRecord("myServerSocket", UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04")); BluetoothSocket socket = serverSocket.accept(); void m() throws IOException { if (socket != null) { InputStream inputStream = socket.getInputStream(); int read = -1; final byte[] bytes = new byte[1024]; for (; (read = inputStream.read(bytes)) > -1;) { final int count = read; Thread _start = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(); for (int i = 0; i < count; i++) { if (i > 0) { sb.append(' '); } String _s = Integer.toHexString(bytes[i] & 0xFF); if (_s.length() < 2) { sb.append('0'); } sb.append(_s); } System.out.println(sb.toString()); } }); _start.start(); } } } }
建立一個Client端,首先須要咱們使用BluetoothDevice的實例的createRfcommSocketToServiceRecord方法來建立一個BluetoothSocket實例。在建立的時候,須要給createRfcommSocketToServiceRecord方法傳入咱們服務端的UUID值。而後使用BluetoothSocket實例的Connect方法對Server端進行鏈接請求,當鏈接成功後,Client端和Server端的傳輸通道就被打開。最後在鏈接完成後使用該實例的close方法來關閉這個鏈接。
class BluetoothClient { BluetoothDevice device = null; //經過構造函數來傳入一個BluetoothDevice實例 public BluetoothClient(BluetoothDevice device) { this.device = device; } BluetoothSocket socket = null; void connetServer() throws IOException { Thread _clientThread = new Thread(new Runnable() { public void run() { try { //經過BluetoothDevice實例的createRfcommSocketToServiceRecord方法能夠返回一個帶有UUID的BluetoothSocket實例 socket = device.createRfcommSocketToServiceRecord(UUID.fromString("84D1319C-FBAF-644C-901A-8F091F25AF04")); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { socket.connect(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if (socket != null) { try { socket.close(); } catch (Exception e) { // TODO: handle exception } } } }); _clientThread.start(); }
getInputStream()——得到一個可讀的流,該流在鏈接不成功的狀況下依舊能夠得到,可是對其操做的話就會報IOException的異常。須要從外部獲取的數據都從該流中獲取。
getOutputStrem()——得到一個可寫的流,該流在鏈接不成功的狀況下依舊能夠得到,可是對其操做的話就會報IOException的異常。須要往外部傳輸的數據均可以寫到該流中傳輸出去。
數據傳輸的大體流程以下:
還要補充一點,因爲藍牙設備是系統設備,因此須要有相應的權限支持。在AndroidManifest.xml文件中添加上權限。
<uses-permission android:name="android.permission.BLUETOOTH"></uses-permission> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>