前言:
本文主要描述Android BLE的一些基礎(chǔ)知識及相關(guān)操作流程,不牽扯具體的業(yè)務(wù)實(shí)現(xiàn),其中提供了針對廣播包及響應(yīng)包的解析思路,希望對正在或即將面臨Android BLE開發(fā)的伙伴們有所引導(dǎo)。
注:其中的單模、雙模、BR、BT、BLE、藍(lán)牙3.0、藍(lán)牙4.0等概念混在一起可能比較難理解,不知下文描述是否清晰,如果有不理解的地方,歡迎留言交流!
一、相關(guān)介紹 1、概述
藍(lán)牙無線技術(shù)是一種全球通用的短距離無線技術(shù),通過藍(lán)牙技術(shù)能夠?qū)崿F(xiàn)多種電子設(shè)備間的相互連接,特別是在小型無線電、耗電量低、成本低、安全性、穩(wěn)定性、易用性以及特別的聯(lián)網(wǎng)能力等固有的優(yōu)勢上,藍(lán)牙無線技術(shù)發(fā)展迅速。
2、分類
藍(lán)牙分為三種:Bluetooth Smart Ready、Bluetooth Smart(Smart是低功耗藍(lán)牙的標(biāo)識)、以及標(biāo)準(zhǔn) Bluetooth。根據(jù) Bluetooth SIG的說法,這樣是為了要分辨裝置間的相容性以及標(biāo)識各版本的傳輸頻率?;旧蟻碚f,Bluetooth Smart Ready適用于任何雙模藍(lán)牙4.0的電子產(chǎn)品,而Bluetooth Smart是應(yīng)用在心率監(jiān)視器或計(jì)步器等使用扭扣式電池并傳輸單一的裝置。Bluetooth Smart Ready的相容性最高,可與Bluetooth Smart及標(biāo)準(zhǔn)藍(lán)牙相通。標(biāo)準(zhǔn)藍(lán)牙則無法與Bluetooth Smart相通。
?

