BLE低功耗藍(lán)牙詳解,解決讀寫(xiě)撬陵、通知失敗問(wèn)題

開(kāi)發(fā)公司的智能鎖,通過(guò)藍(lán)牙控制网缝,是一種低功耗藍(lán)牙巨税,由于之前沒(méi)做過(guò),一路磕磕碰碰總算完成了粉臊,在此寫(xiě)下總結(jié)草添,幫助需要的朋友少走一些彎路,主要解決藍(lán)牙讀寫(xiě)數(shù)據(jù)和設(shè)置通知失敗的問(wèn)題扼仲。

開(kāi)發(fā)步驟:

  1. 檢測(cè)藍(lán)牙是否可用远寸,綁定藍(lán)牙服務(wù)
  2. 使用BluetoothAdapter.startLeScan來(lái)掃描低功耗藍(lán)牙設(shè)備
  3. 在掃描到設(shè)備的回調(diào)函數(shù)中會(huì)得到BluetoothDevice對(duì)象抄淑,并使用BluetoothAdapter.stopLeScan停止掃描
  4. 使用BluetoothDevice.connectGatt來(lái)獲取到BluetoothGatt對(duì)象
  5. 執(zhí)行BluetoothGatt.discoverServices,這個(gè)方法是異步操作驰后,在回調(diào)函數(shù)onServicesDiscovered中得到status肆资, 通過(guò)判斷status是否等于BluetoothGatt.GATT_SUCCESS來(lái)判斷查找Service是否成功
  6. 如果成功了,則通過(guò)BluetoothGatt.getService來(lái)獲取BluetoothGattService
  7. 接著通過(guò)BluetoothGattService.getCharacteristic獲取BluetoothGattCharacteristic
  8. 然后通過(guò)BluetoothGattCharacteristic.getDescriptor獲取BluetoothGattDescriptor

首先1-2步都是固定步驟灶芝,沒(méi)什么好說(shuō)的郑原,按照Android提供的Demo寫(xiě)就可以了,第3步掃描到設(shè)備會(huì)回調(diào)笙以,在回調(diào)中活烙,一般根據(jù)設(shè)備名稱找到想要連接的設(shè)備割岛,然后連接,獲取到BluetoothGatt對(duì)象酸役,然后在BluetoothGatt.discoverServices中會(huì)找到很多Services,根據(jù)硬件工程師提供的UUID連接你需要的Services驾胆;

//Ble服務(wù)發(fā)現(xiàn)回調(diào)
mBleService.setOnServicesDiscoveredListener(newBleService.OnServicesDiscoveredListener() {
@Override
public voidonServicesDiscovered(BluetoothGatt gatt,intstatus) {
List services = gatt.getServices();
for(BluetoothGattService service : services) {
if(service.getUuid().toString().equals(UUID_KEY_DATA)) {
LogUtil.d("藍(lán)牙服務(wù)找到了");
mReadCharacteristic= service.getCharacteristic(UUID_READ);
mWriteCharacteristic= service.getCharacteristic(UUID_WRITE);
break;
}
}
}
});

//設(shè)置通知
private BluetoothGatt mBluetoothGatt;
BluetoothGattCharacteristic characteristic;
boolean enabled;
...
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
...
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
//寫(xiě)入
if(mBluetoothGatt!=null) {
characteristic.setValue(value);
returnmBluetoothGatt.writeCharacteristic(characteristic);
}
//讀取
mBluetoothGatt.readCharacteristic(characteristic);

讀寫(xiě)和設(shè)置通知有幾個(gè)重載的方法簇捍,這里就只列舉其中一種,可以根據(jù)需求來(lái)寫(xiě)俏拱。
找到Services后再根據(jù)硬件工程師提供的UUID找到讀寫(xiě)和通知的UUID暑塑,然后就能進(jìn)行讀寫(xiě)操作了。這里有一個(gè)地方需要注意9亍J赂瘛!讀寫(xiě)和設(shè)置通知都是單步操作搞隐,必須執(zhí)行完一個(gè)才能執(zhí)行第二個(gè)驹愚,否則會(huì)操作失敗。劣纲,之前我在這個(gè)地方糾結(jié)了很久逢捺,網(wǎng)上搜索了很久找不到答案,官方demo里面也沒(méi)有關(guān)于讀寫(xiě)的操作癞季,網(wǎng)上大部分寫(xiě)的都是仿照官方demo寫(xiě)的原理之類的劫瞳。通知打開(kāi)或關(guān)閉其實(shí)也是一次寫(xiě)入的操作,這個(gè)在官方demo中有绷柒。
后來(lái)我查看源碼志于,終于找到了解決的辦法。(還是要多看源碼废睦,少搜索伺绽,養(yǎng)成了習(xí)慣就不好了,依賴性強(qiáng),不會(huì)獨(dú)立解決問(wèn)題)在源碼BluetoothGatt類中奈应,有讀寫(xiě)和通知的具體代碼澜掩,都包含了下面這段代碼,所以判斷都是單步操作杖挣。

