一:概要: android
Android提供了Buletooth的API ,經過API 咱們能夠進行以下的一些操做:服務器
1.掃描其餘的藍牙設備app
2.查詢能配對的藍牙設備異步
3.創建RFCOMM 通道socket
4.鏈接其餘的藍牙設備學習
5.傳輸數據this
6.管理多個鏈接spa
學習和使用藍牙應該以這樣的步驟: 配置藍牙權限---->設置本機藍牙適配器---->發現藍牙設備----->進行配對,鏈接------>利用Socket進行通訊線程
須要熟悉的一些類:如圖code
二詳細步驟:
1.設置藍牙權限
爲了可以使用藍牙的功能必須在清單文件中進行權限的聲明:(必須至少聲明如下權限中 的一個)
BULETOOTH/BULETOOTH_ADMIN:
<uses-permission android:name="android.permission.BLUETOOTH" />//容許應用程序鏈接到已配對的藍牙設備(遠端藍牙,非本機藍牙) <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />//容許應用程序搜索而且配對藍牙設備。
注意:在使用BULETOOTH_ADMIN權限時必須配置BULETOOTH的權限
2.配置本機的藍牙模塊
在這裏須要掌握 BuletoothAdapter的類:
在使用藍牙的功能時必須先檢查本機的設備是否有藍牙的功能,若是不支持那麼白搭,若是支持就要檢查藍牙功能是否激活,若是沒激活咱們要提醒用戶開啓藍牙功能
那麼此時就須要BuletoothAdapter的相關方法。
step 1: 檢查是否支持藍牙
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//getDefaultAdapter是一個static的方法,能夠直接類名調用
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
}//==null,表示該設備並不支持藍牙
step2: 判斷是否激活藍牙
if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }
若是沒有激活,那麼啓動服務進行激活,此時會彈出下面的圖片:
另外: 咱們還能夠對藍牙的狀態改變進行監聽,當用戶的藍牙狀態改變時會發送一條廣播告訴系統本身的狀態發生了改變:
listen ACTION_STATE_CHANGED
broadcast Intent, which the system will broadcast whenever the Bluetooth state has changed.
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); //直接打開系統的藍牙設置面板 Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, 0x1); //直接打開藍牙 adapter.enable(); //關閉藍牙 adapter.disable(); //打開本機的藍牙發現功能(默認打開120秒,能夠將時間最多延長至300秒) discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);//設置持續時間(最多300秒)Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
3.搜索藍牙設備
調用startDiscovery()
來發現藍牙設備:startDiscovery()方法是一個異步方法,調用後會當即返回。該方法會進行對其餘藍牙設備的搜索,該過程會持續12秒。
該方法調用後,搜索過程其實是在一個System Service中進行的,因此能夠調用cancelDiscovery()方法來中止搜索(該方法能夠在未執行discovery請求時調用)。
註冊監聽:
在執行Discovery的方法時,系統會發出三個廣播:開始搜素,結束搜素和找到設備。對這些廣播進行監聽能夠實現一些功能。
通常監聽較多的是找到了設備:
ACTION_FOUND:找到設備,這個Intent中包含兩個extra fields:EXTRA_DEVICE和EXTRA_CLASS,分別包含BluetooDevice和BluetoothClass。
接下來看一個例子:監聽當發現了一個設備的時候進行某些動做:
// 建立一個接收ACTION_FOUND廣播的BroadcastReceiver private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // 發現設備 if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 從Intent中獲取設備對象 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 將設備名稱和地址放入array adapter,以便在ListView中顯示 mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } }; // 註冊BroadcastReceiver IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // 不要忘了以後解除綁定
Caution: Performing device discovery is a heavy procedure for the Bluetooth adapter and will consume a lot of its resources. Once you have found a device to connect, be certain that you always stop discovery with cancelDiscovery()
before attempting a connection. Also, if you already hold a connection with a device, then performing discovery can significantly reduce the bandwidth available for the connection, so you should not perform discovery while connected.
注意:爲了節省資源,當找到了要鏈接的設備務必取消查找。調用cancelDiscovery()。
固然,咱們還能夠調用一些方法使得本身的藍牙設備可以被其餘設備發現:代碼以下
Intent discoverableIntent = newIntent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
此時,系統會彈出下面的對話框供用戶進行選擇:
4.鏈接設備,並用Socket通訊
欲創建鏈接必須同時實現客戶端和服務器端的socket。由於一個手機終端其實即扮演者服務器端的角色也扮演着客戶端的角色,涉及到了收發數據。
當兩個設備在同一個RFCOMM channel下分別擁有一個鏈接的BluetoothSocket,這兩個設備才能夠說是創建了鏈接。注意瞭解RFCOMM。
服務器設備與客戶端設備獲取BluetoothSocket的途徑是不一樣的。服務器設備是經過accepted一個incoming connection來獲取的,而客戶端設備則是經過打開一個到服務 器的RFCOMM channel來獲取的。
做爲一個server:
基本步驟:
1.得到serversocket對象:
2.開啓accept:
3.close():
實現代碼以下:
private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { // Use a temporary object that is later assigned to mmServerSocket, // because mmServerSocket is final BluetoothServerSocket tmp = null; try { // MY_UUID is the app's UUID string, also used by the client code tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
//step 1:得到serverSocket對象, } catch (IOException e) { } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; // Keep listening until exception occurs or a socket is returned while (true) { try { socket = mmServerSocket.accept();
//step:創建鏈接得到socket對象
//注意:在調用accept方法後就創建的鏈接不須要再調用connect的方法了 } catch (IOException e) { break; } // If a connection was accepted if (socket != null) { // Do work to manage the connection (in a separate thread) manageConnectedSocket(socket);
//注意這個方法,應用程序將啓動傳輸數據的線程 mmServerSocket.close();
//step3 :用完資源關閉 break; } } } /** Will cancel the listening socket, and cause the thread to finish */ public void cancel() { try { mmServerSocket.close(); } catch (IOException e) { } } }
做爲一個client:
實現步驟:
step 1 :獲取一個socket對象
step 2 :發起鏈接,調用connect();
step 3:使用完關閉資源.close()
注意:在發起鏈接的時候,保證設備已經中止了discovery(),由於該操做會佔用系統不少資源
實現代碼:
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { // Use a temporary object that is later assigned to mmSocket, // because mmSocket is final BluetoothSocket tmp = null; mmDevice = device; // Get a BluetoothSocket to connect with the given BluetoothDevice try { // MY_UUID is the app's UUID string, also used by the server code tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { } mmSocket = tmp; } public void run() { // Cancel discovery because it will slow down the connection mBluetoothAdapter.cancelDiscovery(); try { // Connect the device through the socket. This will block // until it succeeds or throws an exception mmSocket.connect(); } catch (IOException connectException) { // Unable to connect; close the socket and get out try { mmSocket.close(); } catch (IOException closeException) { } return; } // Do work to manage the connection (in a separate thread) manageConnectedSocket(mmSocket); } /** Will cancel an in-progress connection, and close the socket */ public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }
5.管理藍牙鏈接,進行數據的通訊
當得到了鏈接以後,咱們即可以開始傳輸數據,傳輸數據的通常步驟以下:
step 1 :打開輸入輸出流:InputStream -->getInputStream() . OutputStream --->getOutputStream().
step 2 : 經過字節流來讀取/寫入數據:調用write(byte[])/read(byte[]).
注意:創建專用的線程進行數據的讀寫操做,以防堵塞。相對於write操做,read更容易堵塞。
實現代碼
private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the input and output streams, using temp objects because // member streams are final try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { byte[] buffer = new byte[1024]; // buffer store for the stream int bytes; // bytes returned from read() // Keep listening to the InputStream until an exception occurs while (true) { try { // Read from the InputStream bytes = mmInStream.read(buffer); // Send the obtained bytes to the UI Activity mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer) .sendToTarget(); } catch (IOException e) { break; } } } /* Call this from the main Activity to send data to the remote device */ public void write(byte[] bytes) { try { mmOutStream.write(bytes); } catch (IOException e) { } } /* Call this from the main Activity to shutdown the connection */ public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }