前言
入職不久,也是剛剛接觸安卓開發(fā)。公司主要業(yè)務(wù)是嵌入式設(shè)備以及可穿戴設(shè)備。因此新人主要任務(wù)就是學(xué)習(xí)安卓藍(lán)牙開發(fā)。
由于沒(méi)有任何經(jīng)驗(yàn)因此在開發(fā)過(guò)程中踩到了許多坑,今天將這些填坑過(guò)程分享出來(lái),希望以后開發(fā)中避免這些問(wèn)題。
(一)傳遞對(duì)象而不傳遞地址
開發(fā)之初實(shí)現(xiàn)主界面搜索設(shè)備,點(diǎn)擊目標(biāo)設(shè)備進(jìn)入連接、通信界面的功能,因此需要傳遞目標(biāo)設(shè)備BluetoothDevice的相關(guān)信息。起初采用Intent傳遞Bluetooth.getAddress()方式傳遞藍(lán)牙的Mac地址,在ManagerActivity調(diào)用BluetoothDevice device = mBluetoothAdapter.getRemoteDevice()獲取設(shè)備。實(shí)際使用中發(fā)現(xiàn)此函數(shù)比較耗時(shí),影響效率。
解決辦法:使用Intent傳遞BluetoothDevice對(duì)象。BluetoothDevice實(shí)現(xiàn)了Parcelable接口,可以使用Intent直接傳遞。
(二)加上延時(shí),保證執(zhí)行完畢
手機(jī)端打開藍(lán)牙、關(guān)閉藍(lán)牙、開啟搜索和停止搜索都需要一定的時(shí)間來(lái)完成,因此在執(zhí)行以上操作后最好加上一段延時(shí),等待對(duì)應(yīng)操作完成后再去執(zhí)行下一步。
(三) BLE藍(lán)牙連接參數(shù)
經(jīng)典藍(lán)牙建立連接后類似于Socket通信,出現(xiàn)問(wèn)題的情況不多。遇到問(wèn)題的情況大多數(shù)出現(xiàn)在BLE藍(lán)牙中。
device.connectGatt(context, autoConnect, callback);第二個(gè)參數(shù)最好設(shè)置為false,實(shí)際測(cè)試發(fā)現(xiàn)設(shè)置為false連接速度更快。
(四)找準(zhǔn)UUID,成功開啟監(jiān)聽
BLE藍(lán)牙的服務(wù)和特征都是通過(guò)UUID來(lái)查找的,開發(fā)時(shí)一定要區(qū)分好哪個(gè)BluetoothGattCharacteristic是用于setCharacteristicNotification的,哪個(gè)BluetoothGattCharacteristic是用于writeCharacteristic的。
setCharacteristicNotification函數(shù)用于開啟監(jiān)聽,執(zhí)行成功后相當(dāng)于與設(shè)備建立通信通道,之后可以通過(guò)寫入命令指令來(lái)獲取設(shè)備中的數(shù)據(jù)。
setCharacteristicNotification的返回值基本上一直都是true,但是不代表開啟監(jiān)聽成功。通過(guò)查看谷歌官方BLEdemo發(fā)現(xiàn)安卓系統(tǒng)下還需要設(shè)置用于監(jiān)聽下BluetoothGattCharacteristic的UUID為"00002902-0000-1000-8000-00805f9b34fb"的BluetoothGattDescriptor的Value為BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE。
當(dāng)設(shè)置成功后回調(diào)onDescriptorWrite,當(dāng)status == BluetoothGatt.GATT_SUCCESS基本上才能實(shí)現(xiàn)開啟監(jiān)聽。而且開啟監(jiān)聽以后最好還是要等待200ms左右再向設(shè)備發(fā)命令,等待設(shè)備和手機(jī)建立穩(wěn)定通信通道。
(五)最多20字節(jié)
成功開啟監(jiān)聽后,終于可以與設(shè)備通信了。我使用的設(shè)備是一個(gè)便攜式心電計(jì)。上位機(jī)發(fā)送命令指令,下位機(jī)回復(fù)的數(shù)據(jù)格式均為64字節(jié),然后將64字節(jié)解析出心率和心電圖數(shù)據(jù)。理想很豐滿,然而實(shí)際使用中才發(fā)現(xiàn)每次回調(diào)onCharacteristicChanged方法獲取的數(shù)據(jù)最多20字節(jié),64字節(jié)的數(shù)據(jù)分成了4包發(fā)送上來(lái)。
解決辦法:只能用緩沖區(qū)接收了,判斷緩沖區(qū)大小、判斷緩沖區(qū)第一個(gè)字節(jié),根據(jù)數(shù)據(jù)頭讀取緩沖區(qū),并進(jìn)一步解析數(shù)據(jù)。
不過(guò)值得慶幸的是上位機(jī)命令指令均小于20字節(jié),起碼寫入數(shù)據(jù)不需要分包發(fā)送,如果真有遇到這種特殊情況的請(qǐng)看BLE分包發(fā)送。
既然最多20字節(jié)一包數(shù)據(jù),大數(shù)據(jù)通信就不要考慮BLE了。
(六)一定要關(guān)閉連接
我就有一段程序在通信完畢后忘記了斷開連接,發(fā)現(xiàn)之后再次連接設(shè)備以后每寫入一次命令onCharacteristicChanged回調(diào)多次相同數(shù)據(jù),使得緩沖區(qū)處理出現(xiàn)問(wèn)題。感覺就是建立了多個(gè)連接通道。在通信出錯(cuò)或者完成同步之后一定要調(diào)用mBluetoothGatt.disconnect();
mBluetoothGatt.close();
斷開當(dāng)前連接。
(七)加密BLE設(shè)備
大多數(shù)BLE設(shè)備是非加密的,也就是不需要與手機(jī)配對(duì)即可通信。大部分軟件都是同步BLE設(shè)備的中數(shù)據(jù)到手機(jī)端,整個(gè)流程也是自動(dòng)執(zhí)行的。大體流程就是:掃描目標(biāo)設(shè)備、開啟連接、連接成功掃描服務(wù),掃到服務(wù)開啟監(jiān)聽、收發(fā)數(shù)據(jù)、斷開連接。
BLE設(shè)備加密后在連接設(shè)備時(shí)會(huì)彈出系統(tǒng)藍(lán)牙配對(duì)對(duì)話框,等待用戶配對(duì)。按常理說(shuō)此時(shí)設(shè)備是沒(méi)有建立連接的,因?yàn)檫€沒(méi)有配對(duì)成功,但是安卓手機(jī)端不僅可以完成建立連接,而且還能掃描到服務(wù)。如果按照自動(dòng)流程就去開啟監(jiān)聽是無(wú)法成功的,因?yàn)樵O(shè)備還沒(méi)有配對(duì)成功。
解決辦法:監(jiān)聽系統(tǒng)關(guān)于藍(lán)牙配對(duì)的廣播,在完成配對(duì)之后在去開啟監(jiān)聽。如果是已經(jīng)配對(duì)的設(shè)備不會(huì)由藍(lán)牙配對(duì)廣播,只需按照不加密設(shè)備流程執(zhí)行即可。
(八)6.0以上權(quán)限問(wèn)題
最初測(cè)試用的設(shè)備比較老舊,有天用新手機(jī)測(cè)試發(fā)現(xiàn)根本不能掃描到藍(lán)牙設(shè)備,查詢之后發(fā)現(xiàn)是權(quán)限問(wèn)題。安卓6.0以后掃描藍(lán)牙需要模糊定位權(quán)限
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
安卓隨著版本提升對(duì)于權(quán)限限制更加嚴(yán)格,還是學(xué)著用動(dòng)態(tài)申請(qǐng)權(quán)限吧。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
(九)碎片化帶來(lái)各種問(wèn)題
安卓系統(tǒng)碎片化導(dǎo)致遇到了各種奇葩問(wèn)題:
華為mate8 mate9 榮耀6a無(wú)法主動(dòng)斷開與加密BLE設(shè)備連接,除非取消配對(duì)或者關(guān)閉某一方的藍(lán)牙。
魅族Flyme系統(tǒng)第一次配對(duì)成功后不能斷開連接,以后使用可以正常斷開。
部分手機(jī)在BLE設(shè)備連接上之后會(huì)主動(dòng)斷開一次連接,然后馬上又重新連接上設(shè)備。
結(jié)語(yǔ)
以上就是本人在安卓藍(lán)牙開發(fā)中遇到的諸多問(wèn)題,由于缺乏經(jīng)驗(yàn)和能力相對(duì)不足,踩到了很多坑,不過(guò)在填坑過(guò)程中提高自身能力也是很滿足的。