hello大家好,我是城鄉經濟網小晟來為大家解答以上問題,安卓藍牙開發,Android低功耗藍牙總結很多人還不知道,現在讓我們一起來看看吧!
首先要搞清楚一點,我們在 Android 中通過 SDK 獲得的藍牙廣播包是經過底層的 SDK 給我們處理過的,是一個長度為 62 的字節數組。這個長度為 62 的字節數組是怎么來的呢?
想要搞清楚這個問題,首先我們要明白 iBeacon 向外發送的最原始的廣播包是什么樣的?
【資料圖】
首先我們要搞清楚一點,藍牙在向外發送數據的時候是分成兩個部分的一個就是普通的廣播包還有一個叫做應答包。這是藍牙協議的規定內容,針對于所有的藍牙設備(iBeacon 只是藍牙設備的一種)
需要注意的是,發送數據是從低位到高位一次發送,所以接收到的數據要返回來按字節拼接,例如接收到的MAC為 8b 03 00 b0 01 c2,那么實際的MAC為 c2:01:b0:00:03:8b
首先我們來看一下第一個藍牙廣播包(來自 iBeacon 設備),一共 59 個字節
04 3e 38 0d 01 13 00 01 8b 03 00 b0 01 c2 01 00 ff 7f af 00 00 00 00 00 00 00 00 00 1e 29個字節 02 01 06 1a ff 4c 00 02 15 fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25 27 11 4c b9 c5 30個字節
第一行的內容可以認為是藍牙廣播包中的附帶信息,通過 Android SDK 是沒法看到的,第二行是對應我們 Android SDK 中收到的廣播包中的前一部分。
第一個字節是HCI Packet Type,04表示這是HCI Event;剩下的58bytes則是HCI Event的具體內容第二個字節是EventCode,3e是此事件的代碼;第三個字節是Parameter Length,0x38(十進制56)表示后面數據長度56bytes第四個字節是SubEvent,0d表示這是LE Extended Advertising Report;第五個字節是Num Reports,數值為011b 00這兩個字節代表Event Type,由于發送數據都是按字節發送以及從低位向高位發送,因此真實值是 001b01 表示這是隨機設備地址8b 03 00 b0 01 c2 是此設備的MAC,根據從低向高的發送規則,所以真實MAC是 c2:01:b0:00:03:8b01 代表首要廣播信道的帶寬00 代表次要廣播信道的帶寬,此處表示不使用次要信道ff 表示廣播SID7f 代表Tx Power的大小,此處是127dbmaf 代表RSSI的大小,此處是-81dbm00 00 代表周期廣播間隔00 代表直接地址類型,次數是公共設備地址00 00 00 00 00 00 代表直接BD_ADDR1e 代表接下的的數據的字節數(長度),以下數據就是最重要的廣播數據了
上面的內容就是對應第一行的解釋了,其實 Android SDK 已經幫我們把這些數據中的部分內容解析出來,我們可以直接通過對應的 SDK 的方法來直接獲取。
下面我們再來看 真正意義上的廣播包
格式是這樣的:
一個廣播包是由若干個廣播單元 AD Structure 構成的。每個 AD Structure 的組成是:第一個字節表示長度值 length,表示接下來的 length 個字節是數據部分,數據部分的第一個字節表示數據的類型 AD Type,AD Type 決定了下面的數據代表了什么,關于每個數值代表的數據類型見官方文檔,剩下的 length - 1 個字節表示真正的數據
02 01 06 02 表示接下來的數據有兩個字節 01 表示數據類型,此處類型是 Flags 06 就是具體的數值了 0x06 = 0000 0110 每一位都有不同的含義,見官方文檔
1a ff 4c 00 02 15 fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25 27 11 4c b9 c51a 表示接下來的數據有 26 字節FF 表示數據類型,此處類型是 廠商自定義數據類型(這里的廠商指的是蘋果公司,因為 iBeacon 是蘋果公司提出的)4C 00 表示公司的 ID,此處的 004C 代表蘋果公司02 15 Beacon 的標識位,必須是這樣的fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25表示 Beacon UUID 27 11 是 major 的值4C b9 是 minor 的值C5 表示 Measured Power 表示的是此設備在 1 米處的 RSSI 值,用于距離測算
這段內容其實主要是蘋果公司在藍牙協議的基礎上定義的。
如果符合 1AFF4C000215 則說明此設備是 iBeacon 設備
04 3e 38 0d 01 1b 00 01 8b 03 00 b0 01 c2 01 00 ff 7f af 00 00 00 00 00 00 00 00 00 1e 29個字節02 0a 00 08 16 f0 ff 64 27 11 4c b9 11 09 4d 69 6e 69 42 65 61 63 6f 6e 5f 30 30 39 30 37 30個字節
其中第一行與上面一樣,這里不再介紹02 0a 00 02 表示接下來的數據長度 2 個字節0a 表示數據類型 這里表示 Tx Power Level 取值范圍是 -127 到 127 dBm00 表示 0 dBm08 16 f0 ff 64 27 11 4c b908 表示數據長度 16 表示 Service Data 由 Service UUID 和 service 數據組成 前兩個字節是 UUID 后面是數據f0ff 是 Service UUID 64 27 11 4c b9 是數據11 09 4d 69 6e 69 42 65 61 63 6f 6e11 表示數據長度09 表示設備完整的名字4d 69 6e 69 42 65 61 63 6f 6e 就是設備名字的 ASSIC 碼了 對應 MiniBeaconM i n i B e a c o n 5f 30 30 39 30 37這幾個數據就是 Beacon 開發者隨便亂加入的數據了,不符合協議內容
上面我們分別分析了藍牙原始數據包中的廣播包和應答包,其實對于 iBeacon 來說廣播包中的大多數內容其確定的,只有 UUID Major Minor 會有變化。而且每個位置所代表的作用都已經被 蘋果公司 定義好了。如果想要 iBeacon 發出的數據包有更多的內容,那么我們就可以在應答包中做文章了,應答包是有 32 個字節的。我們只需要按照協議的內容向應答包中添加數據就可以了。
對于 Android 客戶端,通過 Scanresult.getScanRecord().getBytes() 獲得的廣播包是 62 個字節,它把上面原始數據包中的內容提取出來了,只保留了第二行內容。就是 藍牙廣播包第二行(30 byte) 藍牙應答包第二行(最多 32 byte,數目不確定),如果位數不夠的話就用 0 補充。
所以我們現在就可以很好根據獲得的 byte[] 數組來解析廣播包了。
// 現在就獲得廣播包了byte[] result = ScanResult.getScanRecord().getBytes();// UUID 包含 result[9] 和 result[24]result[9]---result[24];// Majorresult[25] result[26]// Minorresult[27] result[28] // Measured Powerresult[29] // 一般我們都是直接會先把 廣播包轉成 16 進制的格式然后來截取String uuid = broadcast.substring(18, 50); // 至于后面應答包的內容就要根據具體的廣播包格式來進行解析了,比如你們公司的硬件開發人員把電池電量放入了里面,那么你們就約定好放在什么位置,到時候你直接取就可以了。
這幾個方法所獲得內容都不是直接從 Android 中收到的廣播(ScanResult.getScanRecord().getBytes())中解析出來的,而是從原始數據包中解析的。
getTxPower 獲取傳輸功率,如果這個 iBeacon 不支持的話,那么結果就是 127
后面這幾個方法作用不大,關鍵看設備是否支持
關鍵方法
ScanRecord 中的這幾個方法就很重要的,這幾個方法都和我們收到的廣播包有關系。
比如:如果應答包中對 Tx Power Level 進行了設置我們就可以通過 getTxPowerLevel() 來直接獲取。比如上面例子中的廣播包,通過調用方法 getTxPowerLevel() 就可以得到 0
其他方法類似,只要你的應答包中數據的格式正確,就可以解析出來。
舉例說明:
比如 Android 端收到的廣播包是:
0201061AFF4C0002150123456789ABCDEF0123456789ABCDEF00000007C5 廣播包020A00 0303F1FF 0E16F1FF6400000007AC233F66C401 070965526F7574650000 應答包
getTxPowerLevel() 返回 0 因為在應答包中有正確的格式數據 020A00
getServiceData() 也會返回值,因為在應答包中有對應的數據 0E16F1FF6400000007AC233F66C401
0E 表示數據長度16 表示類型 此處表示 Service Data - 16-bit UUID (不僅僅是 UUID 還帶有數據) 前兩個字節表示 UUID 后面是數據F1FF 表示 UUID6400000007AC233F66C401 表示數據 Map
List
同樣的下面幾個方法也是對 Android 端收到的 62 byte 的廣播包中數據的解析所得
String getDeviceName() 獲得是名字 需要廣播包中有對應的數據 070965526F7574650000
SpareArray
byte[] getManufacturerSpecificData(int manufacture) 根據制造商代碼(4c 對應的十進制)獲得byte[] (0215)
還是有一些字段翻譯過來不夠精細,詳細見官方文檔:www.bluetooth.com/specificati…
Android核心知識點筆記github:https://github.com/AndroidCot/Android
本文就為大家講解到這里,希望對大家有所幫助。
標簽: