藍牙通信的大概步驟如下:
1,首先開啟藍牙
2,搜索可用設(shè)備
3,創(chuàng)建藍牙socket,獲取輸入輸出流
4,讀取和寫入數(shù)據(jù)
5,斷開連接關(guān)閉藍牙

首先要知道幾個類,BluetoothAdapter,BluetoothGatt,BluetoothDevice,BluetoothCattService,BluetoothCattCharacteristic。
第一個是藍牙設(shè)配器,對藍牙的操作都需要用到它,很重要,BluetoothGatt作為中央來使用和處理數(shù)據(jù),使用時有一個回調(diào)方法BluetoothGattCallback返回中央的狀態(tài)和周邊提供的數(shù)據(jù),BluetoothCattService作為周邊來提供數(shù)據(jù);BluetoothGattServerCallback返回周邊的狀態(tài)。BluetoothDevice是藍牙設(shè)備,BluetoothCattCharacteristic是藍牙設(shè)備的特征。
看著有點亂,我們來打個比喻:BluetoothDevice為學校,BluetoothGatt為學校到達某一個班級的通道,BluetoothCattService為學校的某一個班級,BluetoothCattCharacteristic為班級中的某一個學生。那么藍牙連接通信的過程就是這樣,BluetoothAdapter先找到學校(就是連接目的設(shè)備),再通過通道找到目標班級,最后從班級中找到目標學生,這個學生就是我們設(shè)備之間通信的中介,很重要,學校有唯一的MAC地址,班級有唯一的serviceUUID,學生有唯一的charactersticUUID(相當于學號),所以就是在一所學校找一個學生的問題,好了,應(yīng)該了解了吧。
藍牙通信原理介紹:?
藍牙通信和socket通信原理基本上是一致的,下面我給大家上一張圖(圖為Socket通信圖)。

