詳解Android 藍(lán)牙通信方式總結(jié)
1.摘要
Android手機(jī)間通過藍(lán)牙方式進(jìn)行通信,有兩種常見的方式,一種是socket方式,另一種是通過Gatt Server(Android 5.0以后)通信,socket方式最為簡單,但是很多低功耗的藍(lán)牙設(shè)備,如單片機(jī)上的藍(lán)牙模塊可能不支持;而Gatt方式相對比較復(fù)雜。其實(shí)無論是socket方式還是Gatt,Android設(shè)備間藍(lán)牙通信都是一種C/S(client-server)模式。
本文基于兩種通信方式,進(jìn)行詳細(xì)展開,并推薦了開源項目,建議配合學(xué)習(xí)。
關(guān)鍵詞
(1)Bluetooth
藍(lán)牙(Bluetooth):藍(lán)牙,是一種支持設(shè)備短距離通信(一般10m內(nèi))的無線電技術(shù),能在包括移動電話、PDA、無線耳機(jī)、筆記本電腦、相關(guān)外設(shè)等眾多設(shè)備之間進(jìn)行無線信息交換。利用“藍(lán)牙”技術(shù),能夠有效地簡化移動通信終端設(shè)備之間的通信,也能夠成功地簡化設(shè)備與因特網(wǎng)Internet之間的通信,從而使數(shù)據(jù)傳輸變得更加迅速高效,為無線通信拓寬道路。
(2) UUID
UUID(Universally Unique Identifier):用于標(biāo)識藍(lán)牙服務(wù)以及通訊特征訪問屬性,不同的藍(lán)牙服務(wù)和屬性使用不同的訪問方法。
(3)服務(wù)UUID
服務(wù)UUID(Service UUID):不同的服務(wù)(Service)應(yīng)該有不同的編號(UUID),用以區(qū)分不同的服務(wù)(Service)。
(4)特征值UUID
特征值UUID(Characteristic UUID):特性(Characteristic) 是依附于某個服務(wù)(Service)的
(5)屬性(Property) (5.1)Read: 讀屬性
Read: 讀屬性,具有這個屬性的特性是可讀的,也就是說這個屬性允許手機(jī)來讀取一些信息。手機(jī)可以發(fā)送指令來讀取某個具有讀屬性UUID的信息。
(5.2)Notify: 通知屬性
Notify: 通知屬性, 具有這個屬性的特性是可以發(fā)送通知的,也就是說具有這個屬性的特性(Characteristic)可以主動發(fā)送信息給手機(jī)。
(5.3)Write: 寫屬性
Write: 寫屬性, 具有這個屬性的特性是可以接收寫入數(shù)據(jù)的。通常手機(jī)發(fā)送數(shù)據(jù)給藍(lán)模塊就是通過這個屬性完成的。這個屬性在Write 完成后,會發(fā)送寫入完成結(jié)果的反饋給手機(jī),然后手機(jī)再可以寫入下一包或處理后續(xù)業(yè)務(wù),這個屬性在寫入一包數(shù)據(jù)后,需要等待應(yīng)用層返回寫入結(jié)果,速度比較慢。
(5.4)WriteWithout Response:寫屬性
WriteWithout Response:寫屬性,從字面意思上看,只是寫,不需要返回寫的結(jié)果,這個屬性的特點(diǎn)是不需要應(yīng)用層返回,完全依靠協(xié)議層完成,速度快,但是寫入速度超過協(xié)議處理速度的時候,會丟包。
(6) GATT
GATT(Generic Attribute Profile):中文名叫通用屬性協(xié)議,它定義了services和characteristic兩種東西來完成低功耗藍(lán)牙設(shè)備之間的數(shù)據(jù)傳輸。它是建立在通用數(shù)據(jù)協(xié)議Attribute Protocol (ATT),之上的,ATT把services和characteristic以及相關(guān)的數(shù)據(jù)保存在一張簡單的查找表中,該表使用16-bit的id作為索引。
(7)profile
profile可以理解為一種規(guī)范,一個標(biāo)準(zhǔn)的通信協(xié)議,它存在于從機(jī)中。藍(lán)牙組織規(guī)定了一些標(biāo)準(zhǔn)的profile,例如 HID OVER GATT ,防丟器 ,心率計等。每個profile中會包含多個service,每個service代表從機(jī)的一種能力。
2. Bluetooth Socket
推薦開源項目:https://github.com/Zweo/Bluetooth (https://github.com/zolty-lionheart/Bluetooth)
以該項目demo為例介紹
藍(lán)牙端口監(jiān)聽接口和TCP端口類似:Socket和ServerSocket類。在服務(wù)器端,使用BluetoothServerSocket類來創(chuàng)建一個 監(jiān)聽服務(wù)端口。當(dāng)一個連接被BluetoothServerSocket所接受,它會返回一個新的BluetoothSocket來管理該連接。在客戶 端,使用一個單獨(dú)的BluetoothSocket類去初始化一個外接連接和管理該連接。
最通常使用的藍(lán)牙端口是RFCOMM,它是被Android API支持的類型。RFCOMM是一個面向連接,通過藍(lán)牙模塊進(jìn)行的數(shù)據(jù)流傳輸方式,它也被稱為串行端口規(guī)范(Serial Port Profile,SPP)。
為了創(chuàng)建一個BluetoothSocket去連接到一個已知設(shè)備,使用方法 BluetoothDevice.createRfcommSocketToServiceRecord()。然后調(diào)用connect()方法去嘗試一個 面向遠(yuǎn)程設(shè)備的連接。這個調(diào)用將被阻塞指導(dǎo)一個連接已經(jīng)建立或者該鏈接失效。
為了創(chuàng)建一個BluetoothSocket作為服務(wù)端(或者“主機(jī)”),查看BluetoothServerSocket文檔。
每當(dāng)該端口連接成功,無論它初始化為客戶端,或者被接受作為服務(wù)器端,通過getInputStream()和getOutputStream()來打開IO流,從而獲得各自的InputStream和OutputStream對象
BluetoothSocket類線程安全。特別的,close()方法總會馬上放棄外界操作并關(guān)閉服務(wù)器端口。
注意:需要BLUETOOTH權(quán)限。
2.1 Server端
private static final String UUIDString = "00001101-0000-1000-8000-00805F9B34FB";
//開啟服務(wù)器
private class ServerThread extends Thread {
@Override
public void run() {
try {
/* 創(chuàng)建一個藍(lán)牙服務(wù)器
* 參數(shù)分別:服務(wù)器名稱、UUID */
mServerSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM, UUID.fromString(UUIDString));
while (true){
Log.d("server", "wait cilent connect...");
Message msg = new Message();
msg.obj = "請稍候,正在等待客戶端的連接...";
msg.what = WAITING_FOR_CLIENT;
linkDetectedHandler.sendMessage(msg);
/* 接受客戶端的連接請求 */
BluetoothSocket socket = mServerSocket.accept();
socketMap.put(socket.getRemoteDevice().getAddress(), socket);
// remoteDeviceMap.put(socket.getRemoteDevice().getAddress(),socket.getRemoteDevice());
Log.d("server", "accept success !");
Message msg2 = new Message();
String info = "客戶端已經(jīng)連接上!可以發(fā)送信息。";
msg2.obj = info;
msg.what = CONNECTED_CLIENT;
linkDetectedHandler.sendMessage(msg2);
//啟動接受數(shù)據(jù)
ReadThread mreadThread = new ReadThread(socket.getRemoteDevice().getAddress());
readThreadMap.put(socket.getRemoteDevice().getAddress(),mreadThread);
mreadThread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.2 Server
//開啟客戶端
private class ClientThread extends Thread {
private String remoteAddress;
public ClientThread(String remoteAddress) {
this.remoteAddress = remoteAddress;
}
@Override
public void run() {
try {
//創(chuàng)建一個Socket連接:只需要服務(wù)器在注冊時的UUID號
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(remoteAddress);
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(UUIDString));
//連接
Message msg2 = new Message();
msg2.obj = "請稍候,正在連接服務(wù)器:" + remoteAddress;
msg2.what = IS_CONNECTING_SERVER;
linkDetectedHandler.sendMessage(msg2);
socket.connect();
socketMap.put(remoteAddress, socket);
Message msg = new Message();
msg.obj = remoteAddress;
msg.what = CONNECTED_SERVER;
linkDetectedHandler.sendMessage(msg);
//啟動接受數(shù)據(jù)
ReadThread mreadThread = new ReadThread(remoteAddress);
readThreadMap.put(remoteAddress,mreadThread);
mreadThread.start();
} catch (IOException e) {
e.printStackTrace();
socketMap.remove(remoteAddress);
Log.e("connect", e.getMessage(), e);
Message msg = new Message();
msg.obj = "連接服務(wù)端異常!斷開連接重新試一試。"+e.getMessage();
msg.what = CONNECT_SERVER_ERROR;
linkDetectedHandler.sendMessage(msg);
}
}
}
3. Bluetooth GATT


推薦開源項目:https://github.com/dingpwen/bl_communication (https://github.com/zolty-lionheart/bl_communication)
以該項目demo為例介紹
3.1 Server
private fun setupServer() {
val gattService = BluetoothGattService(Constants.BLE_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY)
val characteristicRead = BluetoothGattCharacteristic(Constants.BLE_READ_UUID, BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ)
val descriptor = BluetoothGattDescriptor(Constants.BLE_DESC_UUID, BluetoothGattCharacteristic.PERMISSION_WRITE)
characteristicRead.addDescriptor(descriptor)
gattService.addCharacteristic(characteristicRead)
val characteristicWrite = BluetoothGattCharacteristic(Constants.BLE_WRITE_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE or
BluetoothGattCharacteristic.PROPERTY_READ or BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_WRITE)
gattService.addCharacteristic(characteristicWrite)
Log.d("wenpd", "startGattServer:stagattServicetus=$gattService")
mGattServer.addService(gattService)
}
3.2 Client
private class GattClientCallback extends BluetoothGattCallback {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (status == BluetoothGatt.GATT_FAILURE) {
disconnectGattServer();
return;
} else if (status != BluetoothGatt.GATT_SUCCESS) {
disconnectGattServer();
return;
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnected = true;
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
disconnectGattServer();
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
Log.d(TAG, "onServicesDiscovered status:" + status);
if (status != BluetoothGatt.GATT_SUCCESS) {
return;
}
BluetoothGattService service = gatt.getService(Constants.SERVICE_UUID);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(Constants.CHARACTERISTIC_UUID);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
mInitialized = gatt.setCharacteristicNotification(characteristic, true);
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
byte[] messageBytes = characteristic.getValue();
/*for(int i = 0, j = messageBytes.length -1; i < j; ++i, --j) {
byte temp = messageBytes[i];
messageBytes[i] = messageBytes[j];
messageBytes[j] = temp;
}*/
String messageString = new String(messageBytes, StandardCharsets.UTF_8);
Log.d(TAG,"Received message: " + messageString);
setReceivedData(messageString);
}
}
參考文獻(xiàn)
1.Android Phone藍(lán)牙通信方式總結(jié)(Socket與Gatt)
2.Bluetooth之BluetoothSocket
3.全面且簡單明了的藍(lán)牙服務(wù)及UUID介紹
4.Android BLE藍(lán)牙開發(fā)-讀寫數(shù)據(jù) 獲取UUID
到此這篇關(guān)于詳解Android 藍(lán)牙通信方式總結(jié)的文章就介紹到這了,更多相關(guān)Android 藍(lán)牙通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android藍(lán)牙開發(fā)深入解析
- 詳解Android——藍(lán)牙技術(shù) 帶你實(shí)現(xiàn)終端間數(shù)據(jù)傳輸
- Android單片機(jī)與藍(lán)牙模塊通信實(shí)例代碼
- Android Bluetooth藍(lán)牙技術(shù)使用流程詳解
- 分享Android 藍(lán)牙4.0(ble)開發(fā)的解決方案
- Android 獲取藍(lán)牙Mac地址的正確方法
- Android手機(jī)通過藍(lán)牙連接佳博打印機(jī)的實(shí)例代碼
- android實(shí)現(xiàn)藍(lán)牙文件發(fā)送的實(shí)例代碼,支持多種機(jī)型
- Android實(shí)現(xiàn)藍(lán)牙(BlueTooth)設(shè)備檢測連接
- Android學(xué)習(xí)筆記之藍(lán)牙功能
相關(guān)文章
Android手機(jī)開發(fā) 控件 TextView文字居中
本文主要介紹Android手機(jī)開發(fā)TextView居中的方法,希望能幫到大家。2016-05-05
Android EditTextView 實(shí)現(xiàn)帶空格分隔的輸入(電話號碼,銀行卡)
這篇文章主要介紹了Android EditTextView 實(shí)現(xiàn)帶空格分隔的輸入(電話號碼,銀行卡)的相關(guān)資料,需要的朋友可以參考下2018-02-02
漂亮的Android音樂歌詞控件 仿網(wǎng)易云音樂滑動效果
這篇文章主要為大家詳細(xì)介紹了漂亮的Android音樂歌詞控件,仿網(wǎng)易云音樂滑動效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01
Android-如何將RGB彩色圖轉(zhuǎn)換為灰度圖方法介紹
本文將詳細(xì)介紹Android-如何將RGB彩色圖轉(zhuǎn)換為灰度圖方法,需要了解更多的朋友可以參考下2012-11-11
Android Activity與Intent詳解及示例代碼
本文主要講解Android Activity與Intent的知識,這里整理了相關(guān)資料并附有示例代碼,有興趣的小伙伴可以參考下2016-08-08
Android用ActionBar高仿微信主界面的實(shí)例代碼
這篇文章主要介紹了Android用ActionBar高仿微信主界面的實(shí)例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05
android項目從Eclipse遷移到Android studio中常見問題解決方法
android項目從Eclipse遷移到Android studio中經(jīng)常會遇到一些問題,本文提供了Android studio使用中常見問題解決方法2018-03-03

