iOS BLE 開發小記[5] 與 Remote Peripheral 互動的最佳實踐

muhlenXi發表於2019-04-22

歡迎訪問我的部落格 muhlenXi,該文章出自我的部落格,歡迎轉載,轉載請註明來源: muhlenxi.com/2017/05/05/…

導語:

在這一節,主要是與 Remote Peripheral 互動的最佳實踐,以及實際開發過程中應該注意的事項。

CoreBluetooth 框架使 Central 端的工作變得容易透明、容易理解。也就是說,你的 APP 可以控制和負責 Central 的大部分方面,比如搜尋裝置、建立連線、與 Remote Peripheral 進行資料互動。本章將以負責的方式來提供一些規範和最佳實踐,尤其是當你為 iOS 裝置開發 APP 的時候。

要留意 Radio 的使用和電量的消耗

當開發一個 APP 與 BLE 裝置互動時,需要銘記:BLE 通訊會通過你的裝置向空中發射 Radio 訊號。其他形式的無線通訊也可能需要使用裝置的 Radio,比如,Wi-Fi,傳統藍芽以及使用 BLE 的其他 APP。因此要減少 Radio 的使用。

當開發 iOS 裝置的 APP 時,最少次數使用 Radio 很重要,因為 Radio 的使用會對 iOS 裝置電池的續航時間有不利影響。以下的這些規範將會幫助你更好的使用 Radio。作為回報,你的 APP 會良好執行和你裝置電池的續航時間將會延長。

只在需要的時候搜尋周邊裝置

當你呼叫 CBCentralManager 類的 scanForPeripheralsWithServices:options: 方法來搜尋正在廣播資料的 Remote Peripheral 時,你裝置的 Radio 會一直監聽正在廣播的裝置,直到你停止搜尋為止。

除非你需要搜尋更多的裝置,否則當你找到你想要連線的裝置後就應該停止搜尋,前幾篇提到過,用 CBCentralManager 類的 stopScan 方法來停止搜尋裝置。

必要的時候再指定 CBCentralManagerScanOptionAllowDuplicatesKey 選項

Remote Peripheral 裝置可能會每秒傳送多個廣播資料包給監聽的 Central,當你呼叫 scanForPeripheralsWithServices:options: 方法搜尋裝置時,該方法預設的行為是將一個 Peripheral 的多個發現事件合併成一個發現事件,也就是說,Central Manager 每找到一個新的 Peripheral 時才會呼叫 centralManager:didDiscoverPeripheral:advertisementData:RSSI: 代理方法,不管收到多少廣播資料包都不會呼叫該方法。當已發現的 Peripheral 的廣播資料發生變化時也會呼叫這一代理方法。

如果你想改變預設行為,呼叫 scanForPeripheralsWithServices:options: 方法時你可以指定 scan option 為 CBCentralManagerScanOptionAllowDuplicatesKey,這樣每當 Central 收到來自 Peripheral 的資料包就會建立一個發現事件。對於某些情況關閉預設行為會很有用,比如基於 Peripheral 的 Proximity (靠近程度)來進行連線互動。Proximity 可以通過 Peripheral 的 接收訊號強度指示(RSSI)的值來判斷,也就是說,指定這個掃描選項會對電源的續航和 APP 的執行造成不利影響。因此,只在必要的情況下再指定該方法的 scan option。

明智地獲取 Peripheral 的資料

當你開發 APP 的時候,對於特定的使用情景,一個 Peripheral 裝置可能擁的大量的 Service 和 Characteristic 已經超過了你需要的數量 ,搜尋 Peripheral 全部的 Service 和 Characteristic 對電源的續航和 APP 的效能帶來不利影響。因此。你應該只搜尋你的 APP 需要的 Service 和 Characteristic。

舉個例子,假如你連線的 Peripheral 有許多可用的 Service,但是你的 APP 只需要用到其中的兩個。你只需要搜尋這兩個 Service 就可以了,只需要呼叫 CBPeripheral 類的 discoverServices: 方法時傳入 Service UUID(用 CBUUID 物件表示) 陣列就可以了。如下所示:

[peripheral discoverServices:@[firstServiceUUID, secondServiceUUID]];
複製程式碼

當你搜尋到這兩個需要的 Service 後,你可以用相似的方式來搜尋你需要的 Characteristic,同樣地,在呼叫 CBPeripheral 類的 discoverCharacteristics:forService: 方法時傳入你想要的 Characteristic UUID(用 CBUUID 物件表示) 陣列就可以了。

訂閱值頻繁變化的 Characteristic

通過前面的文章,我們瞭解到,獲取一個 Characteristic 值的方式有兩種:

  • 你可以在每次需要值的時候明確的呼叫 readValueForCharacteristic: 方法來讀取 Characteristic 的值。
  • 你可以呼叫 setNotifyValue:forCharacteristic: 方法來訂閱 Characteristic 的值,這樣當值發生改變後就會收到來自 Peripheral 的通知。

對於值可能變化的 Characteristic 來說,訂閱是最佳實踐方式,尤其是對於值頻繁改變的 Characteristic,關於如何訂閱一個 Characteristic 的值,可以查閱 Subscribing to a Characteristic’s Value.

當你得到你需要的資料後斷開與裝置的連線

當不再需要連線的時候與裝置斷開連線可以幫助你減少 Radio 的使用,你應該在以下的情景中斷開與 Peripheral 裝置的連線:

  • 你所有訂閱的 Characteristic 的值已經不再通知,你可以通過 Characteristic 的 isNotifying 屬性來判斷 Characteristic 的值是否通知。
  • 你從 Peripheral 裝置中得到了所有的資料。