藍牙客戶端Socket的與Sokcet流程是一樣的,只不過參數(shù)不同而已。如下:?
1、創(chuàng)建客戶端藍牙Sokcet?
2、創(chuàng)建連接?
3、讀寫數(shù)據(jù)?
4、關(guān)閉
服務(wù)端socket:?
1、創(chuàng)建服務(wù)端藍牙Socket?
2、綁定端口號(藍牙忽略)?
3、創(chuàng)建監(jiān)聽listen(藍牙忽略, 藍牙沒有此監(jiān)聽,而是通過whlie(true)死循環(huán)來一直監(jiān)聽的)?
4、通過accept(),如果有客戶端連接,會創(chuàng)建一個新的Socket,體現(xiàn)出并發(fā)性,可以同時與多個socket通訊)?
5、讀寫數(shù)據(jù)?
6、關(guān)閉
下面看客戶端代碼:
/**?
*Title: ConnectThread
*Description: 客戶端邏輯: 客戶端的線程,處理客戶端socket
*Company: ihaveu
@authorMaWei * @date2017/12/26?*/
public classConnectThreadextendsThread{?
?private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);
? ? /** 客戶端socket*/? ??
private final BluetoothSocket mmSoket;
? ? /** 要連接的設(shè)備*/? ??
private final BluetoothDevice mmDevice;
? ? private BluetoothAdapter mBluetoothAdapter;
? ? /** 主線程通信的Handler*/? ?
?private final Handler mHandler;
? ? /** 發(fā)送和接收數(shù)據(jù)的處理類*/? ?
?private ConnectedThread mConnectedThread;
? ? public ConnectThread(BluetoothDevice device, BluetoothAdapter bluetoothAdapter, Handler mUIhandler) {
? ? ? ? mmDevice = device;
? ? ? ? mBluetoothAdapter = bluetoothAdapter;
? ? ? ? mHandler = mUIhandler;
? ? ? ? BluetoothSocket tmp = null;
? ? ? ? try {
? ? ? ? ? ? // 創(chuàng)建客戶端Socket
? ? ? ? ? ? tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? mmSoket = tmp;
? ? }
? ? @Override? ? public void run() {
? ? ? ? super.run();
? ? ? ? // 關(guān)閉正在發(fā)現(xiàn)設(shè)備.(如果此時又在查找設(shè)備,又在發(fā)送數(shù)據(jù),會有沖突,影響傳輸效率)
? ? ? ? mBluetoothAdapter.cancelDiscovery();
? ? ? ? try {
? ? ? ? ? ? // 連接服務(wù)器
? ? ? ? ? ? mmSoket.connect();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? // 連接異常就關(guān)閉
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? mmSoket.close();
? ? ? ? ? ? } catch (IOException e1) {
? ? ? ? ? ? }
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? manageConnectedSocket(mmSoket);
? ? }
? ? private void manageConnectedSocket(BluetoothSocket mmSoket) {
? ? ? ? // 通知主線程連接上了服務(wù)端socket,更新UI
? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_CONNECTED_TO_SERVER);
? ? ? ? // 新建一個線程進行通訊,不然會發(fā)現(xiàn)線程堵塞
? ? ? ? mConnectedThread = new ConnectedThread(mmSoket,mHandler);
? ? ? ? mConnectedThread.start();
? ? }
? ? /**
? ? * 關(guān)閉當前客戶端
? ? */? ? public void cancle() {
? ? ? ? try {
? ? ? ? ? ? mmSoket.close();
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? /**? ? * 發(fā)送數(shù)據(jù)? ? * @paramdata? ? */
? ? public void sendData(byte[] data) {
? ? ? ? if(mConnectedThread != null) {
? ? ? ? ? ? mConnectedThread.write(data);
? ? ? ? }
? ? }
}
服務(wù)端代碼:
/** *
Title: AccepThread
*
Description: 服務(wù)端Socket通過accept()一直監(jiān)聽客戶端連接的線程
*
Company: ihaveu
* * @authorMaWei * @date2017/12/26 */
public classAccepThreadextendsThread{
?/** 連接的名稱*/?
?private static final String NAME = "BluetoothClass";
? ? /** UUID*/? ??
private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);
? ? /** 服務(wù)端藍牙Sokcet*/? ??
private final BluetoothServerSocket mmServerSocket;
? ? private final BluetoothAdapter mBluetoothAdapter;
? ? /** 線程中通信的更新UI的Handler*/? ??
private final Handler mHandler;
? ? /** 監(jiān)聽到有客戶端連接,新建一個線程單獨處理,不然在此線程中會堵塞*/? ?
?private ConnectedThread mConnectedThread;
? ? public AccepThread(BluetoothAdapter adapter, Handler handler) throws IOException {
? ? ? ? mBluetoothAdapter = adapter;
? ? ? ? this.mHandler = handler;
? ? ? ? // 獲取服務(wù)端藍牙socket? ? ? ?
?mmServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
? ? }
? ? @Override? ? public void run() {
? ? ? ? super.run();
? ? ? ? // 連接的客戶端soacket
? ? ? ? BluetoothSocket socket = null;
? ? ? ? // 服務(wù)端是不退出的,要一直監(jiān)聽連接進來的客戶端,所以是死循環(huán)
? ? ? ? while (true){
? ? ? ? ? ? // 通知主線程更新UI,客戶端開始監(jiān)聽
? ? ? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_START_LISTENING);
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? // 獲取連接的客戶端socket
? ? ? ? ? ? ? ? socket =? mmServerSocket.accept();
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? // 通知主線程更新UI, 獲取異常
? ? ? ? ? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_ERROR);
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? // 服務(wù)端退出一直監(jiān)聽線程
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? ? ? if(socket != null) {
? ? ? ? ? ? ? ? // 管理連接的客戶端socket
? ? ? ? ? ? ? ? manageConnectSocket(socket);
? ? ? ? ? ? ? ? // 這里應(yīng)該是手動斷開,案例應(yīng)該是只保證連接一個客戶端,所以連接完以后,關(guān)閉了服務(wù)端socket
? ? ? ? ? ? ? ? try {
//? ? ? ? ? ? ? ? ? ? mmServerSocket.close();
//? ? ? ? ? ? ? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
//? ? ? ? ? ? ? ? } catch (IOException e) {
//? ? ? ? ? ? ? ? ? ? e.printStackTrace();//? ? ? ? ? ? ? ? }? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? /**? ? * 管理連接的客戶端socket? ??
?* @paramsocket? ? */? ??
private void manageConnectSocket(BluetoothSocket socket) {
? ? ? ? // 只支持同時處理一個連接
? ? ? ? // mConnectedThread不為空,踢掉之前的客戶端
? ? ? ? if(mConnectedThread != null) {
? ? ? ? ? ? mConnectedThread.cancle();
? ? ? ? }
? ? ? ? // 主線程更新UI,連接到了一個客戶端
? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_GOT_A_CLINET);
? ? ? ? // 新建一個線程,處理客戶端發(fā)來的數(shù)據(jù)
? ? ? ? mConnectedThread = new ConnectedThread(socket, mHandler);
? ? ? ? mConnectedThread.start();
? ? }
? ? /**
? ? * 斷開服務(wù)端,結(jié)束監(jiān)聽
? ? */? ? public void cancle() {
? ? ? ? try {
? ? ? ? ? ? mmServerSocket.close();
? ? ? ? ? ? mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? /**? ? * 發(fā)送數(shù)據(jù)
? ? * @paramdata? ? */? ??
?public void sendData(byte[] data){
? ? ? ? if(mConnectedThread != null) {
? ? ? ? ? ? mConnectedThread.write(data);
? ? ? ? }
? ? }
}
下面看一個共同通訊處理類:
/** *
Title: ConnectedThread
*Description: 客戶端和服務(wù)端 處理 發(fā)送數(shù)據(jù) 和獲取數(shù)據(jù)
*/
publicclassConnectedThreadextendsThread{
/** 當前連接的客戶端BluetoothSocket*/
privatefinalBluetoothSocket mmSokcet;
/** 讀取數(shù)據(jù)流*/
privatefinalInputStream mmInputStream;
/** 發(fā)送數(shù)據(jù)流*/
privatefinalOutputStream mmOutputStream;
/** 與主線程通信Handler*/
privateHandler mHandler;
privateString TAG ="ConnectedThread";
publicConnectedThread(BluetoothSocket socket,Handler handler) {
?mmSokcet = socket; mHandler = handler;
?InputStream tmpIn =null;
?OutputStream tmpOut =null;
try{?
?????????tmpIn = socket.getInputStream();
?????????tmpOut = socket.getOutputStream();?
?}catch(IOException e) {
?e.printStackTrace();
?}
?mmInputStream = tmpIn;?
?mmOutputStream = tmpOut;
?}
@Overridepublicvoidrun() {
super.run();
????????byte[] buffer =newbyte[1024];
????????while(true) {
????????try{
// 讀取數(shù)據(jù)
????????????????intbytes = mmInputStream.read(buffer);
? ? ? ? ? ?if(bytes >0) {
?????????String data =newString(buffer,0,bytes,"utf-8");
????????// 把數(shù)據(jù)發(fā)送到主線程, 此處還可以用廣播
????????Message message = mHandler.obtainMessage(Constant.MSG_GOT_DATA,data);?
?????????mHandler.sendMessage(message);?
}
?????????Log.d(TAG,"messge size :"+ bytes);
????????????????}catch(IOException e)
?????????????????{ e.printStackTrace();
?????????????}?
?????????}?
?}
// 踢掉當前客戶端
publicvoidcancle() {
????????????????try{?
????????????????????mmSokcet.close();
? ? ????????? }catch(IOException e) {?
?????????????e.printStackTrace();?
?????????}?
?}
/** * 服務(wù)端發(fā)送數(shù)據(jù) *?
@paramdata */
publicvoidwrite(byte[] data) {
????????????????????try{?
?????????????????????????????????mmOutputStream.write(data);
?????????????????????}catch(IOException e) {?
?????????????????????e.printStackTrace();?
?????????????????}?
? ? ? ? ? ?}
}