『壹』 android-Ble藍牙開發Demo示例–掃描,連接,發送和接收數據,分包解包(附源碼)
萬物互聯的物聯網時代的已經來臨,ble藍牙開發在其中扮演著舉重若輕的角色。最近剛好閑一點,抽時間梳理下這塊的知識點。
涉及ble藍牙通訊的客戶端(開啟、掃描、連接、發送和接收數據、分包解包)和服務端(初始化廣播數據、開始廣播、配置Services、Server回調操作)整個環節以及一些常見的問題即踩過的一些坑。
比如
1、在Android不同版本或不同手機的適配問題,掃描不到藍牙設備
2、如何避免ble藍牙連接出現133錯誤?
3、單次寫的數據大小有20位元組限制,如何發送長數據
藍牙有傳統(經典)藍牙和低功耗藍牙BLE(Bluetooth Low Energy)之分,兩者的開發的API不一樣,本文主講Ble藍牙開發,傳統藍牙不展開,有需要的可以自行了解。
相對傳統藍牙,BLE低功耗藍牙,主要特點是快速搜索,快速連接,超低功耗保持連接和數據傳輸。
客戶端
服務端
Android4.3(API Level 18)開始引入BLE的核心功能並提供了相應的 API。應用程序通過這些 API 掃描藍牙設備、查詢 services、讀寫設備的 characteristics(屬性特徵)等操作。
BLE藍牙協議是GATT協議, BLE相關類不多, 全都位於android.bluetooth包和android.bluetooth.le包的幾個類:
android.bluetooth.
.BluetoothGattService 包含多個Characteristic(屬性特徵值), 含有唯一的UUID作為標識
.BluetoothGattCharacteristic 包含單個值和多個Descriptor, 含有唯一的UUID作為標識
.BluetoothGattDescriptor 對Characteristic進行描述, 含有唯一的UUID作為標識
.BluetoothGatt 客戶端相關
.BluetoothGattCallback 客戶端連接回調
.BluetoothGattServer 服務端相關
.BluetoothGattServerCallback 服務端連接回調
android.bluetooth.le.
.AdvertiseCallback 服務端的廣播回調
.AdvertiseData 服務端的廣播數據
.AdvertiseSettings 服務端的廣播設置
.BluetoothLeAdvertiser 服務端的廣播
.BluetoothLeScanner 客戶端掃描相關(Android5.0新增)
.ScanCallback 客戶端掃描回調
.ScanFilter 客戶端掃描過濾
.ScanRecord 客戶端掃描結果的廣播數據
.ScanResult 客戶端掃描結果
.ScanSettings 客戶端掃描設置
BLE設備分為兩種設備: 客戶端(也叫主機/中心設備/Central), 服務端(也叫從機/外圍設備/peripheral)
客戶端的核心類是 BluetoothGatt
服務端的核心類是 BluetoothGattServer 和 BluetoothLeAdvertiser
BLE數據的核心類是 BluetoothGattCharacteristic 和 BluetoothGattDescriptor
下面詳細講解下客戶端和服務端的開發步驟流程
安卓手機涉及藍牙許可權問題,藍牙開發需要在AndroidManifest.xml文件中添加許可權聲明:
在搜索設備之前需要詢問打開手機藍牙:
注意: BLE設備地址是動態變化(每隔一段時間都會變化),而經典藍牙設備是出廠就固定不變了!
通過掃描BLE設備,根據設備名稱區分出目標設備targetDevice,下一步實現與目標設備的連接,在連接設備之前要停止搜索藍牙;停止搜索一般需要一定的時間來完成,最好調用停止搜索函數之後加以100ms的延時,保證系統能夠完全停止搜索藍牙設備。停止搜索之後啟動連接過程;
BLE藍牙的連接方法相對簡單只需調用connectGatt方法;
參數說明
與設備建立連接之後與設備通信,整個通信過程都是在BluetoothGattCallback的非同步回調函數中完成;
BluetoothGattCallback中主要回調函數如下:
上述幾個回調函數是BLE開發中不可缺少的;
當調用targetdDevice.connectGatt(context, false, gattCallback)後系統會主動發起與BLE藍牙設備的連接,若成功連接到設備將回調onConnectionStateChange方法,其處理過程如下:
判斷newState == BluetoothGatt.STATE_CONNECTED表明此時已經成功連接到設備;
mBluetoothGatt.discoverServices();
掃描BLE設備服務是安卓系統中關於BLE藍牙開發的重要一步,一般在設備連接成功後調用,掃描到設備服務後回調onServicesDiscovered()函數,函數原型如下:
BLE藍牙開發主要有負責通信的BluetoothGattService完成的。當且稱為通信服務。通信服務通過硬體工程師提供的UUID獲取。獲取方式如下:
具體操作方式如下:
開啟監聽,即建立與設備的通信的首發數據通道,BLE開發中只有當客戶端成功開啟監聽後才能與服務端收發數據。開啟監聽的方式如下:
BLE單次寫的數據量大小是有限制的, 通常是20位元組 ,可以嘗試通過requestMTU增大,但不保證能成功。分包寫是一種解決方案,需要定義分包協議,假設每個包大小20位元組,分兩種包,數據包和非數據包。對於數據包,頭兩個位元組表示包的序號,剩下的都填充數據。對於非數據包,主要是發送一些控制信息。
監聽成功後通過向 writeCharacteristic寫入數據實現與服務端的通信。寫入方式如下:
其中:value一般為Hex格式指令,其內容由設備通信的藍牙通信協議規定;
若寫入指令成功則回調BluetoothGattCallback中的onCharacteristicWrite()方法,說明將數據已經發送給下位機;
若發送的數據符合通信協議,則服務端會向客戶端回復相應的數據。發送的數據通過回調onCharacteristicChanged()方法獲取,其處理方式如下:
通過向服務端發送指令獲取服務端的回復數據,即可完成與設備的通信過程;
當與設備完成通信之後之後一定要斷開與設備的連接。調用以下方法斷開與設備的連接:
源碼上傳在CSDN上了,有需要的可以借鑒。
=====> Android藍牙Ble通訊Demo示例源碼–掃描,連接,發送和接收數據,分包解包
BLE單次寫的數據量大小是有限制的,通常是20位元組,可以嘗試通過requestMTU增大,但不保證能成功。分包寫是一種解決方案,需要定義分包協議,假設每個包大小20位元組,分兩種包,數據包和非數據包。對於數據包,頭兩個位元組表示包的序號,剩下的都填充數據。對於非數據包,主要是發送一些控制信息。
總體流程如下:
1、定義通訊協議,如下(這里只是個舉例,可以根據項目需求擴展)
2、封裝通用發送數據介面(拆包)
該介面根據會發送數據內容按最大位元組數拆分(一般20位元組)放入隊列,拆分完後,依次從隊列里取出發送
3、封裝通用接收數據介面(組包)
該介面根據從接收的數據按協議里的定義解析數據長度判讀是否完整包,不是的話把每條消息累加起來
4、解析完整的數據包,進行業務邏輯處理
5、協議還可以引入加密解密,需要注意的選演算法參數的時候,加密後的長度最好跟原數據長度一致,這樣不會影響拆包組包
一般都是Android版本適配以及不同ROM機型(小米/紅米、華為/榮耀等)(EMUI、MIUI、ColorOS等)的許可權問題
藍牙開發中有很多問題,要靜下心分析問題,肯定可以解決的,一起加油;
『貳』 混合APP低功耗藍牙項目解析數據可能用到的一些小方法---ble
可用於第三方藍牙設備交互,必須要支持藍牙 4.0。
iOS上:硬體至少是 iphone4s,系統至少是 iOS6。
android上:系統版本至少是 android4.3。
藍牙 4.0 以低功耗著稱,一般也叫 BLE(BluetoothLowEnergy)。目前應用比較多的案例:運動手壞、嵌入式設備、智能家居
在藍牙通訊中有兩個主要的部分,Central 和 Peripheral,有一點類似Client Server。Peripheral 作為周邊設備是伺服器。Central 作為中心設備是客戶端。所有可用的藍牙設備可以作為周邊(Peripheral)也可以作為中央(Central),但不可以同時既是周邊也是中央。
一般手機是客戶端, 設備(比如手環)是伺服器,因為是手機去連接手環這個伺服器。周邊(Peripheral)是生成或者保存了數據的設備,中央(Central)是使用這些數據的設備。你可以認為周邊是一個廣播數據的設備,他廣播到外部世界說他這兒有數據,並且也說明了能提供的服務。另一邊,中央開始掃描附近有沒有服務,如果中央發現了想要的服務,然後中央就會請求連接周邊,一旦連接建立成功,兩個設備之間就開始交換傳輸數據了。
除了中央和周邊,我們還要考慮他倆交換的數據結構。這些數據在服務中被結構化,每個服務由不同的特徵(Characteristics)組成,特徵是包含一個單一邏輯值的屬性類型。
上文中提到了特徵(Characteristics),這里簡單說明下什麼是特徵。
特徵是與外界交互的最小單位。藍牙4.0設備通過服務(Service)、特徵(Characteristics)和描述符(Descriptor)來形容自己,同一台設備可能包含一個或多個服務,每個服務下面又包含若干個特徵,每個特徵下面有包含若干個描述符(Descriptor)。比如某台藍牙4.0設備,用特徵A來描述設備信息、用特徵B和描述符b來收發數據等。而每個服務、特徵和描述符都是用 UUID 來區分和標識的。
source ==> 字元串
count ==> 切割的位數
轉換接收的ios數據
初始化藍牙4.0管理器 => initManager
搜索藍牙4.0設備,模塊內部會不斷的掃描更新附近的藍牙4.0設備信息 => scan
註: 參數(params):single 類型:布爾 true 為單例模式,false為非單例模式;默認為false; 描述:(可選項)則掃描附近的所有支持藍牙4.0的設備類型:parmas:布爾 true 為單例模式,false為非單例模式;默認為false; 非單例模式為僅在本頁面生效連接,單例模式為在連接成功後整個app全局生效
獲取當前掃描到的所有外圍設備信息 => getPeripheral
連接指定外圍設備。iOS端無超時判斷,android端默認有30秒超時判斷 => connect
根據指定的外圍設備 UUID 獲取該外圍設備的所有服務 => discoverService
根據指定的外圍設備 UUID 及其服務 UUID 獲取該外圍設備的所有特徵(Characteristic)=> discoverCharacteristics
根據指定的外圍設備 UUID 及其服務 UUID 和特徵 UUID 監聽數據回發 =>setNotify
根據指定的外圍設備 UUID 及其服務 UUID 和特徵 UUID 寫數據 => writeValueForCharacteristic
剩餘方法根據需求酌情使用
此次開發需求 傳遞位元組以及ASCII碼,apicloud中ble模塊僅僅滿足於傳遞位元組,並且初始低功耗藍牙僅僅滿足於傳遞20位元組以下數據,需設置MTU進行大數據傳輸,此次流控為藍牙的特徵FF03監聽來進行數據流控, 藍牙模塊使用百瑞互聯,如需定製開發模塊或SDK可聯系!
『叄』 Android BLE低功耗藍牙開發極簡系列(二)之讀寫操作
這是Ble極簡系列的第二篇文章,上一篇 Android BLE低功耗藍牙開發極簡系列(一)之掃描與連接 主要是掃描連接,這一篇主要是讀寫操作。
在連接成功後,可以通過Gatt進行discoverServices()。
在mGattCallback 回調添加Servicest的相關回調
當返回的status == BluetoothGatt.GATT_SUCCESS時,進行讀寫以及通知相關的操作, 調用writeDescriptor(),注意設置setValue為ENABLE_INDICATION_VALUE,否則可能後續讀取不到數據。
設置成功,會在onDescriptorWrite方法進行回調,注意UUID_SERVICE,UUID_NOTIFICATION特徵值UUID,可以詢問公司固件端的開發人員,和開發人員配合修改。
讀取數據在onCharacteristicChanged方法中,注意進制間的轉換。
一定要進行讀寫開關操作,注意descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE),否則可能讀取不到數據。
喜歡可以關注博主 BleDemo
『肆』 藍牙低功耗(BLE)概述
Android 4.3(API Level 18)開始引入Bluetooth Low Energy(BLE,低功耗藍牙)的核心功能並提供了相應的 API, 應用程序通過這些 API 掃描藍牙設備、查詢 services、讀寫設備的 characteristics(屬性特徵)等操作。
詳細介紹 GATT 之前,需要了解 GAP(Generic Access Profile) ,它在 用來控制設備連接和廣播 。 GAP 使你的設備被其他設備可見,並決定了你的設備是否可以或者怎樣與合同設備進行交互 。例如 Beacon 設備就只是向外廣播,不支持連接,小米手環就等設備就可以與中心設備連接。
GAP 給設備定義了若干角色,其中主要的兩個是: 外圍設備(Peripheral) 和 中心設備(Central) 。
在 GAP 中外圍設備通過兩種方式向外廣播數據: Advertising Data Payload(廣播數據) 和 Scan Response Data Payload(掃描回復) ,每種數據最長可以包含 31 byte。
這里 廣播數據是必需的 ,因為外設必需不停的向外廣播,讓中心設備知道它的存在。掃描回復是可選的,中心設備可以向外設請求掃描回復,這里包含一些設備額外的信息,例如設備的名字。
GAP 的廣播工作流程如下圖所示:
外圍設備會設定一個廣播間隔,每個廣播間隔中,它會重新發送自己的廣播數據,廣播時間越長,越省電,同時也不太容易掃描到。
大部分情況下, 外設通過廣播自己來讓中心設備發現自己,並建立 GATT 連接,從而進行更多的數據交換。
也有些情況是不需要連接的,只要外設廣播自己的數據即可。用這種方式主要目的是讓外圍設備,把自己的信息發送給多個中心設備。 因為基於 GATT 連接的方式的,只能是一個外設連接一個中心設備。 使用廣播這種方式最典型的應用就是蘋果的 iBeacon。廣播工作模式下的網路拓撲圖如下:
查看這篇博客
GATT 的全名是 Generic Attribute Profile,它定義兩個 BLE 設備通過叫做 Service 和 Characteristic 的東西進行通信。GATT 就是使用了 ATT(Attribute Protocol)協議,ATT 協議把 Service, Characteristic以及對應的數據保存在一個查找表中,次查找表使用 16 bit ID 作為每一項的索引。
一旦兩個設備建立起了連接,GATT 就開始起作用了,這也意味著,你必需完成前面的 GAP 協議。這里需要說明的是,GATT 連接,必需先經過 GAP 協議。實際上,我們在 Android 開發中,可以直接使用設備的 MAC 地址,發起連接,可以不經過掃描的步驟。這並不意味不需要經過 GAP,實際上在晶元級別已經給你做好了,藍牙晶元發起連接,總是先掃描設備,掃描到了才會發起連接。
GATT 連接需要特別注意的是: GATT 連接是獨占的。也就是一個 BLE 外設同時只能被一個中心設備連接 。一旦外設被連接,它就會馬上停止廣播,這樣它就對其他設備不可見了。當設備斷開,它又開始廣播。
中心設備和外設需要雙向通信的話,唯一的方式就是建立 GATT 連接。
下圖展示了 GTT 連接網路拓撲結構。這里很清楚的顯示, 一個外設只能連接一個中心設備,而一個中心設備可以連接多個外設。 Connected Topology一旦建立起了連接,通信就是雙向的了,對比前面的 GAP 廣播的網路拓撲, GAP 通信是單向的。如果你要讓兩個設備外設能通信,就只能通過中心設備中轉。
GATT 通信的雙方是 C/S 關系。 外設作為 GATT 服務端(Server),它維持了 ATT 的查找表以及 service 和 characteristic 的定義 。中心設備是 GATT 客戶端(Client),它向 Server 發起請求。需要注意的是,所有的通信事件,都是由客戶端(也叫主設備,Master)發起,並且接收服務端(也叫從設備,Slave)的響應。
一旦連接建立,外設將會給中心設備建議一個連接間隔(Connection Interval) ,這樣,中心設備就會在每個連接間隔嘗試去重新連接,檢查是否有新的數據。但是,這個連接間隔只是一個建議,你的中心設備可能並不會嚴格按照這個間隔來執行,例如你的中心設備正在忙於連接其他的外設,或者中心設備資源太忙。
下圖展示一個外設(GATT 服務端)和中心設備(GATT 客戶端)之間的數據交換流程,可以看到的是,每次都是主設備發起請求:
『伍』 Android ble (藍牙低功耗) 中的坑和技巧
new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString("00007777-0000-1000-8000-00805f9b34fb");
此時可以根據manfacturerData來匹配自己設定的外圍設備
在BluetoothGattCallback中的關於此問題有三步回調
1、 public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
2、 public void onServicesDiscovered(BluetoothGatt gatt, int status)
mBluetoothGatt.discoverServices()執行後得到的callback,如果狀態為GATT_SUCCESS,則可以獲取ble旁支發起廣播的service和descriptor,把廣播設為enable
3、 public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status)
只有這一步status == BluetoothGatt.GATT_SUCCESS,才可以真正的傳輸數據,如果在第一步或者第二步就開始傳輸數據,會在某些特定的case下導致未知的bug或者空指針錯誤
所以,在中心設備跟外圍開始連接後,你可以設定一個超時時間,在超時時間過後,依然沒能回調onDescriptorWrite並獲得BluetoothGatt.GATT_SUCCESS,則此次過程失敗,你可以根據實際情況進行重連或者提示錯誤
如果要傳輸大於20位元組的數據怎麼辦?
1、 系統mtu可以支持修改到512位元組,完成大數據量的傳輸。但是由於涉及到中心和旁支都需要修改,會造成很大的局限性和底層修改量,而且會觸發比如某些設備第一次修改不生效,另一個設備一次連接中只能修改一次等bug,非常不可取,十分不建議。
2、分包傳輸,自己設計協議分包傳輸是最可取的方案,需要注意的是在分包後,每一個包之間寫入數據需要設置間隔,比如100ms。
在做好5和6的基礎上,依然會在一些設備上出現,由於系統原因,ble剛開始的發送第一個數據出現丟包,請對此做出特殊處理。
『陸』 android 藍牙ble開發鎖屏狀態下不能掃描么
Android 從 4.3(API Level 18) 開始支持低功耗藍牙,但是只支持作為中心設備(Central)模式,這就意味著 Android 設備只能主動掃描和鏈接其他外圍設備(Peripheral)。從 Android 5.0(API Level 21) 開始兩種模式都支持。BLE 官方文檔在 這里。
在 BluetoothAdapter.startLeScan() 的時候,在 BluetoothAdapter.LeScanCallback.onLeScan() 中不能做太多事情,特別是周圍的BLE設備多的時候,非常容易導致出現如下錯誤:
E/GKI_LINUX(17741): ##### ERROR : GKI_exception: GKI_exception(): Task State Table
E/GKI_LINUX(17741): #####
E/GKI_LINUX(17741): ##### ERROR : GKI_exception: TASK ID [0] task name [BTU] state [1]
E/GKI_LINUX(17741): #####
E/GKI_LINUX(17741): ##### ERROR : GKI_exception: TASK ID [1] task name [BTIF] state [1]
E/GKI_LINUX(17741): #####
E/GKI_LINUX(17741): ##### ERROR : GKI_exception: TASK ID [2] task name [A2DP-MEDIA] state [1]
E/GKI_LINUX(17741): #####
E/GKI_LINUX(17741): ##### ERROR : GKI_exception: GKI_exception 65524 getbuf: out of buffers#####
E/GKI_LINUX(17741): ##### ERROR : GKI_exception:
E/GKI_LINUX(17741): **
開發建議:在 onLeScan() 回調中只做盡量少的工作,可以把掃描到的設備,扔到另外一個線程中去處理,讓 onLeScan() 盡快返回。
『柒』 Android藍牙開發(二)經典藍牙消息傳輸實現
上篇文章中,我們主要介紹了藍牙模塊,傳統/經典藍牙模塊BT和低功耗藍牙BLE及其相關的API,不熟悉的可以查看 Android藍牙開發(一)藍牙模塊及核心API 進行了解。
本篇主要記錄用到的經典藍牙開發流程及連接通訊。
藍牙連接前,給與相關系統許可權:
安卓6.0以上系統要動態請求及獲取開啟GPS內容:
藍牙核心對象獲取,若獲取對象為null則說明設備不支持藍牙:
判斷藍牙是否開啟,沒有則開啟:
藍牙掃描:
取消掃描:
藍牙監聽廣播,監聽藍牙開關,發現設備,掃描結束等狀態,定義狀態回調介面,進行對應操作,例如:監聽到藍牙開啟後,進行設備掃描;發現設備後進行連接等。
客戶端,與服務端建立長連接,進行通訊:
服務端監聽客戶端發起的連接,進行接收及通訊:
客戶端連接及服務端監聽基類,用於客戶端和服務端之前Socket消息通訊,進行消息或文件的發送、接收,進行通訊關閉操作等:
我這里只是簡單記錄了項目中用到的藍牙通訊,兩個設備之間不通過配對進行連接、通訊。
相關詳細內容及使用請查看Github項目: https://github.com/MickJson/BluetoothCS
藍牙配對操作及其它內容,可以詳細查看我下面的參考資料,寫的十分詳細,比如設備通過MAC地址,可以通過BluetoothAdapter獲取設備,再通過客戶端connect方法去進行連接等。
連接中遇到問題:read failed, socket might closed or timeout, read ret: -1。
通過改UUID,反射等方法都還是會出現錯誤。連接時,要確保服務端及客戶端都處於完全斷開狀態,否則連接就會出現以上問題,但偶爾還是會有問題,期待有什麼好的方法可留言告訴我。
參考資料:
Android-經典藍牙(BT)-建立長連接傳輸短消息和文件
Android藍牙開發—經典藍牙詳細開發流程
歡迎點贊/評論,你們的贊同和鼓勵是我寫作的最大動力!
『捌』 Android 藍牙開發(三)-藍牙的詳細介紹
前面的兩篇文章,主要是在 Android 官網關於藍牙介紹的基礎上加上自己的理解完成的。主要針對的是 Android 開發中的一些 API 的使用。
第一篇文章 Android 藍牙開發(一) 主要是介紹了普通的藍牙在 Android 開發中的運用。
第二篇文章 Android 藍牙開發(二) 主要是介紹了低功耗藍牙的開發。
這篇文章主要介紹的是藍牙的歷史和一些關於藍牙的通用知識,還有廣播包的知識。要想徹底了解藍牙開發,這些基礎的知識也是需要的,就像網路協議一樣,這些都是基礎的內容。我們的 API 的調用都是以這個為基礎的,了解這些,開發過程中遇到問題,才可以知道什麼怎麼一回事。
下篇文章主要講的就是實際開發中的一些坑。
藍牙其實就是一種近距離無線通信技術。
從下到上分別為:控制器(Controller)-->主機(host)-->應用(Application)
詳細介紹各個層的含義:
BLE 應用可以分為兩大類:基於非連接的和基於連接的
意思就是外設和周邊設備不發生連接,主要靠掃描到的廣播來獲取信息。發送廣播的一方叫做 broadcaster 監聽廣播的一方叫做 oberver 在 GAP 層有對應的角色定義。
網路拓撲圖:
這種方式就是廣播設備不斷的向外發送廣播(含有特定的信息),然後觀察者接受到廣播按照兩者之間約定好的協議進行解析拿到有用的信息。例如:iBeacon,通過這種設備我們可以實現室內定位。
其實這些設備的角色可以即使廣播者又是觀察者。接收到廣播後作出了處理,然後又發送廣播。這樣就形成了雙向的網路,類似於網際網路,這就是藍牙 Mesh 組網。
廣播數據包格式:
每個廣播數據包由 31 byte 組成。分為有效數據和無效數據兩部分。
例子:
這里是掃描的數據包(轉換成了 16 進制,兩個代表一個位元組),第一個位元組是 02 表示後面的兩個位元組是數據部分,然後第二個位元組是 01 表示了數據的類型。後面一個位元組就是真正的數據了。這個廣播數據單元就分析完了。下面就是另一個數據單元了。依次類推,關於數據類型的解釋,官網有。
這是數據類型對應的含義表。
網路拓撲圖:
一個中心設備可連接多個外設,但是一個外設只能連接一個中心(外設連接成功後就會停止對外廣播,別人就發現不了它了)。其中一個中心設備的連接外設的數量也是有限的。
鏈接: https://mp.weixin.qq.com/s?__biz=MzU5NzA2NjQzMg==&mid=2247484141&idx=1&sn=&scene=21#wechat_redirect
『玖』 Android 藍牙開發(一)
普通藍牙設備官方文檔
Android 平台包含藍牙網路堆棧支持 ,憑藉此支持,設備能以無線方式與其他藍牙設備交換數據。應用框架提供了通過 Android Bluetooth API 訪問藍牙功能的途徑。使用 Bluetooth API Android 應用可以執行下面的操作:
傳統藍牙適用於電池使用強度較大的操作,例如 Android 設備之間的流傳輸和通信等。針對具有低功耗要求的藍牙設備,Android 4.3(API 18)中引入了面向低功耗藍牙的 API 支持。
使用 Android Bluetooth API 來完成使用藍牙進行通信的四項主要任務: 設置藍牙 、 查找局部區域內的配對設備或可用設備 、 連接設備 ,以及在 設備之間傳輸數據 。
關於藍牙的 API 在 android.bluetooth 包中,下面介紹一下和藍牙相關的主要類:
在 BluetoothProfile IPC 客戶端連接到服務(即,運行特定配置文件的內部服務)或斷開服務連接時向其發送通知的介面。
使用藍牙必須聲明許可權 BLUETOOTH 才可以執行藍牙通信。
1、獲取藍牙適配器
例如:我們可以查詢所有已配對的設備,然後使用 ArrayAdapter 向用戶顯示每台設備的名稱:
要發起連接僅需要知道目標藍牙設備的 Mac 地址就可以了。
注意 執行 discovery 對於藍牙適配器來說是一個非常繁重的過程,並且會消耗大量資源。在找到要連接的設備後, 要確保使用 cancelDiscovery() 來停止發現,然後嘗試連接 。如果您已經和某台設備進行連接,那麼這個時候執行發現操作會大幅度的減少此連接可用的帶寬!因此不應該在處於連接狀態的時候執行發現操作!
例如:
在連接之前如果兩個設備沒有配對,則系統會自動發出配對請求。
伺服器套接字接受連接的基本過程
放在子線程中去執行。
例子:
客戶端連接的基本過程
調用 connect() 的時候要確保客戶端沒有執行發現操作。如果執行了會大幅度降低連接的速度,增加失敗的可能。
例子
在連接之前調用 cancleDiscovery() 在進行連接之前應該始終調用這個方法,而且調用的時候無需檢測是否正在掃描。
過程:
從 Android 3.0 開始, Bluetooth API 便支持使用藍牙配置文件。藍牙配置文件是適用於設備間藍牙通信的無線介面規范。
1、藍牙配置文件就是設備間通信(藍牙設備)的一種規范
免提配置文件便是一個示例,對於連接到無線耳機的手機,兩台設備都必須支持免提配置文件。我們也可以通過實現介面 BluetoothProfile 來寫入自己的類來支持特定的藍牙配置文件。Android API 提供了以下的幾種藍牙配置文件的實現:
2、使用配置文件的基本步驟
創建 HDP 應用:
關於普通藍牙設備和普通藍牙設備之間的連接通信
關於藍牙設備和藍牙儀器(藍牙耳機、電子秤等等類似產品)
這種之間的通信是通過配置文件代理來實現的。
都有一個對應的配置文件代理類。具體的操作是通過這個對象來完成。
參考: https://mp.weixin.qq.com/s?__biz=MzU5NzA2NjQzMg==&mid=2247484128&idx=1&sn=&scene=21#wechat_redirect
『拾』 Android 低功耗藍牙(Ble) 開發總結
Android 從 4.3(API Level 18) 開始支持低功耗藍牙,但是只支持作為中心設備(Central)模式,這就意味著 Android 設備只能主動掃描和鏈接其他外圍設備(Peripheral)。從 Android 5.0(API Level 21) 開始兩種模式都支持。
低功耗藍牙開發算是較偏技術,實際開發中坑是比較多的,網上有很多文章介紹使用和經驗總結,但是有些問題答案不好找,甚至有些誤導人,比如 :獲取已經連接的藍牙,有的是通過反射,一大堆判斷,然而並不是對所有手機有用,關於Ble傳輸速率問題的解決,都是默認Android每次只能發送20個位元組,然而也並不是,,,下面進入正文。
這里用的是 Android5.0 新增的掃描API,
這里說一下,如果做藍牙設備管理頁面,可能區分是否是已連接的設備,網上又通過反射或其他挺麻煩的操作,也不見得獲取到,官方Api 就有提供
與外圍設備交互經常每次發的數據大於 mtu的,需要做分包處理,接收數據也要判斷數據的完整性最後才返回原數據做處理,所以一般交互最少包含包長度,和包校驗碼和原數據。當然也可以加包頭,指令還有其他完整性校驗。下面分享幾個公用方法:
我自己封裝的一個BleUtil ,因為涉及跟公司業務關聯性太強(主要是傳輸包的協議不同)就先不開源出來了,如果這邊文章對大家有幫助反饋不錯,我會考慮上傳個demo到github供大家使用,
在這先給大家推薦一個不錯 Demo ,裡面除了沒有分包,協議,和傳輸速率。基本的功能都有,而且調試數據到列印到界面上了。最主要是它可以用兩個個手機一個當中心設備一個當外圍設備調試。
首先傳輸速率優化有兩個方向,1 外圍設備傳輸到Android 。2 Android傳輸到外圍設備。
我在開發中首先先使用上面那位仁兄的demo調試,兩個Android 設備調試不延時,上一個成功馬上下一個,最多一秒發11個20位元組的包。
後來和我們的藍牙設備調試時發現發送特別快,但是數據不完整,他藍牙模塊接收成功了,但是透傳數據到晶元處理時發現不完整,我們的硬體小夥伴說因為 波特率 限制(差不多每10位元組透傳要耗時1ms)和藍牙模塊的buff (列印時是最多100byte,100列印的)限制,就算藍牙模塊每包都告訴你接收成功,也是沒透傳完就又接收了。後來通過調試每次發20K數據,最後是 Android 發是 20位元組/130ms 穩定。給Android 發是 20位元組/ 8ms 。 (天殺的20位元組,網上都是說20位元組最多了)
後來看了國外一家物聯網公司總結的 Ble 吞吐量的文章(上面有連接),知道Android 每個延時是可以連續接收6個包的。就改為 120位元組/ 16ms (為啥是16ms,不是每次間隔要6個包嗎,怎麼像間隔兩次,這時因為波特率影響,多了5個包100位元組,差不多 我們的單片機透傳到藍牙模塊要多耗時不到10ms )
而Android 發數據可以申請 我們設備的mtu 來得到最多每次能發多少位元組。延時還是130ms,即:241位元組/ 130ms 提高12倍,這個速度還可以。
根據藍牙BLE協議, 物理層physical layer的傳輸速率是1Mbps,相當於每秒125K位元組。事實上,其只是基準傳輸速率,協議規定BLE不能連續不斷地傳輸數據包,否則就不能稱為低功耗藍牙了。連續傳輸自然會帶來高功耗。所以,藍牙的最高傳輸速率並不由物理層的工作頻率決定的。
在實際的操作過程中,如果主機連線不斷地發送數據包,要麼丟包嚴重要麼連接出現異常而斷開。
在BLE裡面,傳輸速度受其連接參數所影響。連接參數定義如下:
1)連接間隔。藍牙基帶是跳頻工作的,主機和從機會商定多長時間進行跳頻連接,連接上才能進行數據傳輸。這個連接和廣播狀態和連接狀態的連接不是一樣的意思。主機在從機廣播時進行連接是應用層的主動軟體行為。而跳頻過程中的連接是藍牙基帶協議的規定,完全由硬體控制,對應用層透明。明顯,如果這個連接間隔時間越短,那麼傳輸的速度就增大。連接上傳完數據後,藍牙基帶即進入休眠狀態,保證低功耗。其是1.25毫秒一個單位。
2)連接延遲。其是為了低功耗考慮,允許從機在跳頻過程中不理會主機的跳頻指令,繼續睡眠一段時間。而主機不能因為從機睡眠而認為其斷開連接了。其是1.25毫秒一個單位。明顯,這個數值越小,傳輸速度也高。
藍牙BLE協議規定連接參數最小是5,即7.25毫秒;而Android手機規定連接參數最小是8,即10毫秒。iOS規定是16,即20毫秒。
連接參數完全由主機決定,但從機可以發出更新參數申請,主機可以接受也可以拒絕。android手機一部接受,而ios比較嚴格,拒絕的概率比較高。
參考:
在iOS和Android上最大化BLE吞吐量
最大化BLE吞吐量第2部分:使用更大的ATT MTU