在上述的場景中,取消一些訂閱並與 Peripheral 斷開連線,你可以通過呼叫 setNotifyValue:forCharacteristic: 方法來取消訂閱一個 Characteristic 的值,設定第一個引數為 NO 。你可以通過呼叫 CBCentralManager 類的 cancelPeripheralConnection: 方法來斷開與 Peripheral 裝置的連線。像這樣:

[myCentralManager cancelPeripheralConnection:peripheral];
複製程式碼

提示:cancelPeripheralConnection:方法是 nonblocking(非阻塞)的,一些 CBPeripheral 類的命令仍然等待 Peripheral,當你嘗試斷開連線可能沒有完成執行.因為可能其他 APP 還在連線 Peripheral,取消一個本地連線不能保證裝置物理連線立刻斷開。從 APP 的角度來看,認為 Peripheral 是斷開的,Central Manager 會呼叫 centralManager:didDisconnectPeripheral:error: 代理方法進行回撥。

重新連線 Peripheral

使用 CoreBluetooth 框架,你有三種方式可以重新連線 Peripheral:

  • 通過呼叫 retrievePeripheralsWithIdentifiers: 方法來恢復一個已知的 Peripheral 列表 --- Peripheral 是你發現的或者過去連線的。如果你要找的 Peripheral 在列表中,嘗試去連線它。這種重連方式在 恢復已知的 Peripheral 列表 小節中有描述。

  • 通過呼叫 retrieveConnectedPeripheralsWithServices: 方法來恢復系統當前已經連線的 Peripheral 列表,如果你要找的在列表中,則與它建立一個本地連線,這種重連方式在 恢復當前已連線的 Peripheral 列表 小節中有描述。

  • 通過呼叫 scanForPeripheralsWithServices:options: 方法掃描和搜尋 Peripheral,如果找到它,則連線。這種方式在 iOS BLE 開發小記[2]中有描述。

根據使用情況,每次重連 Peripheral ,你可能不想掃描和搜尋同樣的 Peripheral,你可能首先想用其他方式來重連。如圖所示,一個可能的重連工作流程可能是按照上面的提到的順序依次嘗試這些方式。

重連工作流程

提示:你決定嘗試的重連方式的個數取決於 APP 的使用情況,舉個例子,你可能決定不使用第一種方式,或者你可能並行使用第一種和第二種方式。

恢復已知的 Peripheral 列表

當你第一次發現一個 Peripheral 時候,系統會建立一個識別符號(用 NSUUID 物件表示的一個 UUID)來標識這個 Peripheral,你可以使用 NSUserDefaults 來儲存這個識別符號。過後你可以嘗試呼叫CBCentralManager 類的 retrievePeripheralsWithIdentifiers: 方法來恢復並重新連線這個 Peripheral,下面描述的一種方式就是使用這個方法來重新連線以前的 Peripheral。

當 APP 啟動時,呼叫 retrievePeripheralsWithIdentifiers: 方法,傳入一個包含 Peripheral 識別符號的陣列來發現和重連先前的 Peripheral,像這樣:

knownPeripherals =
        [myCentralManager retrievePeripheralsWithIdentifiers:savedIdentifiers];
複製程式碼

Central Manager 嘗試在先前發現的 Peripheral中去匹配你提供的識別符號,然後返回一個包含 CBPeripheral 物件的陣列,如果沒有匹配的物件,陣列將會是空的。你應該去嘗試其餘的兩種方式中的一種。如果陣列不是空的,在介面中讓使用者去選擇要重連哪一個。

當使用者選擇 Peripheral 後,呼叫 CBCentralManager 類的 connectPeripheral:options: 方法去連線 Peripheral。如果 Peripheral 裝置被連線後, Central Manager 會呼叫 centralManager:didConnectPeripheral: 代理方法,此時 Peripheral 重連成功。

提示:Peripheral 可能因為一些原因不能連線,舉個例子,裝置不在 Central 附近,此外,一些 BLE 裝置使用週期變化的隨機裝置地址。因此,即使裝置在附近,從上次系統發現 Peripheral,裝置的地址也可能發生改變,在這種情況下,你嘗試連線的 CBPeripheral 物件與實際的 Peripheral 不相符。如果你不能重新連線 Peripheral,因為它的裝置地址已經變了,你必須重新呼叫 scanForPeripheralsWithServices:options: 方法來搜尋連線。

關於裝置隨機地址的詳細資訊,請查閱 Bluetooth 4.0 規範,第3卷,C部分,10.8 章節和 Bluetooth Accessory Design Guidelines for Apple Products.

恢復當前已連線的 Peripheral 列表

另一種重連 Peripheral 的方式就是檢查你要連線的 Peripheral 是否一直被系統連線(舉例,被另一個 APP 連線),你可以呼叫 CBCentralManager 類的 retrieveConnectedPeripheralsWithServices: 方法,它返回一個 CBPeripheral 物件的陣列,陣列中包含當前系統已經連線的 Peripheral。

因為系統當前可能連線超過一個以上的 Peripheral,你可以傳入一個 CBUUID 物件的陣列來恢復你指定 Service的 Peripheral,如果當前連線的 Peripheral 中沒有你指定的 Peripheral,陣列將是空的,你應該嘗試其餘兩種方式中的一種。如果陣列不為空,在介面中讓使用者去選擇要重連哪一個。

假設使用者選擇了渴望的 Peripheral,通過呼叫 CBCentralManager 類的 connectPeripheral:options: 方法來本地化連線。即使系統一直連線著裝置,你必須本地化連線後再進行互動。當建立了本地連線後,Central Manager 會呼叫 centralManager:didConnectPeripheral: 代理方法,此時裝置重連成功。

參考文獻

1、Best Practices for Interacting with a Remote Peripheral Device

結束語

歡迎在本文下面留言一起交流心得...

相關文章