前言:
本文主要描述Android BLE的一些基礎知識及相關操作流程,不牽扯具體的業務實現,其中提供了針對廣播包及響應包的解析思路,希望對正在或即將面臨Android BLE開發的伙伴們有所引導。
注:其中的單模、雙模、BR、BT、BLE、藍牙3.0、藍牙4.0等概念混在一起可能比較難理解,不知下文描述是否清晰,如果有不理解的地方,歡迎留言交流!
一、相關介紹 1、概述
藍牙無線技術是一種全球通用的短距離無線技術,通過藍牙技術能夠實現多種電子設備間的相互連接,特別是在小型無線電、耗電量低、成本低、安全性、穩定性、易用性以及特別的聯網能力等固有的優勢上,藍牙無線技術發展迅速。
2、分類
藍牙分為三種:Bluetooth Smart Ready、Bluetooth Smart(Smart是低功耗藍牙的標識)、以及標準 Bluetooth。根據 Bluetooth SIG的說法,這樣是為了要分辨裝置間的相容性以及標識各版本的傳輸頻率。基本上來說,Bluetooth Smart Ready適用于任何雙模藍牙4.0的電子產品,而Bluetooth Smart是應用在心率監視器或計步器等使用扭扣式電池并傳輸單一的裝置。Bluetooth Smart Ready的相容性最高,可與Bluetooth Smart及標準藍牙相通。標準藍牙則無法與Bluetooth Smart相通。
?
?
3、BLE介紹BLE是Bluetooth Low Energy的縮寫,又叫藍牙4.0,區別于藍牙3.0和之前的技術。BLE前身是NOKIA開發的Wibree技術,主要用于實現移動智能終端與周邊配件之間的持續連接,是功耗極低的短距離無線通信技術,并且有效傳輸距離被提升到了100米以上,同時只需要一顆紐扣電池就可以工作數年之久。BLE是在藍牙技術的基礎上發展起來的,既同于藍牙,又區別于傳統藍牙。BLE設備分單模和雙模兩種,雙模簡稱BR,商標為Bluetooth Smart Ready,單模簡稱BLE或者LE,商標為Bluetooth Smart。Android是在4.3后才支持BLE,這說明不是所有藍牙手機都支持BLE,而且支持BLE的藍牙手機一般是雙模的。雙模兼容傳統藍牙,可以和傳統藍牙通信,也可以和BLE通信,常用在手機上,android4.3和IOS4.0之后版本都支持BR,也就是雙模設備。單模只能和BR和單模的設備通信,不能和傳統藍牙通信,由于功耗低,待機長,所以常用在手環的智能設備上。
二、基本概念 1、Generic Access Profile(GAP)
用來控制設備連接和廣播,GAP使你的設備被其他設備可見,并決定了你的設備是否可以或者怎樣與合同設備進行交互。
2、Generic Attribute Profile(GATT)通過BLE連接,讀寫屬性類數據的Profile通用規范,現在所有的BLE應用Profile都是基于GATT的。
3、Attribute Protocol (ATT)GATT是基于ATTProtocol的,ATT針對BLE設備做了專門的優化,具體就是在傳輸過程中使用盡量少的數據,每個屬性都有一個唯一的UUID,屬性將以characteristics and services的形式傳輸。
4、CharacteristicCharacteristic可以理解為一個數據類型,它包括一個value和0至多個對次value的描述(Descriptor)。
5、Descriptor對Characteristic的描述,例如范圍、計量單位等。
6、ServiceCharacteristic的集合。例如一個service叫做“Heart Rate Monitor”,它可能包含多個Characteristics,其中可能包含一個叫做“heart ratemeasurement”的Characteristic。
7、UUID唯一標示符,每個Service,Characteristic,Descriptor,都是由一個UUID定義。
三、Android BLE API 1、BluetoothGatt
繼承BluetoothProfile,通過BluetoothGatt可以連接設備(connect),發現服務(discoverServices),并把相應地屬性返回到BluetoothGattCallback,可以看成藍牙設備從連接到斷開的生命周期。
2、BluetoothGattCharacteristic相當于一個數據類型,可以看成一個特征或能力,它包括一個value和0~n個value的描述(BluetoothGattDescriptor)。
3、BluetoothGattDescriptor描述符,對Characteristic的描述,包括范圍、計量單位等。
4、BluetoothGattService服務,Characteristic的集合。
5、BluetoothProfile一個通用的規范,按照這個規范來收發數據。
6、BluetoothManager
通過BluetoothManager來獲取BluetoothAdapter。
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
代表了移動設備的本地的藍牙適配器, 通過該藍牙適配器可以對藍牙進行基本操作,一個Android系統只有一個BluetoothAdapter,通過BluetoothManager獲取。
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
掃描后發現可連接的設備,獲取已經連接的設備。
BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
已經連接上設備,對設備的某些操作后返回的結果。
1 2 3 4 ? BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback(){ //實現回調方法,根據業務做相應處理 }; BluetoothGatt bluetoothGatt = bluetoothDevice.connectGatt(this, false, bluetoothGattCallback); ?三、操作流程 1、藍牙開啟
在使用藍牙BLE之前,需要確認Android設備是否支持BLE feature(required為false時),另外要需要確認藍牙是否打開。如果發現不支持BLE,則不能使用BLE相關的功能;如果支持BLE,但是藍牙沒打開,則需要打開藍牙。代碼示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 ? //是否支持藍牙模塊 @TargetApi(18) public static boolean isSupportBle(Context context) { if(context != null && context.getPackageManager().hasSystemFeature("android.hardware.bluetooth_le")) { BluetoothManager manager = (BluetoothManager)context.getSystemService("bluetooth"); return manager.getAdapter() != null; } else { return false; } } //是否開啟藍牙 @TargetApi(18) public static boolean isBleEnable(Context context) { if(!isSupportBle(context)) { return false; } else { BluetoothManager manager = (BluetoothManager)context.getSystemService("bluetooth"); return manager.getAdapter().isEnabled(); } } //開啟藍牙 public static void enableBle(Activity act, int requestCode) { Intent mIntent = new Intent("android.bluetooth.adapter.action.REQUEST_ENABLE"); act.startActivityForResult(mIntent, requestCode); } //藍牙開啟過程 if(isSupportBle(mContext)){ //支持藍牙模塊 if(!isBleEnable(mContext)){ //沒開啟藍牙則開啟 enableBle(mSelfActivity, 1); } } else{ //不支持藍牙模塊處理 } //藍牙開啟回調 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { //判斷requestCode是否為開啟藍牙時傳進去的值,再做相應處理 if(requestCode == 1){ //藍牙開啟成功后的處理 } super.onActivityResult(requestCode, resultCode, data); } ?2、設備搜索
?
BluetoothAdapter.startDiscovery在大多數手機上是可以同時發現經典藍牙和Ble的,但是startDiscovery的回調無法返回Ble的廣播,所以無法通過廣播識別設備,且startDiscovery掃描Ble的效率比StartLeScan低很多。所以在實際應用中,還是StartDiscovery和StartLeScan分開掃,前者掃傳統藍牙,后者掃低功耗藍牙。
?
?
由于搜索需要盡量減少功耗,因此在實際使用時需要注意:當找到對應的設備后,立即停止掃描;不要循環搜索設備,為每次搜索設置適合的時間限制,避免設備不在可用范圍的時候持續不停掃描,消耗電量。
?
?
通過調用BluetoothAdapter的 startLeScan() 搜索BLE設備。調用此方法時需要傳入 BluetoothAdapter.LeScanCallback 參數。具體代碼示例如下:
1 2 3 4 5 6 7 8 ? BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { //對掃描到的設備進行處理,可以依據BluetoothDevice中的信息、信號強度rssi以及廣播包和響應包組成的scanRecord字節數組進行分析 } }); ??
3、設備通信兩個設備通過BLE通信,首先需要建立GATT連接,這里我們講的是Android設備作為client端,連接GATT Server。連接GATT Server,需要調用BluetoothDevice的connectGatt()方法,此函數帶三個參數:Context、autoConnect(boolean)和 BluetoothGattCallback 對象。調用后返回BluetoothGatt對象,它是GATT profile的封裝,通過這個對象,我們就能進行GATT Client端的相關操作。如斷開連接bluetoothGatt.disconnect(),發現服務bluetoothGatt.discoverServices()等等。示例代碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 ? BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address); BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback(){ @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { super.onReliableWriteCompleted(gatt, status); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { super.onReadRemoteRssi(gatt, rssi, status); } @Override public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { super.onMtuChanged(gatt, mtu, status); } }; BluetoothGatt bluetoothGatt = bluetoothDevice.connectGatt(this, false, bluetoothGattCallback); //以下為獲得Gatt后的相關操作對應的響應方法 //notification to onCharacteristicChanged; bluetoothGatt.setCharacteristicNotification(characteristic, true); //readCharacteristic to onCharacteristicRead; bluetoothGatt.readCharacteristic(characteristic); //writeCharacteristic to onCharacteristicWrite; bluetoothGatt.wirteCharacteristic(mCurrentcharacteristic); //connect and disconnect to onConnectionStateChange; bluetoothGatt.connect(); bluetoothGatt.disconnect(); //readDescriptor to onDescriptorRead; bluetoothGatt.readDescriptor(descriptor); //writeDescriptor to onDescriptorWrite; bluetoothGatt.writeDescriptor(descriptor); //readRemoteRssi to onReadRemoteRssi; bluetoothGatt.readRemoteRssi(); //executeReliableWrite to onReliableWriteCompleted; bluetoothGatt.executeReliableWrite(); //discoverServices to onServicesDiscovered; bluetoothGatt.discoverServices(); ?四、數據解析
2、TYPE = 0x02:非完整的16 bit UUID列表
3、TYPE = 0x03:完整的16 bit UUID列表
4、TYPE = 0x04:非完整的32 bit UUID列表
5、TYPE = 0x05:完整的32 bit UUID列表
6、TYPE = 0x06:非完整的128 bit UUID列表
7、TYPE = 0x07:完整的128 bit UUID列表
8、TYPE = 0x08:設備簡稱
9、TYPE = 0x09:設備全名
10、TYPE = 0x0A:表示設備發送廣播包的信號強度
11、TYPE = 0x0D:設備類別
12、TYPE = 0x0E:設備配對的Hash值
13、TYPE = 0x0F:設備配對的隨機值
14、TYPE = 0x10:TK安全管理(Security Manager TK Value)
15、TYPE = 0x11:帶外安全管理(Security Manager Out of Band),各bit定義如下:
16、TYPE = 0x12:外設(Slave)連接間隔范圍,數據中定義了Slave最大和最小連接間隔,數據包含4個字節:前兩字節定義最小連接間隔,取值范圍:0x0006 ~ 0x0C80,而0xFFFF表示未定義;后兩字節,定義最大連接間隔,取值范圍同上,不過需要保證最大連接間隔大于或者等于最小連接間隔。
17、TYPE = 0x14:服務搜尋16 bit UUID列表
18、TYPE = 0x15:服務搜尋128 bit UUID列表
19、TYPE = 0x16:16 bit UUID Service,前兩個字節是UUID,后面是Service的數據
20、TYPE = 0x17:公開目標地址,表示希望這個廣播包被指定的目標設備處理,此設備綁定了公開地址
21、TYPE = 0x18:隨機目標地址,表示希望這個廣播包被指定的目標設備處理,此設備綁定了隨機地址
22、TYPE = 0x19:表示設備的外觀
23、TYPE = 0x1A:廣播區間
24、TYPE = 0x1B:LE設備地址
25、TYPE = 0x1C:LE設備角色
26、TYPE = 0x1D:256位設備配對的Hash值
27、TYPE = 0x1E:256位設備配對的隨機值
28、TYPE = 0x20:32 bit UUID Service,前4個字節是UUID,后面是Service的數據
29、TYPE = 0x21:128 bit UUID Service,前16個字節是UUID,后面是Service的數據
30、TYPE = 0x3D:3D信息數據
31、TYPE = 0xFF:廠商自定義數據,廠商自定義的數據中,前兩個字節表示廠商ID,剩下的是廠商自己按照需求添加,里面的數據內容自己定義。
根據如下數據包,舉例說明解析的思路
搜索設備獲取的數據包如下: 1 ? 02 01 06 14 FF 11 22 00 00 00 01 00 1F 09 01 00 00 00 CE DD 5E 5A 5D 23 06 08 48 45 54 2D 35 09 03 E7 FE 12 FF 0F 18 0A 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
根據解析規則,可分成如下部分:
1、廣播數據
2、響應數據
1 ? 09 03 E7 FE 12 FF 0F 18 0A 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?3、有效數據
1 ? 02 01 06 14 FF 11 22 00 00 00 01 00 1F 09 01 00 00 00 CE DD 5E 5A 5D 23 06 08 48 45 54 2D 35 09 03 E7 FE 12 FF 0F 18 0A 18 ?4、無效數據
1 ? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?
其中的有效數據又可分為如下幾個數據單元:
02 01 06
14 FF 11 22 00 00 00 01 00 1F 09 01 00 00 00 CE DD 5E 5A 5D 23
06 08 48 45 54 2D 35
09 03 E7 FE 12 FF 0F 18 0A 18
根據上面定義的AD Type分別解析如下:
第一組數據告訴我們該設備屬于LE普通發現模式,不支持BR/EDR;
第二組數據告訴我們該數據為廠商自定義數據,一般是必須解析的,可根據協議規則進行解析獲取對應的所需信息;
第三組數據告訴我們該設備的簡稱為HET-5,其中對應的字符是查找ASSIC表得出的;
第四組數據告訴我們UUID為E7FE-12FF-0F18-0A18(此處有疑,類型03表示的是16位的UUID,對應的兩個字節,而此處有8個字節,估計是設備燒錄時把字節位數理解為了字符位數導致的問題).
五、參考鏈接
1、藍牙Bluetooth BR/EDR 和 Bluetooth Smart 必需要知道的十個不同點
2、BLE簡介和Android BLE編程
3、BLE廣播數據解析
評論
查看更多