1.前言
隨著智能穿戴的普及,藍(lán)牙開發(fā)也火熱起來划提。不過與傳統(tǒng)藍(lán)牙開發(fā)不一樣的是万牺,由于考慮到穿戴設(shè)備的電量問題和使用場景纵竖,即數(shù)據(jù)量小、離散傳輸和近距離通信杏愤,所以采用基于藍(lán)牙4.0規(guī)范的BLE設(shè)備靡砌。
雖然在開發(fā)時調(diào)用的API有些不同,但流程大致相同珊楼,可以找到一些共通點通殃,在此做個大概的歸納:
- 設(shè)置藍(lán)牙權(quán)限,檢測設(shè)備支持厕宗,啟動藍(lán)牙画舌;
- 查找藍(lán)牙設(shè)備(傳統(tǒng)方式較為復(fù)雜,需先讓遠(yuǎn)程設(shè)備可被檢測已慢,然后獲取設(shè)備信息并配對曲聂,才能建立加密連接);
- 連接藍(lán)牙設(shè)備(由于使用場景不同佑惠,所以協(xié)議也不同朋腋。傳統(tǒng)方式使用Socket協(xié)議,需雙方通過套接字識別膜楷,建立穩(wěn)定的流式傳輸通道旭咽,通信量大但耗電。BLE則使用GATT協(xié)議赌厅,傳輸數(shù)據(jù)塊穷绵,通過回調(diào)的方法進行讀寫和通知操作,通信量小特愿、不連續(xù)但省電仲墨。)
- 解析通信數(shù)據(jù)勾缭,根據(jù)配置協(xié)議取出數(shù)據(jù),交由業(yè)務(wù)邏輯判斷目养,并給予內(nèi)容的顯示或操作上的回應(yīng)漫拭。
- 關(guān)閉藍(lán)牙設(shè)備,畢竟是很耗資源的功能混稽,不用記得釋放采驻。
由此可知,不管開沒開發(fā)過藍(lán)牙匈勋,開發(fā)的是什么版本的藍(lán)牙礼旅,其實不影響學(xué)習(xí)和理解BLE開發(fā)。
2.關(guān)鍵術(shù)語和概念
BLE洽洁,全稱Bluetooth Low Energy痘系,即低功耗藍(lán)牙。除了遠(yuǎn)程設(shè)備支持外饿自,安裝應(yīng)用的手機必須大于安卓4.3(API 18)版本才行汰翠。這方面的知識官網(wǎng)的開發(fā)指南上有明確的說明,若覺得英文不方便看昭雌,有人已經(jīng)翻譯了复唤,下面主要是說一下關(guān)鍵點。
2.1.GATT協(xié)議
GATT分為三部分Service烛卧、Characteristic佛纫、Descriptor,這三部分都由UUID作為唯一標(biāo)示符总放。一個藍(lán)牙4.0的終端可以包含多個Service呈宇,表示自己具有不同的功能;一個Service可以包含多個Characteristic局雄,意味著一個功能由不同的特征共同描述甥啄;一個Characteristic包含一個Value和多個Descriptor,說明每個特征都是一個數(shù)值和多個幫助理解值含義的相關(guān)信息組成炬搭;一個Descriptor包含一個Value蜈漓,類似XML文件中的<tag>
,是附加信息尚蝌。需要注意的是迎变,Characteristic和Descriptor是存放數(shù)據(jù)的地方,具有相關(guān)讀寫權(quán)限或者操作屬性的設(shè)置飘言。
2.2.角色和責(zé)任
設(shè)備的角色是固定的,中央設(shè)備具有掃描的功能驼侠,通過廣播獲取外圍設(shè)備列表姿鸿;外圍設(shè)備則是數(shù)據(jù)采集的功能谆吴,并發(fā)出廣播方便被搜索到。
但是苛预,設(shè)備的責(zé)任是相對的句狼,服務(wù)端作為數(shù)據(jù)的來源,而客戶端則是獲取數(shù)據(jù)的那一方热某,不管主動還是被動腻菇。
配置協(xié)議主要是告訴開發(fā)人員厌漂,數(shù)據(jù)的格式和內(nèi)容叛甫,該如何讀寫。
3.位置權(quán)限
基本權(quán)限和設(shè)備支持判斷就不講了狮崩,大家看官方說明就行了秘遏。使用藍(lán)牙時還需要獲取位置信息丘薛,根據(jù)信息的來源和系統(tǒng)的版本有些不同的設(shè)置,具體如下描述:
- 5.0系統(tǒng)(API 21)之前邦危,當(dāng)信息僅來自于網(wǎng)絡(luò)位置時洋侨,需添加權(quán)限
ACCESS_COARSE_LOCATION
。而當(dāng)位置信息來自于GPS或來自于網(wǎng)絡(luò)和GPS時倦蚪,只需添加權(quán)限ACCESS_FINE_LOCATION
希坚,系統(tǒng)會自動申請硬件功能。 - 而5.0系統(tǒng)之后陵且,系統(tǒng)不再自動申請吏够,需根據(jù)位置信息的來源分別添加如
android.hardware.location.network
或android.hardware.location.gps
相關(guān)硬件功能聲明。
4.BluetoothAdapter
這個類映射了設(shè)備的藍(lán)牙模塊滩报,藍(lán)牙功能的使用將從它開始锅知。
常用方法 | 作用解釋 |
---|---|
getDefaultAdapter() | 獲取藍(lán)牙適配器,安卓4.3之后引入BluetoothManager脓钾,也可以通過它獲取實例 |
getRemoteDevice(String address) | 遠(yuǎn)程設(shè)備是通過MAC地址識別的售睹,通過這個方法獲取實例 |
isEnabled() | 判斷藍(lán)牙是否打開,可通過enable()和disable()靜默地切換狀態(tài)可训,也可以通過Intent提示用戶操作 |
startLeScan(BluetoothAdapter.LeScanCallback callback) | 開啟LE藍(lán)牙的搜索昌妹,另有方法對Service的UUID進行搜索 |
stopLeScan(BluetoothAdapter.LeScanCallback callback) | 關(guān)閉LE藍(lán)牙的搜索,找到目標(biāo)設(shè)備或到了設(shè)定時間就關(guān)閉 |
搜索BLE和傳統(tǒng)藍(lán)牙使用不同的方法握截,所以不能同時搜索兩種設(shè)備飞崖。
5.LeScanCallback
傳統(tǒng)藍(lán)牙是通過BroadcastReceiver監(jiān)聽ACTION_FOUND
的意圖獲取每個搜索到的設(shè)備,而BLE則是通過回調(diào)這個類的方法谨胞。
private LeDeviceListAdapter mLeDeviceListAdapter;
...
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
6. BluetoothGatt
此對象是對GATT協(xié)議的封裝固歪,通過調(diào)用遠(yuǎn)程設(shè)備BluetoothDevice的connectGatt(Context, boolean, BluetoothGattCallback)
方法可以獲取,布爾類型參數(shù)表示是否斷后重連。由于是從遠(yuǎn)程設(shè)備處獲取信息牢裳,所以遠(yuǎn)程設(shè)備是服務(wù)端而安卓設(shè)備是客戶端逢防。BluetoothGatt對象可對客戶端進行相關(guān)操作。
常用方法 | 作用解釋 |
---|---|
getDevice() | 獲取GATT客戶端連接的遠(yuǎn)程設(shè)備 |
getService(UUID uuid) | 獲取遠(yuǎn)程設(shè)備提供的某個服務(wù) |
getServices() | 獲取遠(yuǎn)程設(shè)備提供的所以服務(wù) |
close() | 關(guān)閉GATT客戶端 |
connect() | 重連遠(yuǎn)程設(shè)備 |
disconnect() | 斷開已建立的連接或取消正在嘗試的連接 |
discoverServices() | 發(fā)現(xiàn)遠(yuǎn)程設(shè)備提供的服務(wù)以及它們的特性和描述 |
setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enable) | 當(dāng)指定特征的值變化時蒲讯,是否發(fā)出通知/指示 |
readCharacteristic(BluetoothGattCharacteristic characteristic) | 從相關(guān)的遠(yuǎn)程設(shè)備讀取所請求的特征 |
readDescriptor(BluetoothGattDescriptor descriptor) | 從相關(guān)的遠(yuǎn)程設(shè)備讀取給定描述的值 |
writeCharacteristic(BluetoothGattCharacteristic characteristic) | 將指定的特征及值寫入相關(guān)的遠(yuǎn)程設(shè)備 |
writeDescriptor(BluetoothGattDescriptor descriptor) | 將指定的描述值寫入相關(guān)的遠(yuǎn)程設(shè)備 |
7.BluetoothGattCallback
BluetoothGatt對象的操作將會回調(diào)BluetoothGattCallback的相應(yīng)方法來向用戶反映結(jié)果忘朝,方便進一步的判斷和操作。
new BluetoothGattCallback() {
// gatt為管理GATT客戶端的對象
@Override // status為變化前狀態(tài)判帮,newState為變化后狀態(tài)局嘁,由connect()和disconnect()方法引起
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
// TODO: 當(dāng)GATT客戶端與服務(wù)端連接狀態(tài)發(fā)生改變時觸發(fā),執(zhí)行連接狀態(tài)相關(guān)業(yè)務(wù)
}
@Override // status為是否發(fā)現(xiàn)成功晦墙,由discoverServices()方法引起
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
// TODO: 當(dāng)GATT客戶端從服務(wù)端發(fā)現(xiàn)新的支持服務(wù)時觸發(fā)悦昵,執(zhí)行GATT數(shù)據(jù)解析,為讀寫更新提供對象
}
@Override // characteristic發(fā)生改變的特征偎痛,由setCharacteristicNotification()方法設(shè)置
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
// TODO: 當(dāng)GATT服務(wù)端被指定的特征發(fā)生改變而發(fā)送通知時觸發(fā)旱捧,更新UI或執(zhí)行處理業(yè)務(wù)
}
@Override // characteristic讀取的特征,status讀取狀態(tài)踩麦,由readCharacteristic()方法引起
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
// TODO: 當(dāng)GATT客戶端讀取指定特征時觸發(fā)枚赡,判斷并執(zhí)行顯示或處理業(yè)務(wù)
}
@Override // characteristic寫入的特征,status寫入狀態(tài)谓谦,由writeCharacteristic()方法引起
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
// TODO: 當(dāng)GATT客戶端向指定特征寫入時觸發(fā)贫橙,判斷并檢測寫入的值是否正確
}
@Override // descriptor讀取的描述,status讀取狀態(tài)反粥,由readDescriptor()方法引起
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
// TODO: 當(dāng)GATT客戶端讀取指定描述時觸發(fā)卢肃,判斷并執(zhí)行顯示或處理業(yè)務(wù)
}
@Override // descriptor寫入的描述,status寫入狀態(tài)才顿,由writeDescriptor()方法引起
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
// TODO: 當(dāng)GATT客戶端向指定描述寫入時觸發(fā)莫湘,判斷并檢測寫入的值是否正確
}
};
}
8.關(guān)閉客戶端
當(dāng)你的應(yīng)用不在需要BLE功能時,記得關(guān)閉并讓系統(tǒng)釋放資源郑气。
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
9.總結(jié)
以上按照操作流程將涉及的關(guān)鍵類介紹了一遍幅垮,具體實現(xiàn)官方給出了Demo。大概講一下思路尾组,Activity展示數(shù)據(jù)和響應(yīng)用戶操作忙芒,BroadcastReceiver執(zhí)行界面更新等具體業(yè)務(wù),Service在Activity的控制下與BLE模塊交互讳侨,詳情參考這篇博客呵萨。
Characteristic和Descriptor的讀取權(quán)限需通過位運算符的組合來設(shè)置,就是XX|XX
跨跨,大家肯定不陌生潮峦,相關(guān)分解識別代碼可以參考這篇文章。
最后提供幾個實際項目的博客鏈接供大家參考:
http://www.cnblogs.com/cxk1995/p/5693979.html
http://www.cnblogs.com/wobeinianqing/category/694014.html
http://www.cnblogs.com/heiyue/tag/bluetooth/default.html?page=15