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