前言
上一篇文章中我們已經(jīng)認(rèn)識(shí)了gatt的基本機(jī)構(gòu)以及如何獲得gatt中的Service以及Characteristic试躏,接下來我們將學(xué)習(xí)對(duì)于Characteristic的基本操作设褐,并使用這些基本操作助析,來操縱小米手環(huán),實(shí)現(xiàn)一些有趣的功能寡键。
我們可以大體想想一下小米手環(huán)所實(shí)現(xiàn)的功能:
- 計(jì)步獲取
- 震動(dòng)
- 電量信息獲取
- Led顏色控制
- User信息
- 睡眠監(jiān)測(cè)
等等雪隧。
這里我們選取一些有意思的功能進(jìn)行實(shí)現(xiàn)员舵,比如震動(dòng)藕畔,led控制劫流,計(jì)步獲取等。
porfile和協(xié)議的獲取
因?yàn)橹拔覀円呀?jīng)可以對(duì)輕松的獲得小米手環(huán)GATT的結(jié)構(gòu)仍秤,所有的service可很、characteristic、descriptor等的UUID苇本,但是我們對(duì)于每一個(gè)UUID所實(shí)現(xiàn)的功能菜拓,以及每個(gè)功能所使用的解析方式(也就是協(xié)議)是無從得知的纳鼎。
這里我們能夠想到的解決這些問題的方式有兩種:
- 網(wǎng)絡(luò)資料中獲取。顯然網(wǎng)上肯定有很多破解小米手環(huán)的文章劝贸,但是我們發(fā)現(xiàn)所有的文章里面也只有對(duì)獲取步數(shù)等基本的信息逗宁,而且很多嘗試后都是錯(cuò)誤的。
- 自己動(dòng)手反編譯小米運(yùn)動(dòng)APP件甥。首先這個(gè)APP肯定經(jīng)過了混淆編譯的言缤,反編譯后的源碼閱讀是很困難的管挟,但是也不是不可讀的弄捕,只要愿意花費(fèi)時(shí)間导帝,還是可以完全破解他的穿铆。但是畢竟時(shí)間有限荞雏,我們結(jié)合我們想要的,查找想要的信息悦陋。
最終我們獲得以下的characteristic的UUID:
//alertchar
public static final UUID IMMIDATE_ALERT_CHAR_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
//計(jì)步char:讀取該UUID下的value數(shù)組 第0 個(gè)數(shù)據(jù)就是 步數(shù)
public static final UUID STEP_CHAR_UUID = UUID.fromString("0000ff06-0000-1000-8000-00805f9b34fb");
//電量信息
public static final UUID BATTERY_CHAR_UUID = UUID.fromString("0000ff0c-0000-1000-8000-00805f9b34fb");
//用戶信息char
public static final UUID USER_INFO_CHAR_UUID = UUID.fromString("0000ff04-0000-1000-8000-00805f9b34fb");
//控制點(diǎn)char
public static final UUID CONTROL_POINT_CHAR_UUID = UUID.fromString("0000ff05-0000-1000-8000-00805f9b34fb");
而我們想要實(shí)現(xiàn)的功能都將是對(duì)這些characteristic進(jìn)行操作完成的俺驶。
Characteristic的基本操作
任何BLE功能的實(shí)現(xiàn)都要對(duì)characteristic進(jìn)行操作棍辕,
主要包括有三種:
- 讀取特征值
- 寫入特征值
- 特征值的變化通知
以下我們將用代碼說明如何進(jìn)行讀寫特征值:
** 讀取特征值 **
當(dāng)從GATT中獲取到該特征后,利用該特征的對(duì)象讀取他的值:
mGatt.readCharacteristic(characteristic);
然后從讀操作的回調(diào)函數(shù)中獲取特征值:
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d(TAG, "onCharacteristicRead UUID : " + characteristic.getUuid());
byte[] data = characteristic.getValue();
}
** 寫特征值 **
寫特征值的操作和讀是一樣的:
gatt寫操作:
byte[] value;
characteristic.setValue(value);
mGatt.writeCharacteristic(characteristic);
回調(diào)中獲取寫的結(jié)果
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d(TAG, "onCharacteristicWrite UUID: " + characteristic.getUuid() + "state : " + status);
}
** 通知變化 **
這個(gè)名字好像并不能很好的說明這個(gè)功能是干什么的,但是看英文名字就一目了然了栋荸,setCharacteristicNotification,很顯然就是設(shè)置監(jiān)聽特征值凭舶,監(jiān)聽到它發(fā)生變化后,就會(huì)觸發(fā)回調(diào)函數(shù):
mGatt.setCharacteristicNotification(characteristic, enable)
BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(Profile.notificationDesUUID);
clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
//clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
mGatt.writeDescriptor(clientConfig);
在Descritor的寫入回調(diào):
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
Log.d(TAG, "onDescriptorWrite");
gatt.readCharacteristic(batteryChar);
}
功能實(shí)現(xiàn)
我們知道了那個(gè)Characteristic實(shí)現(xiàn)什么功能匆背,并知道了如何操作钝尸,在得到他們之間的協(xié)議(即怎么解析value值)皆可以實(shí)現(xiàn)以上的所有功能搂根,下面我結(jié)合我們知道的簡(jiǎn)單的說一下他們的實(shí)現(xiàn)。
具體實(shí)現(xiàn)細(xì)節(jié)查看Demo的源碼中xParser.java:
計(jì)步
計(jì)步功能的可以由兩種實(shí)現(xiàn):
- 每隔一段時(shí)間讀取一下步數(shù)猪叙。
- 事實(shí)顯示步數(shù),即每走一步更新一次犬第。
很顯然1是通過讀取特征值芒帕,2是通過變化通知實(shí)現(xiàn)的背蟆。
讀取特征值,解析后表示步數(shù)带膀。
byte stepNum = characteristic.getValue;
震動(dòng)
震動(dòng)很明顯是通過寫入特征值實(shí)現(xiàn)的本砰,相當(dāng)于往手環(huán)寫入命令。
寫入Immidate Alert特征值能夠?qū)崿F(xiàn)震動(dòng)舔株。
經(jīng)測(cè)試还棱,寫入的數(shù)值為 0x01,0x2,0x03,0x04均能實(shí)現(xiàn)震動(dòng)珍手,震感好像是一樣的,震動(dòng)的次數(shù)好像不同寡具,還未詳細(xì)進(jìn)行統(tǒng)計(jì)稚补。
電量信息
電量信息,包括了電量百分比顯示厦坛、充電狀態(tài)乍惊、上一次充電時(shí)間等均可以讀取润绎。
當(dāng)然電量也是既可以讀取诞挨,也可以通知了小作。
整個(gè)電量的信息通過解析電量特征值獲得:
byte[] batteryInfo = characteristic.getValue;
Led控制
尚未實(shí)現(xiàn)顾稀,后續(xù)補(bǔ)充坝撑。
Demo: MiBandReader
Github地址:** MiBandReader **
- 震動(dòng)(通過Immidate Alert實(shí)現(xiàn),0x02震動(dòng)10次)
- 獲取實(shí)時(shí)步數(shù)
- 電量信息(百分比電量/充電狀態(tài)/上次充電時(shí)間/充電次數(shù))
- 修復(fù)連接斷開問題抚笔,主動(dòng)或者通過代碼配對(duì)
調(diào)戲別人的手環(huán)
首先我們要知道的手環(huán)手邊之類的周邊設(shè)備有這樣的一個(gè)特性:** 一旦建立了GATT連接就不再被掃描到 **侨拦,所以理論上我們是沒有機(jī)會(huì)對(duì)別人的手環(huán)手表下手的狱从,但是我們不能忽略的一個(gè)問題是,大家對(duì)于耗電的恐懼敞葛。
你掃描一下你周圍的Ble設(shè)備就會(huì)發(fā)現(xiàn)有不少的Band与涡,watch之類的ble設(shè)備驼卖,都沒有跟手機(jī)進(jìn)行連接,因?yàn)樗麄兛赡苡X得看著藍(lán)牙那個(gè)標(biāo)志就覺得耗電吧儒飒,也不管你低功耗高功耗檩奠,直接一關(guān)了之。
所以井誉,機(jī)會(huì)是有的,但是要考慮風(fēng)險(xiǎn)和后果整胃。調(diào)戲之前先確定好調(diào)戲的對(duì)象具有充分的可調(diào)戲性颗圣。危險(xiǎn)動(dòng)作,后果自負(fù),別問我怎么知道的在岂!
相關(guān)閱讀
Android BLE開發(fā)之初識(shí)GATT