?
3、BLE介紹BLE是Bluetooth Low Energy的縮寫,又叫藍(lán)牙4.0,區(qū)別于藍(lán)牙3.0和之前的技術(shù)。BLE前身是NOKIA開發(fā)的Wibree技術(shù),主要用于實(shí)現(xiàn)移動智能終端與周邊配件之間的持續(xù)連接,是功耗極低的短距離無線通信技術(shù),并且有效傳輸距離被提升到了100米以上,同時(shí)只需要一顆紐扣電池就可以工作數(shù)年之久。BLE是在藍(lán)牙技術(shù)的基礎(chǔ)上發(fā)展起來的,既同于藍(lán)牙,又區(qū)別于傳統(tǒng)藍(lán)牙。BLE設(shè)備分單模和雙模兩種,雙模簡稱BR,商標(biāo)為Bluetooth Smart Ready,單模簡稱BLE或者LE,商標(biāo)為Bluetooth Smart。Android是在4.3后才支持BLE,這說明不是所有藍(lán)牙手機(jī)都支持BLE,而且支持BLE的藍(lán)牙手機(jī)一般是雙模的。雙模兼容傳統(tǒng)藍(lán)牙,可以和傳統(tǒng)藍(lán)牙通信,也可以和BLE通信,常用在手機(jī)上,android4.3和IOS4.0之后版本都支持BR,也就是雙模設(shè)備。單模只能和BR和單模的設(shè)備通信,不能和傳統(tǒng)藍(lán)牙通信,由于功耗低,待機(jī)長,所以常用在手環(huán)的智能設(shè)備上。
二、基本概念 1、Generic Access Profile(GAP)
用來控制設(shè)備連接和廣播,GAP使你的設(shè)備被其他設(shè)備可見,并決定了你的設(shè)備是否可以或者怎樣與合同設(shè)備進(jìn)行交互。
2、Generic Attribute Profile(GATT)通過BLE連接,讀寫屬性類數(shù)據(jù)的Profile通用規(guī)范,現(xiàn)在所有的BLE應(yīng)用Profile都是基于GATT的。
3、Attribute Protocol (ATT)GATT是基于ATTProtocol的,ATT針對BLE設(shè)備做了專門的優(yōu)化,具體就是在傳輸過程中使用盡量少的數(shù)據(jù),每個(gè)屬性都有一個(gè)唯一的UUID,屬性將以characteristics and services的形式傳輸。
4、CharacteristicCharacteristic可以理解為一個(gè)數(shù)據(jù)類型,它包括一個(gè)value和0至多個(gè)對次value的描述(Descriptor)。
5、Descriptor對Characteristic的描述,例如范圍、計(jì)量單位等。
6、ServiceCharacteristic的集合。例如一個(gè)service叫做“Heart Rate Monitor”,它可能包含多個(gè)Characteristics,其中可能包含一個(gè)叫做“heart ratemeasurement”的Characteristic。
7、UUID唯一標(biāo)示符,每個(gè)Service,Characteristic,Descriptor,都是由一個(gè)UUID定義。
三、Android BLE API 1、BluetoothGatt
繼承BluetoothProfile,通過BluetoothGatt可以連接設(shè)備(connect),發(fā)現(xiàn)服務(wù)(discoverServices),并把相應(yīng)地屬性返回到BluetoothGattCallback,可以看成藍(lán)牙設(shè)備從連接到斷開的生命周期。
2、BluetoothGattCharacteristic相當(dāng)于一個(gè)數(shù)據(jù)類型,可以看成一個(gè)特征或能力,它包括一個(gè)value和0~n個(gè)value的描述(BluetoothGattDescriptor)。
3、BluetoothGattDescriptor描述符,對Characteristic的描述,包括范圍、計(jì)量單位等。
4、BluetoothGattService服務(wù),Characteristic的集合。
5、BluetoothProfile一個(gè)通用的規(guī)范,按照這個(gè)規(guī)范來收發(fā)數(shù)據(jù)。
6、BluetoothManager
通過BluetoothManager來獲取BluetoothAdapter。
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
代表了移動設(shè)備的本地的藍(lán)牙適配器, 通過該藍(lán)牙適配器可以對藍(lán)牙進(jìn)行基本操作,一個(gè)Android系統(tǒng)只有一個(gè)BluetoothAdapter,通過BluetoothManager獲取。
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
掃描后發(fā)現(xiàn)可連接的設(shè)備,獲取已經(jīng)連接的設(shè)備。
BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
已經(jīng)連接上設(shè)備,對設(shè)備的某些操作后返回的結(jié)果。
1 2 3 4 ? BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback(){ //實(shí)現(xiàn)回調(diào)方法,根據(jù)業(yè)務(wù)做相應(yīng)處理 }; BluetoothGatt bluetoothGatt = bluetoothDevice.connectGatt(this, false, bluetoothGattCallback); ?三、操作流程 1、藍(lán)牙開啟
在使用藍(lán)牙BLE之前,需要確認(rèn)Android設(shè)備是否支持BLE feature(required為false時(shí)),另外要需要確認(rèn)藍(lán)牙是否打開。如果發(fā)現(xiàn)不支持BLE,則不能使用BLE相關(guān)的功能;如果支持BLE,但是藍(lán)牙沒打開,則需要打開藍(lán)牙。代碼示例如下:
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 ? //是否支持藍(lán)牙模塊 @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; } } //是否開啟藍(lán)牙 @TargetApi(18) public static boolean isBleEnable(Context context) { if(!isSupportBle(context)) { return false; } else { BluetoothManager manager = (BluetoothManager)context.getSystemService("bluetooth"); return manager.getAdapter().isEnabled(); } } //開啟藍(lán)牙 public static void enableBle(Activity act, int requestCode) { Intent mIntent = new Intent("android.bluetooth.adapter.action.REQUEST_ENABLE"); act.startActivityForResult(mIntent, requestCode); } //藍(lán)牙開啟過程 if(isSupportBle(mContext)){ //支持藍(lán)牙模塊 if(!isBleEnable(mContext)){ //沒開啟藍(lán)牙則開啟 enableBle(mSelfActivity, 1); } } else{ //不支持藍(lán)牙模塊處理 } //藍(lán)牙開啟回調(diào) @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { //判斷requestCode是否為開啟藍(lán)牙時(shí)傳進(jìn)去的值,再做相應(yīng)處理 if(requestCode == 1){ //藍(lán)牙開啟成功后的處理 } super.onActivityResult(requestCode, resultCode, data); } ?2、設(shè)備搜索
?
BluetoothAdapter.startDiscovery在大多數(shù)手機(jī)上是可以同時(shí)發(fā)現(xiàn)經(jīng)典藍(lán)牙和Ble的,但是startDiscovery的回調(diào)無法返回Ble的廣播,所以無法通過廣播識別設(shè)備,且startDiscovery掃描Ble的效率比StartLeScan低很多。所以在實(shí)際應(yīng)用中,還是StartDiscovery和StartLeScan分開掃,前者掃傳統(tǒng)藍(lán)牙,后者掃低功耗藍(lán)牙。
?
?
由于搜索需要盡量減少功耗,因此在實(shí)際使用時(shí)需要注意:當(dāng)找到對應(yīng)的設(shè)備后,立即停止掃描;不要循環(huán)搜索設(shè)備,為每次搜索設(shè)置適合的時(shí)間限制,避免設(shè)備不在可用范圍的時(shí)候持續(xù)不停掃描,消耗電量。
?
?
通過調(diào)用BluetoothAdapter的 startLeScan() 搜索BLE設(shè)備。調(diào)用此方法時(shí)需要傳入 BluetoothAdapter.LeScanCallback 參數(shù)。具體代碼示例如下:
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) { //對掃描到的設(shè)備進(jìn)行處理,可以依據(jù)BluetoothDevice中的信息、信號強(qiáng)度rssi以及廣播包和響應(yīng)包組成的scanRecord字節(jié)數(shù)組進(jìn)行分析 } }); ??
3、設(shè)備通信兩個(gè)設(shè)備通過BLE通信,首先需要建立GATT連接,這里我們講的是Android設(shè)備作為client端,連接GATT Server。連接GATT Server,需要調(diào)用BluetoothDevice的connectGatt()方法,此函數(shù)帶三個(gè)參數(shù):Context、autoConnect(boolean)和 BluetoothGattCallback 對象。調(diào)用后返回BluetoothGatt對象,它是GATT profile的封裝,通過這個(gè)對象,我們就能進(jìn)行GATT Client端的相關(guān)操作。如斷開連接bluetoothGatt.disconnect(),發(fā)現(xiàn)服務(wù)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后的相關(guān)操作對應(yīng)的響應(yīng)方法 //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(); ?四、數(shù)據(jù)解析
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:設(shè)備簡稱
9、TYPE = 0x09:設(shè)備全名
10、TYPE = 0x0A:表示設(shè)備發(fā)送廣播包的信號強(qiáng)度
11、TYPE = 0x0D:設(shè)備類別
12、TYPE = 0x0E:設(shè)備配對的Hash值
13、TYPE = 0x0F:設(shè)備配對的隨機(jī)值
14、TYPE = 0x10:TK安全管理(Security Manager TK Value)
15、TYPE = 0x11:帶外安全管理(Security Manager Out of Band),各bit定義如下:
16、TYPE = 0x12:外設(shè)(Slave)連接間隔范圍,數(shù)據(jù)中定義了Slave最大和最小連接間隔,數(shù)據(jù)包含4個(gè)字節(jié):前兩字節(jié)定義最小連接間隔,取值范圍:0x0006 ~ 0x0C80,而0xFFFF表示未定義;后兩字節(jié),定義最大連接間隔,取值范圍同上,不過需要保證最大連接間隔大于或者等于最小連接間隔。
17、TYPE = 0x14:服務(wù)搜尋16 bit UUID列表
18、TYPE = 0x15:服務(wù)搜尋128 bit UUID列表
19、TYPE = 0x16:16 bit UUID Service,前兩個(gè)字節(jié)是UUID,后面是Service的數(shù)據(jù)
20、TYPE = 0x17:公開目標(biāo)地址,表示希望這個(gè)廣播包被指定的目標(biāo)設(shè)備處理,此設(shè)備綁定了公開地址
21、TYPE = 0x18:隨機(jī)目標(biāo)地址,表示希望這個(gè)廣播包被指定的目標(biāo)設(shè)備處理,此設(shè)備綁定了隨機(jī)地址
22、TYPE = 0x19:表示設(shè)備的外觀
23、TYPE = 0x1A:廣播區(qū)間
24、TYPE = 0x1B:LE設(shè)備地址
25、TYPE = 0x1C:LE設(shè)備角色
26、TYPE = 0x1D:256位設(shè)備配對的Hash值
27、TYPE = 0x1E:256位設(shè)備配對的隨機(jī)值
28、TYPE = 0x20:32 bit UUID Service,前4個(gè)字節(jié)是UUID,后面是Service的數(shù)據(jù)
29、TYPE = 0x21:128 bit UUID Service,前16個(gè)字節(jié)是UUID,后面是Service的數(shù)據(jù)
30、TYPE = 0x3D:3D信息數(shù)據(jù)
31、TYPE = 0xFF:廠商自定義數(shù)據(jù),廠商自定義的數(shù)據(jù)中,前兩個(gè)字節(jié)表示廠商ID,剩下的是廠商自己按照需求添加,里面的數(shù)據(jù)內(nèi)容自己定義。
根據(jù)如下數(shù)據(jù)包,舉例說明解析的思路
搜索設(shè)備獲取的數(shù)據(jù)包如下: 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
根據(jù)解析規(guī)則,可分成如下部分:
1、廣播數(shù)據(jù)
2、響應(yīng)數(shù)據(jù)
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、有效數(shù)據(jù)
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、無效數(shù)據(jù)
1 ? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?
其中的有效數(shù)據(jù)又可分為如下幾個(gè)數(shù)據(jù)單元:
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
根據(jù)上面定義的AD Type分別解析如下:
第一組數(shù)據(jù)告訴我們該設(shè)備屬于LE普通發(fā)現(xiàn)模式,不支持BR/EDR;
第二組數(shù)據(jù)告訴我們該數(shù)據(jù)為廠商自定義數(shù)據(jù),一般是必須解析的,可根據(jù)協(xié)議規(guī)則進(jìn)行解析獲取對應(yīng)的所需信息;
第三組數(shù)據(jù)告訴我們該設(shè)備的簡稱為HET-5,其中對應(yīng)的字符是查找ASSIC表得出的;
第四組數(shù)據(jù)告訴我們UUID為E7FE-12FF-0F18-0A18(此處有疑,類型03表示的是16位的UUID,對應(yīng)的兩個(gè)字節(jié),而此處有8個(gè)字節(jié),估計(jì)是設(shè)備燒錄時(shí)把字節(jié)位數(shù)理解為了字符位數(shù)導(dǎo)致的問題).
五、參考鏈接
1、藍(lán)牙Bluetooth BR/EDR 和 Bluetooth Smart 必需要知道的十個(gè)不同點(diǎn)
2、BLE簡介和Android BLE編程
3、BLE廣播數(shù)據(jù)解析
電子發(fā)燒友App















評論