Android BLE開發(fā)的基礎(chǔ)知識

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.networkandroid.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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市跑杭,隨后出現(xiàn)的幾起案子铆帽,更是在濱河造成了極大的恐慌咆耿,老刑警劉巖德谅,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異萨螺,居然都是意外死亡窄做,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門慰技,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椭盏,“玉大人,你說我怎么就攤上這事吻商√图眨” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵艾帐,是天一觀的道長乌叶。 經(jīng)常有香客問我,道長柒爸,這世上最難降的妖魔是什么准浴? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮捎稚,結(jié)果婚禮上乐横,老公的妹妹穿的比我還像新娘。我一直安慰自己今野,他們只是感情好葡公,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著条霜,像睡著了一般催什。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蛔外,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天蛆楞,我揣著相機與錄音,去河邊找鬼夹厌。 笑死豹爹,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的矛纹。 我是一名探鬼主播臂聋,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了孩等?” 一聲冷哼從身側(cè)響起艾君,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肄方,沒想到半個月后冰垄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡权她,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年虹茶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隅要。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡蝴罪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出步清,到底是詐尸還是另有隱情要门,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布廓啊,位于F島的核電站欢搜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏崖瞭。R本人自食惡果不足惜狂巢,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望书聚。 院中可真熱鬧唧领,春花似錦、人聲如沸雌续。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驯杜。三九已至受啥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鸽心,已是汗流浹背滚局。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留顽频,地道東北人藤肢。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像糯景,于是被迫代替她去往敵國和親嘁圈。 傳聞我的和親對象是個殘疾皇子省骂,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容