synchronized(mDeviceBusy) {
if(mDeviceBusy)return false;
mDeviceBusy=true;
}

通過(guò)搜索mDeviceBusy=false找到了解決的答案肩榕,在每次執(zhí)行寫(xiě)、讀程梦、通知操作后都會(huì)有一個(gè)是否成功的回調(diào)点把,在回調(diào)中設(shè)置了mDeviceBusy=false,所以在回調(diào)中可以繼續(xù)下一步操作了屿附;在BluetoothGattCallback 中可以重寫(xiě)以下回調(diào)郎逃,根據(jù)具體業(yè)務(wù)邏輯來(lái)重寫(xiě),都是異步操作挺份。

// 發(fā)現(xiàn)Services回調(diào)
@Override
public voidonServicesDiscovered(BluetoothGatt gatt,intstatus) {
if(mOnServicesDiscoveredListener!=null) {
mOnServicesDiscoveredListener.onServicesDiscovered(gatt, status);
}

if(status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
}else{
Log.w(TAG,"onServicesDiscovered received: "+ status);
}

}
// 讀操作回調(diào)
@Override
public voidonCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,intstatus) {
if(mOnDataAvailableListener!=null) {
mOnDataAvailableListener.onCharacteristicRead(gatt, characteristic, status);
}
}
//寫(xiě)操作回調(diào)
@Override
public voidonCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,intstatus) {
super.onCharacteristicWrite(gatt, characteristic, status);
String address = gatt.getDevice().getAddress();
for(inti =0; i < characteristic.getValue().length; i++) {
Log.i(TAG,"address: "+ address +",Write: "+ characteristic.getValue()[i]);
}
if(mOnDataAvailableListener!=null) {
mOnDataAvailableListener.onCharacteristicWrite(gatt, characteristic,status);
}
}
//通知寫(xiě)入回調(diào)
@Override
public voidonDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
intstatus) {
if(mOnDataAvailableListener!=null) {
mOnDataAvailableListener.onDescriptorWrite(gatt, descriptor,status);
}
}
//通知收到數(shù)據(jù)的回調(diào)
@Override
public voidonCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
if(mOnDataAvailableListener!=null) {
mOnDataAvailableListener.onCharacteristicChanged(gatt, characteristic);
}
}

最后在BLE低功耗藍(lán)牙中最重要的三個(gè)操作完成了褒翰,剩下就是一些收尾工作,最后說(shuō)幾點(diǎn)需要注意的地方匀泊,釋放該釋放的資源避免內(nèi)存泄漏优训,這可以參考官方demo來(lái)寫(xiě);掃描到需要設(shè)備后記得停止掃描各聘;打開(kāi)通知后揣非,記得關(guān)閉通知,提高藍(lán)牙的性能躲因。
BLE官方demo
官方講解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末早敬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子大脉,更是在濱河造成了極大的恐慌搞监,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镰矿,死亡現(xiàn)場(chǎng)離奇詭異琐驴,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)秤标,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)绝淡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人抛杨,你說(shuō)我怎么就攤上這事够委。” “怎么了怖现?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我屈嗤,道長(zhǎng)潘拨,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任饶号,我火速辦了婚禮铁追,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茫船。我一直安慰自己琅束,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布算谈。 她就那樣靜靜地躺著涩禀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪然眼。 梳的紋絲不亂的頭發(fā)上艾船,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音高每,去河邊找鬼屿岂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鲸匿,可吹牛的內(nèi)容都是我干的爷怀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼带欢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼运授!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起洪囤,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤徒坡,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后瘤缩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喇完,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年剥啤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锦溪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡府怯,死狀恐怖刻诊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情牺丙,我是刑警寧澤则涯,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布复局,位于F島的核電站,受9級(jí)特大地震影響粟判,放射性物質(zhì)發(fā)生泄漏亿昏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一档礁、第九天 我趴在偏房一處隱蔽的房頂上張望角钩。 院中可真熱鬧,春花似錦呻澜、人聲如沸递礼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)脊髓。三九已至,卻和暖如春睹欲,著一層夾襖步出監(jiān)牢的瞬間供炼,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工窘疮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留袋哼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓闸衫,卻偏偏與公主長(zhǎng)得像涛贯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蔚出,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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