Android Bluetooth 與 Headset 通信

Android Bluetooth

本文主要記錄 Android 與藍(lán)牙設(shè)備通信過程的整個流程凤类,并對流程中的一些坑給出相應(yīng)的解決思路扛稽。
本文中的通信設(shè)備是藍(lán)牙耳機柴灯,其他藍(lán)牙設(shè)備整體思路及流程類似物延,視具體情況稍加調(diào)整

最近手上有個項目是基于移動端 App 與藍(lán)牙耳機通信的宣旱,死磕一番發(fā)現(xiàn)藍(lán)牙真的是...

for (int i = 0; i < 10000; i ++) {
    fuck("Android Bluetooth");
}

下圖是項目完成后整理的一份流程表,希望對大家有幫助

Android 藍(lán)牙連接流程

通過圖中所示流程相信大部分開發(fā)者都能清楚的了解到藍(lán)牙的整個連接過程教届,但是為什么要畫這張圖呢响鹃?是因為在圖中星標(biāo)的這些位置需要引起大家注意

獲取藍(lán)牙適配器

這是所有藍(lán)牙開發(fā)的第一步

在 Android API 17 及之前的版本中,需要通過 BluetoothAdapter 的 getDefaultAdapter() 函數(shù)進行獲取

在 Android API 18 開始可以通過 BluetoothManager 這個類的 getAdapter() 函數(shù)獲取到 BluetoothAdapter 對象

判斷藍(lán)牙開關(guān)

既然要用藍(lán)牙案训,你得保證它開著啊

開關(guān)檢測可以通過 BluetoothAdapter 的 isEnabled() 函數(shù)進行檢測买置,返回 true 表示已開啟,false 未開啟强霎,如果 BluetoothAdapter 為 null 則表示設(shè)備不支持藍(lán)牙

如果藍(lán)牙未開啟忿项,這個時候就需要申請開啟藍(lán)牙

這里特別說明,不要使用 mBluetoothAdapter.enable() 這句代碼來開啟藍(lán)牙城舞,在 Android 動態(tài)授權(quán)的機制出來后轩触,這句代碼在某些高版本的系統(tǒng)中無效,這對用戶體驗是致命的家夺,就好像你一拳打出去打在空氣中一樣脱柱?當(dāng)然,如果你覺得用戶體驗沒個屌用就請原諒在下這頓逼逼叨

為了保證通過較好的用戶體驗來打開藍(lán)牙拉馋,可以使用如下代碼申請

// REQUEST_ENABLE_BT 是定義的局部變量榨为,在 onActivityResult 會通過 requestCode 變量返回該值,用于識別操作類型
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);

然后在 Activity 的 onActivityResult() 函數(shù)中處理用戶的決定

掃描設(shè)備

掃描設(shè)備可以通過 BluetoothAdapter 的 startDiscovery() 開啟掃描設(shè)備煌茴,千萬要記得在發(fā)現(xiàn)目標(biāo)設(shè)備之后立即調(diào)用 cancelDiscovery() 關(guān)閉随闺。Google 官方也強調(diào)過掃描藍(lán)牙設(shè)備是一個比較耗的過程,所以能省則省

掃描到的設(shè)備會以廣播的形式回調(diào)給設(shè)備蔓腐,所以我們需要注冊 BluetoothDevice.ACTION_FOUND 的監(jiān)聽器矩乐,在這里便可以獲取到目標(biāo)設(shè)備的 BluetoothDevice 類

設(shè)備校驗

這里的設(shè)備校驗我采用的是通過名稱匹配的方式,我們的藍(lán)牙耳機出廠的設(shè)備名稱是有一定規(guī)律的回论,如:HeadsetHK_38913散罕、HeadsetHK_81390、HeadsetHK_34698

那我只要找到以 HeadsetHK_ 開頭的設(shè)備就嘗試進入下面的流程

可能有些同學(xué)會覺得這里的處理不夠嚴(yán)謹(jǐn)傀蓉,那是得看使用場景來的

如果用戶正常想要使用我們的藍(lán)牙耳機的場景下欧漱,他周圍剛好有一個名字同樣以 HeadsetHK_ 開頭的設(shè)備并且又不是我們的產(chǎn)品,這種概率大家自己掂量

為什么會選用這個不夠嚴(yán)謹(jǐn)?shù)姆绞絹磉M行校驗僚害,是因為在此之前硫椰,我也是希望能夠藍(lán)牙設(shè)備藍(lán)牙設(shè)備能夠給我一個反饋繁调,告訴 app 我是自己人,快拉我上車

但是通過 BluetoothSocket 去連接設(shè)備的時候發(fā)現(xiàn)一個問題靶草,藍(lán)牙不穩(wěn)定蹄胰,而且部分手機有些通信堵塞的感覺

在藍(lán)牙設(shè)備開機的情況下,BluetoothSocket 連接可能 3~5s 便可以進行通信奕翔,但是如果設(shè)備關(guān)機了裕寨,BluetoothSocket 連接的過程可能需要等上15~30s 才能給出反饋

當(dāng)然針對不同的使用場景需要采用不同的方案,這里只是將我的思路給出來分享給大家

設(shè)備配對

在 API 19 中派继,BluetoothDevice 類新增了 createBond() 函數(shù)宾袜,可用于主動配對設(shè)備,但是在此之前的版本中驾窟,我們需要通過反射的機制來進行主動配對庆猫。代碼如下

