Android 上的藍牙實踐
這是我在 Droidcon Beijing 2016 和 GDG Devfest 2016 上做的分享,以下是正文:
Slide 01 我今天分享的主題是 Android 上低功耗藍牙的實踐。這個主題比較小眾。我在過去的一年多的時間里,主要是在做低功耗藍牙相關的開發。接觸過程中發現,BLE 的開發和通常的 Android APP 的開發有點不一樣,這里需要訪問硬件資源,而且涉及到一些協議相關的內容,而且這方面的資料也比較少。今天我從 Android 開發者的角度,來分享一下低功耗藍牙開發實踐。
Slide 02 今天分享的內容,主要包含如下幾個部分:首先對藍牙和低功耗藍牙做一個簡單的介紹;然后介紹 Android 上對低功耗藍牙的支持;再介紹一下在 Android 平臺上可以開發哪些低功耗藍牙應用;然后是,開發過程中,可以幫助我們調試的工具;最后,總結一下所謂的 “最佳實踐”,低功耗藍牙開發的一些小經驗。
Slide 03 在介紹低功耗藍牙之前,不得不說一下它的超集—藍牙。藍牙普及率相當的高,相信每個人都知道它,標識是這樣的(圖片)。簡單來說,藍牙其實就是一個近距離無線通信技術,最早是由愛立信研發出來。藍牙 Bluetooth 這個名字看起來是一個合成詞,藍色的牙齒,實際上不是,這個詞是一個丹麥的國王的綽號,當時研發它的工程師正在看一個關于這個國王的書,就起了這個名字,從此這個國王圖片,就帶上了藍牙耳機。
說到藍牙,就不得不說藍牙技術聯盟(Bluetooth SIG),它負責藍牙規范制定和推廣的國際組織。做藍牙相關產品的,少不了和它打交道。藍牙技術聯盟同時也擁有藍牙商標,如果要使用,需要通過他們的授權。
我們回到藍牙技術本身。藍牙它有哪些特點呢?首先,近距離通信,典型距離是 10 米以內,傳輸速度最高可達 24 Mbps,支持多連接,安全性高,非常適合用智能設備上。
簡單介紹一下藍牙的版本演進。99 年藍牙 1.0 發布,后來發布的藍牙 2.1 使用最廣的,現在絕大部分藍牙產品都是這個版本,也是我們所謂的經典藍牙。藍牙 3.0,也就是所謂的高速藍牙,最高傳輸速度可達 24Mbps。藍牙 4.0/4.1 在這個版本中引入了低功耗藍牙。藍牙 5.0 很快也要發布了,主要是針對物聯網方向的改進。
Slide 04 下面介紹一下低功耗藍牙,它的全稱是 Bluetooth Low Energy,簡稱為 BLE。從名字可以看出,它的最大特點就是低功耗,一些 BLE 設備可以用一個紐扣電池使用一兩年。還有一些其他的有點,例如成本低呀,連接速度快呀,安全性高呀。另外,低功耗不是沒有缺點的,低功耗意味著低傳輸速率,它被設計就是用來傳輸少量數據的。總體來說,低功耗藍牙非常適合用在可穿戴設備或者物聯網上。
Slide 05 下面我們看一下 BLE 的協議棧,作為 Android 開發者,我們不必理解 BLE 的協議棧每個細節,這里大概介紹一下協議架構。我們都知道,協議一般都是分層設計的。BLE 協議棧也不例外。我們來看一下這個圖。整個協議棧大致分為三部分,從下到上分別為,控制器(Controller)→主機(Host)→應用(Applications)。
控制器:它是協議棧的底層的實現,直接與硬件相關,一般直接集成在 SoC 中,由芯片廠商實現,包括物理層和鏈路層。 主機:這是協議棧的上層實現,是硬件的抽象,與具體的硬件和廠家無關。 應用層:就是使用 Host 層提供的 API,開發的應用。
協議棧里面的模塊比較多,我們就簡單介紹幾個和我們開發相關的幾塊簡單介紹一下。
Slide 06 首先是物理層。藍牙是工作在 2.4GHz 附近,這是工業、科學、醫療 ISM 頻段。可以看到它和 WiFi 工作在同一個頻段。藍牙把頻段切分為 40 個通道,3 個廣播通道,37 個數據通道,按照一定規律跳頻通信(高斯頻移鍵控 GFSK)。
在 Host 層和 Controller 之間有一個接口層,簡稱為 HCI。主機和控制器之間就是通過 HCI 命令和事件交互的。HCI 這一層是協議棧中是可選的,例如在一些簡單小型的設備上可能就沒有,但是所有的 Android 設備上肯定是有。這是藍牙上層應用和芯片的交互的必經之路。后面我們會講到,這一層的 log,能夠很好的幫助我們分析和調試問題。
Slide 07 在 Host 部分,協議結構要復雜一些,有邏輯鏈路控制和適配層,安全管理模塊等等。我們重點來看屬性協議,簡稱為 ATT,它是 BLE 通信的基礎。ATT 把數據封裝,向外暴露為“屬性”,提供“屬性”的為服務端,獲取“屬性”的為客戶端。ATT 是專門為低功耗藍牙設計的,結構非常簡單,數據長度很短。
Slide 08 接下來我們看一下 GATT,全稱叫做通用屬性配置文件,它是建立在前面說的 ATT 的基礎上,對 ATT 進行進一步的邏輯封裝,定義數據的交互方式和含義。這是我們做 BLE 開發的時候直接接觸的概念。GATT 按照層級定義了三個概念:服務(Service)、特征(Characteristic)和描述(Descriptor)。他們的包含關系如右邊這個圖所表示的:一個 Service 包含若干個 Characteristic,一個 Characteristic 可以包含若干 Descriptor。而 Characteristic 定義了數值和操作。Characteristic 的操作這幾種權限:讀、寫、通知等權限。我們說的 BLE 通信,其實就是對 Characteristic 的讀寫或者訂閱通知。還有最外面一層,Profile配置文件,把若干個相關的 Service 組合在一起,就成為了一個 Profile,Profile 就是定義了一個實際的應用場景。
Slide 09 這里還要多說一點,Service、Characteristic 還有 Descriptor 都是使用 UUID 唯一標示的。具體的表現形式,我們在后面會講到。我們先來說說 UUID 是什么? UUID 是全局唯一標識,它是 128bit 的值,為了便于識別和閱讀,一般標示程如下的形式,8-4-4-12 的16進制標示。
關于 UUID 有一些規范,為了避免沖突,一般都不會自己手動去定義。例如 Android 中提供了 UUID.randomUUID() 來生成一個隨機的 UUID。我們也看到,UUID 有點太長了,在低功耗藍牙中這種數據長度非常受限的情況下,使用起來肯定不方便,所以藍牙又使用了所謂的 16 bit 或者 32 bit 的 UUID。其實本質上并沒有什么 16bit 或者 32 bit UUID,藍牙 SIG 定義了一個基礎的UUID(Bluetooth Base UUID),形式如下。除了 XXXX 那幾位意外,其他都是固定,所以說,其實 16 bit UUID 是對應了一個 128 bit 的 UUID。這樣一來,UUID 就大幅減少了,例如 16 bit uuid 只有有限的 65536 個,所以 16 bit UUID 并不能隨便使用。SIG 已經預先定義了一些 UUID,如果你想添加一些自己的 16 bit 的 UUID,可以花錢買。
Slide 10 再往上,是通用訪問控制配置文件,也就是 GAP,由名字可以看出,它定義了 BLE 整個通信過程中的流程,例如廣播、掃描、連接等流程。還定義了參與通信的設備角色,以及他們各自的職能,例如廣播數據的 Broadcaster,接收廣播的 Observer,還有被連接的“外設” Peripheral 和發起連接的“中心設備” Central。可以看到,參與交互的設備角色都不是對等。詳細的交互流程,我們放到后面講。
最后,就是應用層,就是使用 Host 提供的 API 開發的低功耗藍牙應用。 到這里,我們就把 BLE 的協議棧過了一下,為我們開發 BLE 有了一些理論基礎。
Slide 11 接下來,我們來看一下 Android 平臺上對低功耗藍牙的支持。
Slide 12 從 Android 4.3 Jelly Bean,也就是 API 18 才開始支持低功耗藍牙。這時支持 BLE 的 Central 模式,也就是我們在上面 GAP 中說的,Android 設備只能作為中心設備去連接其他設備。從 Android 5.0 開始才支持外設模式。
Android SDK 中 BLE 相關的 API 都在 android.bluetooth.* 下面,同時在 Android 5.0 也引入了一些也需要用到 android.bluetooth.le* 下面的 API。
例如,在前面介紹的 GATT 定義的一些概念,都有對應的類,例如 BluetoothGatt/BluetoothGattService/BluetoothGattCharacteristic 等。有了前面的介紹,我們就能很容易的理解這些類的作用。
另外,要在 APP 中使用藍牙功能,需要在 Manifest 中申請藍牙相關的權限。在 Android 6.0 及以上平臺中,還需要申請定位權限。為什么會這樣?因為 BLE 確實有定位的能力,我們后面會講到。
Slide 13 下面我們來看一下,Android 上藍牙實現的架構。我們來看右邊這個圖,這是 Android 上一個非常經典的層級結構。最下面硬件部分,可以使用各廠家的具體實現,通過硬件抽象層(HAL)接口統一連接到 Android AOSP 中,通過 JNI 提供 Java 訪問接口。藍牙服務運行在 com.android.bluetooth 進程中,最后通過 Binder 機制向客戶端,也就是 APP 提供相關的 API。
關于藍牙協議棧,這里多說一點。Android 4.2 以前用的是老牌協議棧實現 BlueZ,4.2 開始換成了由 Google 和 Broadcom(博通)聯合開發的 BlueDroid,專門在 Android 平臺使用。BlueDroid 作為全新的實現,功能不是完善,我們可以看到在 4.3 以后才支持 BLE,在 5.0 以后才支持外設模式,到目前為止,功能其實還是不是很完善。也有一些 Bug。
Slide 14 這里介紹一下 Android 中 BLE 操作的過程,APP 發起一個 BLE 操作,然后理解返回,操作結果通過回調上報。操作被封裝為一個消息,然后放到協議棧的消息隊列中,有一個獨立的線程獲取消息進行處理,這里非常類似于我們熟知的 Looper 和 Handler 機制。
因為是使用消息機制,回調的時候必須知道通知哪個客戶端?客戶端發起請求之前,首先要向協議棧注冊客戶端,注冊成功以后,返回一個 clientIf,這是一個整型,是客戶端在協議棧的一個句柄,客戶端的后續操作,都只需要帶上這個 clientIf 句柄即可。
在操作完成的時候,一般都有一個顯式的停止操作,用來釋放前面的申請的 clientIf 和資源。如果不能正確的釋放,不僅會造成內存泄漏,而且可能會導致后續所有的 BLE 操作都是不能做了。因為這個 clientIf 是有限,在現在藍牙協議棧中只有 32 個,而且是Android 上所有 APP 共用的。當這些資源用完以后,只有通過殺掉對應的 APP 或者重啟藍牙才能恢復。
Slide 15 Android 上 BLE 的實現我們就講到這里,接下來介紹一下 Android 上能夠使用 BLE 做一些哪些事情,開發一些什么應用?
Slide 16 BLE 應用可以分為兩大類:基于非連接的和連接的。
基于非連接的,這種應用就是依賴 BLE 的廣播,也叫作 Beacon。這里有兩個角色,發送廣播的一方叫做 Broadcaster,監聽廣播的一方叫 Observer。
基于連接的,就是通過建立 GATT 連接,收發數據。這里也有兩個角色,發起連接的一方,叫做中心設備—Central,被連接的設備,叫做外設—Peripheral。
Slide 17 我們先來看非連接的,也就是基于廣播 Beacon 的應用。它的網絡拓撲結構如下。我們知道廣播是單向的,Broadcaster 向外廣播,監聽者接收附近的廣播,整體來說形成一個單向的星型。網絡中可以有多個外設,也可以有多個監聽者(動畫)。
完全基于廣播的應用,有大名鼎鼎的 iBeacon,這是蘋果公司定義的基于 BLE 廣播實現的功能,可以實現廣告推送和室內定位。這也說明了,APP 使用 BLE,需要定位權限。還有前段時間比較火的,手機 QQ 可以“尋找丟失兒童”的項目,其實也是這個原理,在兒童用品中植入可以發送特定廣播的設備,手機掃描到了,根據手機的地理位置,就能大致確定范圍。
還有些設備,可以同時實現兩個角色,既能發送廣播,也可以接收廣播。一個設備接收到廣播,可以通過處理,然后再轉發出去,這樣就可以形成一個雙向的網格,這就是藍牙的 Mesh。這樣的網絡可以不受藍牙傳輸距離限制了,只要在空間中布置足夠密集的節點,就能把信息從網絡一點,傳遞到任何一點。這個可以應用在物聯網和智能家居系統中。
前面在介紹協議棧物理層的時候,我們知道廣播只在37、38、39這三個廣播頻道進行廣播,監聽者也在這三個頻道進行監聽。我們前面介紹了,藍牙通信是跳頻的,只有雙方設備在某個時刻跳到同一個頻到上,才能收到廣播,這種傳播數據效率比較低,數據量也有限,不適合大規模的數據傳輸。
Slide 18 接下來我們介紹一下廣播的數據,也就是廣播包。我們所說的廣播數據其實包含兩部分:Advertising Data(廣播數據) 和 Scan Response Data(掃描響應數據)。通常情況下,廣播的一方,按照一定的間隔,往空中廣播 Advertising Data,當某個監聽設備監聽到這個廣播數據時候,會通過發送 Scan Response Request,請求廣播方發送掃描響應數據數據。這兩部分數據的長度都是固定的 31 字節。在 Android 中,系統會把這兩個數據拼接在一起,返回一個 62 字節的數組。
廣播數據包的結構如這個圖所示(動畫)。廣播包中是包含一個一個的小 AD structure,每個 AD structure 是一個完整的數據,它的結構是:第一個字節表示長度 n,后面緊接 n 個字節的數據。數據部分第一個字節表示數據類型,也就是后面的數據含義,后面 n - 1 個字節表示真實數據。例如 0x08 是設備的名字,后面的數據就是設備名字的 UTF-8 編碼。
這些廣播數據可以自己手動去解析,在 Android 5.0 也提供 ScanRecord 幫你解析,直接可以通過這個類獲得有意義的數據。
廣播中可以有哪些數據類型呢?設備連接屬性,標識設備支持的 BLE 模式,這個是必須的。設備名字,設備包含的關鍵 GATT service,或者 Service data,廠商自定義數據等等。
這里我們也可以看到,廣播數據只有最多62字節,所以廣播數據空間每個直接都非常珍貴。一般都把哪些數據放到廣播中呢?原則上是廣播中要放一些能夠表達設備身份的數據,還有一些需要暴露的必要數據。因為空間的限制,所以基于廣播做不了太復雜的應用,到了 Bluetooth 5.0,據說要大幅擴展廣播數據的容量,擴展到 512 字節,這時想象空間就比較大了。
另外,再順帶提一下,無線通信中基本都有信號強度的概念 — 也就是 RSSI,RSSI 單位是 dB,通過 RSSI 能夠大致推測出距離的遠近。但是這個在 Android 設備上非常不靠譜,RSSI 的值波動很大,跟環境和手機的角度關系很大。
Slide 19 我們來直觀看一下掃描到的結果是什么樣。例如我們使用一個 APP 掃描,掃到一個設備,這些內容都是從廣播數據中解析出來的,例如設備名字,設備類型,GATT 服務數據,產商自定義數據等。原始數據是這樣的(動畫),這里是一個 62 字節的16進制標示,下面這個表格中,每一行就是一個 AD Structure。
Slide 20 我們來看一下 Android 作為接收者怎么接收廣播數據,掃描設備。代碼其實很簡單,首先創建一個 LeScanCallback,用來接收收到廣播以后,回調上報數據。然后會用 BluetoothAdapter 的 startLeScan 來開始掃描,需要停止掃描的時候,使用 stopLeScan 來停止。
我么來詳細看一下這個回調函數,onLeScan,有 BluetoothDevice 這個參數,代表掃描到的設備,關鍵是設備的的 MAC 地址信息。然后就是 RSSI,表示掃描到的設備的信號強度,接下來 scanRecord 就是我們前面介紹的廣播數據,這個數據的長度是62字節。值得提的一點是,BLE 所有回調函數都不是在主線程中的。
這里有幾點需要注意,這里在不需要掃描以后,一定要 stopLeScan,而且 start 和 stop 中傳入的 LeScanCallback 一定要是同一個,因為 LeScanCallback 就是我們客戶端的標識。否者就會出現我們前面說的 clientIf 不釋放的問題。在 Android 開發中,我們經常會使用匿名內部類來做參數,在這里就千萬不要這么做。
在 Android 5.0 中,提供了全新的掃描 API — BluetoothLeScanner,它提供了對掃描更加精細的控制。
除了這種方法,還可以使用經典藍牙掃描的方式,BluetoothAdapter 的 startDiscovery(),然后通過 BroadcastReceiver 來接收收到的廣播。如果只是做 BLE 的開發,不建議使用這個方法,這是一個非常重的操作,靈活性非常差。
Slide 21 接下來我們來看一下掃描的工作流程。首先 APP 發起掃描請求,通過藍牙的 Service 發送請求給藍牙芯片。藍牙芯片開始掃描,掃描到了設備,就通過回調上報。我們知道,掃描真正執行實在 BT 芯片中,只要 APP 發送了請求下去以后,Android 系統就可以休眠了,也就是我們常說的 AP (Application Processor),等掃描到了設備以后,底層 BP (Baseband Processor)就會喚醒上層 AP,執行回調通知到 APP,(動畫)就像我們圖中紅色框標出的這樣。這里有一個問題,隨著我們周圍的 BLE 設備逐漸增多,頻繁掃描到設備,系統就會被頻繁的喚醒,甚至睡眠不下去,從而導致耗電嚴重。
為了避免這種問題,耗電的問題。我們需要盡可能少的使用掃描。即使需要掃描,我們也希望盡可能少的上報掃描到的設備。這里就可以使用 Android 5.0 上提供的新接口,設置 ScanFilter,通過一定的規則過濾,只有掃描到了符合我們的規則的設備才上報,或者通過設置延遲上報,從而減少喚醒系統的次數。
這里總結一下掃描中一些建議。1、首先,盡可能使用新的 API,功能更強大;2、盡可能少地掃描,因為畢竟掃描是一個比較重的操作,耗電,也會減慢 BLE 連接速度;3、掃描的時候,盡量設置 ScanFilter,只掃描那些你感興趣的設備,而不是全盤掃描;4、正確使用 API,特別是合理停止掃描,防止資源泄漏。
Slide 22 下面我們來看一下 Android 作為 Broadcaster 的應用。從 Android 5.0 開始,Android 設備就可以像外設一樣發送 BLE 廣播了。這時 Android 設備之間就可以通過 BLE 來交互數據,或者發現對方設備了,例如類似 NFC 一樣交換簡單信息的應用,想象空間還是很大的。
Android 中實現的代碼如下,通過前面的介紹,我們知道廣播有兩種包:Advertising Data 和 Scan Response Data,我們這里設置好這兩種包,然后通過 BluetoothLeAdvertier 的 startAdvertising 就可以了。這里需要注意的點和前面一樣,Start 了,需要注意 Stop。
Slide 23 非連接的應用我們就講到這里,接下來我們將基于連接的 BLE 應用。它的網絡拓撲如圖所示。我們看到,參與通信的有兩個角色:中心設備(Central)和外設(Peripheral)。一個中心設備可以連接多個外設,一個外設只能被一個中心設備連接。中心設備和外設之間的通信是雙向的。可以看到這是一個典型的星型結構。其實一個中心設備能夠同時連接的設備數量也是有限,一般最多連接 7 個外設。
Slide 24 BLE 連接的建立是通過 GAP 來協商和創建連接。Central 設備發起連接,外設接收連接請求,并協商連接參數。
前面我們介紹了 GATT,GATT 核心內容就是 Service、Characteristic 以及 Descriptor。每個 BLE 外設,根據自己的功能,向外暴露 Service 等。其實最重要的獲取 Service 中的 Characteristic,Characteristic 可以被讀、寫、還有變化的時候有通知,這樣就實現了雙向的通信。
Slide 25 我們通過一個例子來簡單看一下 GATT 的結構。在右邊這個圖中,我們連接了一個小米手環2,這里個列表中每一行就是一個 Service,例如 Generic Access、Device Information 等,還有沒有名字的,直接顯示了一串 UUID。這是怎么回事呢?前面我們介紹了,藍牙聯盟已經預先定義了一些 Service,都是一些 16bit UUID 的。這些Service有標準的含義和用途。例如 Generic Access 這個 service 就描述了設備連接相關的屬性。還有 Immediate Alert 服務,標識設備支持標準的即時提醒功能,例如小米手環作為提醒通知設備,Hear Rate 表示心率服務。而直接顯示 UUID 的標示廠商自定義的,有 128 bit 的長的,也有 16 bit 短的,短的標示購買的,可以看到廠商購買了 FEE0 這個。自定義 Service 具體怎么操作,里面屬性的含義只有廠商自己知道。
這里也展開了兩個 Service,里面列出來的是 Characteristic,有些還有 Descriptor。后面標簽標示這個特征有哪些權限,例如 W 標示可寫。Character 的 UUID 也是類似,有官方定義的我們直接指導怎么讀寫,例如我們往 Alert Level 里面寫入 1,手環就應該能夠發出提醒。直接讀取 Hear Rate 就能獲得到心率。另外也有廠商自定義的,里面數據的內容,就只有廠商自己知道了。
官方定義了哪些 Service 和 Characteristic,都在藍牙的官網上有定義,可以通過 KeyNote 中的連接去查看。
Slide 26 這是在 Android 中使用 GATT 連接的具體寫法。可以看到,Android SDK 相關的類都和 GATT 里面概念一一對應。前面我們也說了,Android 上 BLE 的操作都是異步的,這里也要創建一個 BluetoothGattCallback 用來出來回調,這個類非常重要,所有的 GATT 操作的回調都在這里。
通過 BluetoothDevice 的 connectGatt() 方法得到 BluetoothGatt,表示一個連接,用完以后,記得 close() 來釋放資源。
Slide 27 我們接下來看一下 Android 中 GATT 操作的流程。右邊這個圖,APP 是我們的應用,右邊藍牙服務端,從左向右箭頭是 APP 發起的請求,從右向左的箭頭是回調。我們看到所有的操作都是異步的完成的。連接過程是,首先使用 gattConnect 發起連接,收到 onConnectionStateChange() 通知連接是否成功,若成功,則進行下一步的 discoverService(),這一步就是發現設備所有的 GATT Service,若發現成功,通過 onServiceDiscovered() 回調,這時才算真正的連接成功。然后可以通過 BluetoothGatt 的 getService() 來獲得BluetoothGattService,進而獲得BluetoothGattCharacteristic 等,然后對 Characteristic 進行讀寫。
圖中這是理想狀況。有可能是這樣(動畫),你在嘗試建立一個 GATT 連接,而沒有回調返回的時候,同時再發起一個 GATT 連接,這個時候有很大概率連接會失敗。所以最好不要同時發起多個連接請求。
另外,在一個 GATT 連接中,你對 Characteristic 發起讀寫操作的時候,如果上一個請求沒有返回之前,不能發起另外一個操作(動畫),否者后一個就會失敗。所以對于一個連接,請求必須順序執行,一個請求完成以后,才能進行下一個請求。
我們預期 request 和 response 是成對出現的,但是現實是,有時候會出現發送一個 request,而沒有回調的情況。前面我們說了,在前一個回調之前,不能發起新的 request,這樣我們是不是就傻等在這里了呢?為了解決這些問題,下面推薦一個解決方案。
Slide 28 為了實現只有一個連接請求的需求,我們可以創建連接管理類,在這個類中每次只有一個正在連接的設備,因為連接需要經過多次交互,可以使用狀態機是最合適的解決方案。根據回調出發狀態轉移,同時也設置一個在某個狀態停留的時間有個閾值,超過這個時間,即使沒有回調也會發生狀態轉移。把所有的連接請求放到一個隊列中,等前面的連接成功或者失敗以后,才進行下一個連接請求。
接下來,對于已經建立的 GATT 連接,所有的操作都是異步的,而且需要順序執行。為了保證這樣的邏輯,寫起非常麻煩,想象一下你需要連續讀寫多個 Characteristic 的場景。解決方法是封裝異步調用成為同步調用,具體的實現原理是使用 wait/notify 來實現即可。寫起來就非常方便,而且不容易出現狀態錯誤。
Slide 29 在 Android 5.0 以后,我們還可以把 Android 設備作為外設,被中心設備連接。這個時候開始,Android 設備之間可以真正地使用 BLE 進行雙向通信了,應用場景也非常多。具體的實現與 Central 基本的對應,了解了 GATT 原理,這里實現也就非常簡單了。這里不詳細說了。
Slide 30 通過前面的介紹,已經講解完了 Android 設備作為 BLE 應用的所有四個角色:監聽者、廣播者、中心設備以及外設。也穿插介紹了一些開發中可能遇到的坑,但是實際開發過程中,我們需要怎么 Debug BLE 相關的問題呢?下面我們介紹一些可以幫助我們的 Debug 工具。
Slide 31 首先,我們可以使用一些 BLE 測試 APP 來驗證一些基本功能,在應用市場上有很多類似的 APP,這里特別推薦 nRF Connect 這個 App。這個 APP 就像 API demo 一樣,實現了所有 Android 提供的 API 能做的事情,APP 質量很高,用起來也非常方便,前面介紹有些截圖,就是來自這個 APP。
另外,查看 Log 是最常用的方法。 Logcat 作為 Android 開發者最熟悉不過。Logcat 中可以查看 com.android.bluetooth 這個進程的 log,可以了解 Java 層的一些狀態。
更深入一點,我們可以查看協議棧的 log。藍牙的協議棧 log 默認沒有打印,我們可以在開發者選擇中打開。(動畫)。如圖中所示,打開這兩個開關:
先說下面這個開關,打開這個開關,在 Logcat 就會中輸出 BlueDroid 中的 Log,通過這些 log 可以排查 BlueDroid 里面實現的一些問題。
有時候,有時候知道協議棧的log可能還不夠,打開第一個開關,系統就會抓取 HCI 層的 log,log 文件一般在 /sdcard/bt_snoop.log。HCI 層我們之前介紹了,Host 和 Controller 交互的必經之路。這個 log 非常類似我們在網卡上進行的網絡抓包。實際上這個 log 文件,也可以通過網絡抓包軟件 WireShark 打開,如圖,這里可以看到所有 HCI 命令和事件,以及對應的數據。通過這個 log 可以排查藍牙芯片以上的問題。
其實還可以更進一步,可以排查藍牙芯片是否正常工作,就是通過一些設備直接抓取藍牙空中包。這個需要購買特定的硬件和軟件配合使用。
Slide 32 最后我們來總結一下,Android 中 BLE 開發一些所謂的最佳實踐。
Slide 33 最后我們來總結一下,Android 中 BLE 開發一些所謂的最佳實踐。
Slide 34 首先,我們要盡量少干一些事情。因為藍牙的硬件資源有限,對芯片的請求當然是越少越好。另外,BlueDroid 還很年輕,上層對它的壓力也是越小越好。我們在保證業務的情況下,可以盡量遵循如下一些原則:盡量少的連接數量,盡量短的連接時間,盡量少的掃描,至于盡量少的 ClientIf,如果在 APP 中多個模塊中都要掃描或者連接,應該做盡可能的合并。盡量少的廣播數據,盡量少的并行請求,在回調中要做盡量少的工作。
Slide 35 另外,我們需要盡量多做一些事情。藍牙雖然是一個統一的標準,但是不同廠家實現之間還是有一定的差距,例如 MTK 和高通平臺是有些不一樣的。另外,藍牙這一塊,不同的 ROM 廠家都會有一些修改,需要在不同的 ROM 上都要做一些測試,最后連接的外設,實現也不太一樣,也需要做盡量多的測試。
Bluetooth 還在快速的發展,不管是藍牙規范的制定,還是 Android 平臺對藍牙的支持,給了我們開發者提供了更多的空間和可能性,期待 Android BLE 能夠出現更多好用好玩的應用。
Slide 36 最后,這次分享沒法做到面面俱到,開發過程中還需要更深入的了解,這里有一些參考資料:
- 這是藍牙的 4.1 的協議文檔,這是最權威的資料了;
- 這是 Bluetooth 的官方網站,關于藍牙的各種資料都能從這里找到;
- 這是我關于藍牙寫的一些文章;
- 這是 Android 開發者網站關于低功耗藍牙的開發的簡介。
來自:http://www.race604.com/android-ble-in-action/