一.藍牙API
與藍牙開發(fā)主要的相關(guān)類是以下四個
BluetoothAdapter
字面上則理解為藍牙適配器鱼冀,打開藍牙蒋腮,關(guān)閉藍牙割择,搜索設(shè)備,獲取藍牙Socket連接都是通過這個類來實現(xiàn)的冒萄。對應(yīng)的方法就有
enable():用來打開藍牙臊岸,一般在5.0后的話則會出現(xiàn)彈框提示是否開啟藍牙,其他則沒有提示宦言,也可以調(diào)用來進行彈窗打開
Intent intent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);? ? startActivity(intent );
disable():關(guān)閉藍牙
getDefaultAdapter():獲取藍牙適配器BluetoothAdapter扇单,只有這個方法來獲取
getAddress():獲取本地藍牙的MAC地址商模,這個則是每一個藍牙設(shè)備的唯一
getName():獲取本地藍牙的名稱
getRemoteDevice(String address):獲取藍牙地址獲取到遠程的設(shè)備
startDiscovery():開啟藍牙設(shè)備搜索
cancelDiscovery():關(guān)閉掃描
listenUsingRfcommWithServiceRecord(serverSocketName,UUID):獲取BluetoothServerSocket
BluetoothDevice
代表一個藍牙設(shè)備
createRfcommSocketToServiceRecord(UUIDuuid):根據(jù)UUID創(chuàng)建并返回一個BluetoothSocket
getName():獲取藍牙設(shè)備名稱
getAddress():獲取藍牙的MAC地址
BluetoothServerSocket:類似于ServerSocket奠旺,方法都差不多,可以說藍牙之間的通訊跟Socket相似施流。這個相當(dāng)于服務(wù)器Socket
accept():這個方法會阻塞响疚,直到連接建立,用來監(jiān)聽連接
close():關(guān)閉socket連接
BluetoothSocket:相當(dāng)于客戶端Socket
connect():用來向服務(wù)器BluetoothServerSocket發(fā)起連接
getInputStream():獲取輸入流
getOutputStream():獲取輸出流
close():關(guān)閉連接
getRemoteDevice():獲取這個Socket連接的遠程設(shè)備
二.搜索藍牙設(shè)備
知道對應(yīng)API后就可以進行對應(yīng)的藍牙開發(fā)瞪醋,這里以獲取藍牙設(shè)備為例子
1.獲取本地藍牙適配器
? ? ? BluetoothAdapter
mAdapter= BluetoothAdapter.getDefaultAdapter();
2.打開藍牙
if(!mAdapter.isEnabled()){//彈出對話框提示用戶是后打開Intent enabler =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enabler, REQUEST_ENABLE);//不做提示忿晕,強行打開// mAdapter.enable();
}
3.搜索設(shè)備
mAdapter.startDiscovery();//開啟搜索
搜索設(shè)備的回調(diào)則需要通過注冊廣播的形式來獲取
//發(fā)現(xiàn)設(shè)備的ActionIntentFilter filter =newIntentFilter(BluetoothDevice.ACTION_FOUND);? registerReceiver(mReceiver, filter);//設(shè)備搜索完畢的actionfilter =newIntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);? registerReceiver(mReceiver, filter);
定義廣播
BroadcastReceiver mReceiver =newBroadcastReceiver() {publicvoidonReceive(Context context, Intent intent){? ? ? ? ? String action = intent.getAction();//當(dāng)掃描到設(shè)備的時候if(BluetoothDevice.ACTION_FOUND.equals(action)) {// 獲取設(shè)備對象BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//提取強度信息intrssi = intent.getExtras().getShort(BluetoothDevice.EXTRA_RSSI);? ? ? ? ? ? Log.e(TAG, device.getName() +"\n"+ device.getAddress() +"\n強度:"+ rssi);? ? ? ? ? ? ? ? ? }//搜索完成elseif(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {? ? ? ? ? ? ? Log.e(TAG,"onReceive: 搜索完成");? ? ? ? }? ? }? };
之后就可以進行個人的一些操作
三.藍牙聊天的實現(xiàn)
要實現(xiàn)藍牙聊天則涉及到藍牙之間的傳輸通信,前面也說到了银受,這里肯定就是用到BluetoothServerSocket以及BluetoothSocket践盼。
藍牙傳輸通信相當(dāng)于服務(wù)器端與客戶端之間的通信,只不過不同是這里每一個藍牙設(shè)備本身自己既充當(dāng)服務(wù)器端也充當(dāng)客戶端宾巍,大致的關(guān)系就是
藍牙連接
注意咕幻,這些連接都是阻塞式的,都要放在線程里去執(zhí)行顶霞。
1.對于BluetoothServerSocket肄程,建立一個AcceptThread,來監(jiān)聽是否有設(shè)備發(fā)起連接
//連接等待線程classAcceptThreadextendsThread{privatefinalBluetoothServerSocket serverSocket;publicAcceptThread(){? ? ? ? ? ? BluetoothServerSocket tmp =null;try{//獲取實例tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, MY_UUID_SECURE);? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? }? ? ? ? ? ? serverSocket = tmp;? ? ? ? }@Overridepublicvoidrun(){super.run();//監(jiān)聽是否有端口連接BluetoothSocket socket =null;while(mState != STATE_TRANSFER) {try{? ? ? ? ? ? ? ? ? ? Log.e(TAG,"run: AcceptThread 阻塞調(diào)用选浑,等待連接");? ? ? ? ? ? ? ? ? ? socket = serverSocket.accept();? ? ? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? ? ? Log.e(TAG,"run: ActivityThread fail");break;? ? ? ? ? ? ? ? }//獲取到連接Socket后則開始通信if(socket !=null){synchronized(BluetoothChatService.this) {switch(mState) {caseSTATE_LISTEN:caseSTATE_CONNECTING://傳輸數(shù)據(jù)蓝厌,服務(wù)器端調(diào)用Log.e(TAG,"run: 服務(wù)器AcceptThread傳輸");? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sendMessageToUi(MainActivity.BLUE_TOOTH_DIALOG ,"正在與"+ socket.getRemoteDevice().getName() +"連接");//開始數(shù)據(jù)傳輸dataTransfer(socket, socket.getRemoteDevice());break;caseSTATE_NONE:caseSTATE_TRANSFER:// 沒有準(zhǔn)備好或者終止連接try{? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? socket.close();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Log.e(TAG,"Could not close unwanted socket"+ e);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }break;? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }publicvoidcancel(){? ? ? ? ? ? Log.e(TAG,"close: activity Thread");try{if(serverSocket !=null)? ? ? ? ? ? ? ? ? ? ? ? serverSocket.close();? ? ? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? ? ? Log.e(TAG,"close: activity Thread fail");? ? ? ? ? ? ? ? }? ? ? ? }? ? }
可以看到,當(dāng)BluetoothServerSocket監(jiān)聽到有設(shè)備連接的時候古徒,就會調(diào)用dataTransfer開啟一個數(shù)據(jù)傳輸拓提。
2.同樣如何發(fā)起連接BluetoothSocket呢
需要一個ConnectThread來發(fā)起
classConnectThreadextendsThread{privatefinalBluetoothSocket socket;privatefinalBluetoothDevice device;publicConnectThread(BluetoothDevice device){this.device = device;? ? ? ? ? ? BluetoothSocket mSocket =null;try{//獲取SocketmSocket = device.createRfcommSocketToServiceRecord(? ? ? ? ? ? ? ? ? ? ? ? MY_UUID_SECURE);? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? Log.e(TAG,"ConnectThread: fail");? ? ? ? ? ? ? ? sendMessageToUi(MainActivity.BLUE_TOOTH_TOAST ,"連接失敗,請重新連接");? ? ? ? ? ? }? ? ? ? ? ? socket = mSocket;? ? ? ? }@Overridepublicvoidrun(){super.run();//建立后取消掃描bluetoothAdapter.cancelDiscovery();try{//開啟連接socket.connect();? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? e.printStackTrace();try{? ? ? ? ? ? ? ? ? ? socket.close();? ? ? ? ? ? ? ? }catch(IOException e1) {? ? ? ? ? ? ? ? ? ? e1.printStackTrace();? ? ? ? ? ? ? ? ? ? Log.e(TAG,"run: unable to close");? ? ? ? ? ? ? ? }//TODO 連接失敗顯示sendMessageToUi(MainActivity.BLUE_TOOTH_TOAST ,"連接失敗隧膘,請重新連接");? ? ? ? ? ? ? ? BluetoothChatService.this.start();? ? ? ? ? ? }// 重置synchronized(BluetoothChatService.this) {? ? ? ? ? ? ? ? mConnectThread =null;? ? ? ? ? ? }//連接建立代态,開始傳輸dataTransfer(socket, device);? ? ? ? }publicvoidcancel(){try{if(socket !=null)? ? ? ? ? ? ? ? ? ? ? ? socket.close();? ? ? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? }? ? ? ? }? ? }
之后建立連接之后就會調(diào)用dataTransfer來進行數(shù)據(jù)傳輸,同樣也需要一個線程來維護數(shù)據(jù)傳輸
classTransferThreadextendsThread{privatefinalBluetoothSocket socket;privatefinalOutputStream out;privatefinalInputStream in;publicTransferThread(BluetoothSocket mBluetoothSocket){? ? ? ? ? ? ? ? socket = mBluetoothSocket;? ? ? ? ? ? ? ? OutputStream mOutputStream =null;? ? ? ? ? ? ? ? InputStream mInputStream =null;try{if(socket !=null){//獲取連接的輸入輸出流mOutputStream = socket.getOutputStream();? ? ? ? ? ? ? ? ? ? ? ? mInputStream = socket.getInputStream();? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? out = mOutputStream;? ? ? ? ? ? ? ? in = mInputStream;? ? ? ? ? ? ? ? isTransferError =false;? ? ? ? }@Overridepublicvoidrun(){super.run();//讀取數(shù)據(jù)byte[] buffer =newbyte[1024];intbytes;while(true){try{? ? ? ? ? ? ? ? ? ? bytes = in.read(buffer);//TODO 分發(fā)到主線程顯示uiHandler.obtainMessage(MainActivity.BLUE_TOOTH_READ, bytes, -1, buffer)? ? ? ? ? ? ? ? ? ? ? ? ? ? .sendToTarget();? ? ? ? ? ? ? ? ? ? Log.e(TAG,"run: read "+newString(buffer ,0, bytes) );? ? ? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? ? ? ? ? Log.e(TAG,"run: Transform error"+ e.toString());? ? ? ? ? ? ? ? ? ? BluetoothChatService.this.start();//TODO 連接丟失顯示并重新開始連接sendMessageToUi(MainActivity.BLUE_TOOTH_TOAST ,"設(shè)備連接失敗/傳輸關(guān)閉");? ? ? ? ? ? ? ? ? ? isTransferError =true;break;? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }/**? ? ? ? * 寫入數(shù)據(jù)傳輸? ? ? ? *@parambuffer? ? ? ? */publicvoidwrite(byte[] buffer){try{? ? ? ? ? ? ? ? out.write(buffer);//TODO 到到UI顯示uiHandler.obtainMessage(MainActivity.BLUE_TOOTH_WRAITE , -1, -1, buffer)? ? ? ? ? ? ? ? ? ? ? ? .sendToTarget();? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? Log.e(TAG,"Exception during write "+ e);? ? ? ? ? ? }? ? ? ? }publicvoidcancel(){try{if(socket !=null)? ? ? ? ? ? ? ? ? ? socket.close();? ? ? ? ? ? }catch(IOException e) {? ? ? ? ? ? ? ? Log.e(TAG,"close() of connect socket failed"+ e);? ? ? ? ? ? }? ? ? ? }? ? }
藍牙聊天則是基于上面三個線程來進行實現(xiàn)舀寓,同樣胆数,對于藍牙文件間的傳輸也是同個道理,通過輸入輸出流來進行處理。之后的操作就比較容易處理了
四.簡單實現(xiàn)
https://github.com/ZengZeHong/BlueToothChat