// 傳入的 device 就是希望配對的 BluetoothDevice 類
Method bond = BluetoothDevice.class.getMethod("createBond");
bond.invoke(device);

連接設(shè)備

再看看上面的流程圖,為什么我要將掃描設(shè)備绅络、設(shè)備校驗月培、連接設(shè)備和數(shù)據(jù)通信用星號標(biāo)出?

掃描設(shè)備是因為比較耗恩急,需要強調(diào)杉畜;設(shè)備校驗是為了提升能夠成功建立連接的準(zhǔn)確度;

那連接設(shè)備和數(shù)據(jù)通信為什么要單獨擰出來說明衷恭?而且還分為兩個步驟此叠?

按照我沒有了解之前,自以為連接成功就可以進行通信了随珠,然并卵

大家記得 Android 系統(tǒng)自帶的藍(lán)牙設(shè)置界面中灭袁,為什么有些系統(tǒng)在點擊掃描到的設(shè)備列表之后,點擊目標(biāo)設(shè)備第一次是設(shè)備配對牙丽,而第二次點擊才是連接設(shè)備简卧?

因為每個藍(lán)牙設(shè)備都是由0或者多個組件構(gòu)成的兔魂,這些組件有音視頻烤芦、拍照、定位等各個功能析校,而且每個設(shè)備都有一個主要和次要的組件

像藍(lán)牙耳機主要組件肯定就是音頻构罗,但是你不能肯定的說市面上所有藍(lán)牙耳機都沒有定位組件

說這些是為了告訴大家,既然藍(lán)牙模塊其實是N個功能組件的集合智玻,那我們是可以單獨與藍(lán)牙設(shè)備中的某一個功能組件建立連接的

同樣的遂唧,如果希望發(fā)起與藍(lán)牙設(shè)備的連接,也要使用反射

Method connect = btHeadsetCls.getMethod("connect", BluetoothDevice.class);
connect.setAccessible(true);
connect.invoke(bluetoothHeadset, device);

不論是配對還是連接的反射返回吊奢,都會返回一個 boolean 值告訴我們成功或者失敗盖彭,但是我可以確切的告訴大家,這兩個值是不可靠的,那這個時候我們怎么才能知道藍(lán)牙設(shè)備與我們的 App 連接成功呢召边?

需要監(jiān)聽 BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED铺呵,該廣播會反饋藍(lán)牙連接的當(dāng)前狀態(tài)

我們只需要在收到廣播之后,作出對應(yīng)的 UI 改變即可

數(shù)據(jù)通信

確保設(shè)備連接成功之后隧熙,就需要進行數(shù)據(jù)通信了

具體的通信方式這里不再贅述片挂,主要使用到的是 BluetoothDevice 類中的 createRfcommSocketToServiceRecord() 創(chuàng)建連接然后進行讀取

這里直接分享給大家一個網(wǎng)上找到工具類

<a target='_blank'>BluetoothChatUtil 藍(lán)牙通信連接工具類下載</a>


后話

其實文中還有很多沒有提及到的細(xì)節(jié)。例如對藍(lán)牙廣播的監(jiān)聽是否應(yīng)該放到 service 中贞盯?當(dāng)用戶在下拉菜單或者是轉(zhuǎn)到系統(tǒng)設(shè)置界面中進行藍(lán)牙設(shè)置的時候音念,我們 app 是接收不到廣播的。

本文沒有對藍(lán)牙權(quán)限獲取的步驟進行說明躏敢,直接從獲取藍(lán)牙適配器開始闷愤。后面會陸續(xù)整理出相應(yīng)的文章希望大家關(guān)注

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市件余,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蛾扇,老刑警劉巖攘烛,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異镀首,居然都是意外死亡坟漱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門更哄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芋齿,“玉大人,你說我怎么就攤上這事成翩∶倮Γ” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵麻敌,是天一觀的道長栅炒。 經(jīng)常有香客問我,道長术羔,這世上最難降的妖魔是什么赢赊? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮级历,結(jié)果婚禮上释移,老公的妹妹穿的比我還像新娘。我一直安慰自己寥殖,他們只是感情好玩讳,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布涩蜘。 她就那樣靜靜地躺著,像睡著了一般熏纯。 火紅的嫁衣襯著肌膚如雪皱坛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天豆巨,我揣著相機與錄音剩辟,去河邊找鬼。 笑死往扔,一個胖子當(dāng)著我的面吹牛贩猎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播萍膛,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吭服,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蝗罗?” 一聲冷哼從身側(cè)響起艇棕,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎串塑,沒想到半個月后沼琉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡桩匪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年打瘪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片傻昙。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡闺骚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妆档,到底是詐尸還是另有隱情僻爽,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布贾惦,位于F島的核電站胸梆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏纤虽。R本人自食惡果不足惜乳绕,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一绞惦、第九天 我趴在偏房一處隱蔽的房頂上張望逼纸。 院中可真熱鬧,春花似錦济蝉、人聲如沸杰刽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贺嫂。三九已至滓鸠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間第喳,已是汗流浹背糜俗。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留曲饱,地道東北人悠抹。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像扩淀,于是被迫代替她去往敵國和親楔敌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

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