對於ios應用,你必需要清楚它是在前臺運行,仍是在後臺運行。由於資源有限,你要對這兩種模式區別處理。ios
默認狀況下,當應用進入後臺或掛起時,藍牙任務是不執行的。可是,你能夠把應用聲明爲支持藍牙後臺執行模式,這樣當有藍牙相關事件發生時,你的應用就能夠被喚醒來處理任務。即便你的應用不要求後臺處理支持,當有重要的事件發生時,系統仍然可能跳出警告,要求處理。數據庫
即便你的應用支持一種或兩種都支持後臺執行模式,也不是就必定能永遠執行。在某些狀況下,系統可能終止你的應用以便爲前臺應用讓出內存,這將致使當前活動和鏈接等信息丟失。自ios7以後,藍牙庫支持保存狀態信息,並可在下次啓動app時還原狀態信息。你能夠經過這個特性來實現長鏈接。安全
Foreground-Only Apps
只支持前臺運行的應用
大部分的apps,除非你要求後臺運行,在進入後臺後,應用會很快被掛起。在掛起狀態下,應用沒法處理藍牙相關任務,沒法接收藍牙事件。直到從新回到前臺。app
在central端,只支持前臺運行的應用,在進入後臺或被掛起時就沒法掃描和發現peripheral的廣播包。若是是在peripheral端,廣播將中止,任何central想訪問characteristic的值都將收到異常信息。框架
不一樣狀況下,默認的行爲可能會影響你的程序。好比,在你與peripheral交互數據時,應用掛起(好比用戶切到另外一個應用)。這時鏈接可能會斷開,你並不會收到通知,直到應用從新激活。ui
Take Advantage of Peripheral Connection Options代理
利用peripheral鏈接選項orm
只支持前臺的藍牙應用在掛起後發生的藍牙事件會被系統排隊,並在應用進入前臺時把事件發給應用。當特定的central事件發生時,藍牙庫能夠提供一種方式來提示用戶。用戶能夠根據這些提示來決定是否激活應用。htm
若想利用使用這些提示,你須要在調用connectPeripheral:options: 方法時傳入以下參數。
CBConnectPeripheralOptionNotifyOnConnectionKey: 在應用掛起後,與指定的peripheral成功創建鏈接,則發出通知
CBConnectPeripheralOptionNotifyOnDisconnectionKey: 在應用掛起後,若是與指定的peripheral斷開鏈接,則發出通知
CBConnectPeripheralOptionNotifyOnNotificationKey: 在應用掛起後,指定的peripheral有任何通知都進行提示
Core Bluetooth Background Execution Modes
後臺執行模式
若是你的應用在後臺時也須要處理藍牙事件,就必須在Info.plist中聲明應用要支持藍牙後臺模式,這樣,當有藍牙事件發生時,系統會喚醒應用來處理。
有兩種藍牙後臺模式,一種爲central角色,另外一種爲peripheral角色。若是應用須要兩種角色,則能夠聲明支持兩種模式。聲明方式:增長UIBackgroundModes 鍵,並增長包含下列字符串的array值。
? bluetooth-central—The app communicates with Bluetooth low energy peripherals using the Core Bluetooth framework.
? bluetooth-peripheral—The app shares data using the Core Bluetooth framework
注意:Info.plist中會顯示爲更加人性化的文本,不是直接顯示實際的鍵值對。如要顯示實際值,可右鍵,或control點擊,在彈出菜單中選擇Show Raw Keys/Values
The bluetooth-central Background Execution Mode
支持central後臺運行的模式
若是你的應用支持central角色的後臺模式,也就是Info.plist中UIBackgroundModes鍵的值中包含bluetooth-central值。那麼應用將能夠在後臺處理特定的藍牙相關事件。即便在後臺,你仍然能夠發現和鏈接peripherals,能夠檢索和讀寫數據。而且當有CBCentralManagerDelegate or CBPeripheralDelegate 代理事件發生時,系統會喚醒應用來處理。
須要注意的是,進入後臺時,掃描的處理有些區別:
1, CBCentralManagerScanOptionAllowDuplicatesKey 這個鍵會被忽略,屢次發現同一peripheral會被合併成一個發現事件。
2,若是全部掃描中的應用都在後臺,那麼你應用的掃描間隙會延長。結果是,掃描到peripheral的時間可能會延長。
這樣作是爲了減小輻射節省電量。
The bluetooth-peripheral Background Execution Mode
支持peripheral後臺運行的模式
若是要支持peripheral角色的後臺模式,你須要在Info.plist中的增長UIBackgroundModes鍵並在值中包含bluetooth-peripheral值。這樣系統會喚醒應用來處理讀寫和訂閱事件。
藍牙框架(Core Bluetooth framework)不只容許你的應用被喚醒來處理讀寫和訂閱請求,還容許你的應用在後臺狀態下發送廣播。但你必須注意後臺時廣播與前臺時廣播是不一樣的。即使如此,你必須注意後臺與前臺時廣播處理的區別。特別是當你的應用須要在後臺發送廣播。
1,CBAdvertisementDataLocalNameKey 這個鍵會被忽略,而且peripheral的local name不會被廣播
2,CBAdvertisementDataServiceUUIDsKey 的值中包含的全部service uuids都會被放到「overflow」區域;只有ios設備顯示指明在搜索它時纔會搜索到這些值。
3,若是全部的處於廣播狀態的應用都在後臺,廣播頻率將下降。
Use Background Execution Modes Wisely
明智使用後臺運行模式
雖然爲了完成某些事情,有必要把你的應用聲明成支持後臺運行模式,你也應該要能有效處理後臺任務。由於執行藍牙任務會使用無線電,從而耗費電池電量,因此儘可能最小化後臺任務。應用被藍牙事件喚醒後應能儘快處理好任務,以便被從新掛起。
支持後臺運行的任務要遵循幾個原則
1,應用應該是基於會話的,並提供接口讓用戶決定什麼時候開始或中止藍牙事件。
2,應用被喚醒後,大約有10秒鐘的時間來完成任務,因此應該儘快完成任務並從新掛起。若在後臺花費太多時間,則將受到系統的遏制甚至被扼殺。
3,應用不該該使用這種被喚醒的機會來執行與之無關的事情。
Performing Long-Term Actions in the Background
後臺長時間執行
一些應用須要長時間後臺運行。舉個例子,你可發一款家庭安全應用,ios設備與藍牙門鎖通信。當用戶離開家時自動鎖門,當用戶回到家時門自動打開,整個過程應用都是後臺運行。當用戶離開家時,ios與門鎖斷開鏈接。這是應用只簡單調用connectPeripheral:options: ,由於鏈接沒有超時,ios設備將在用戶回到家時從新鏈接上。
假設用戶離開家好幾天,並假設app被系統終止,應用將沒法在用戶回到家時重連門鎖,這時用戶將沒法開門。對於這類應用,很重要的一點要可以繼續使用藍牙執行長時事件,如管理活動和懸停鏈接。
State Preservation and Restoration
狀態保存和還原
由於狀態保存和還原是藍牙內在支持的,你的應用可選擇支持這一特徵來讓系統保存central和peripheral manager的狀態,並繼續執行藍牙任務,即便你的應用不在運行。當任務完成,系統從新激活應用到後臺,讓你的應用有機會還原狀態並處理事件。上面說的家庭安全應用,系統能夠管理鏈接請求,並在用戶回到家從新鏈接上藍牙時從新激活應用來處理 centralManager:didConnectPeripheral: 代理回調。
藍牙庫支持狀態保存和還原,支持central角色,peripheral角色。當應用實現central角色並增長支持狀態保存和還原,系統就會在終止應用釋放內存前保存central manager對象的狀態,若是應用有多個central managers,你可選擇哪些對象你但願系統爲你維護。對於CBcentralManger 對象,系統如此維護:
1,central manager掃描的services和對應的options
2,已鏈接的和未鏈接上的peripherals
3,訂閱的characteristics
實現peirpheral角色的應用相似處理。對於CBPeripheralManager對象,系統這樣維護:
1,廣播的數據
2,peripheral manager發佈到設備數據庫的services和characteristic
3,那些訂閱了你characteristics的值得centrals
當應用被系統從新激活到後臺,假如應用以前有發現peripheral,你能夠從新建立應用的central和peripheral manager,並還原他們的狀態。後面將繼續說明如何利用狀態保存與還原。
Adding Support for State Preservation and Restoration
增長支持狀態保存與還原
這一特性是可選的,增長步驟以下:
1,(必須)在建立和初始化時選擇支持狀態保存和還原。Opt In to State Preservation and Restoration 這一節將更詳細描述
2,(必須)在應用被系統喚醒時復原central或peripheral manager對象。Reinstantiate Your Central and Peripheral Managers 這裏將繼續描述
3,(必須)實現還原代理方法。Implement the Appropriate Restoration Delegate Method. 這裏將繼續說明
4,(可選)更新central和peripheral managers的初始化過程。Update Your Initialization Process。這裏將繼續說明
Opt In to State Preservation and Restoration
選擇支持狀態保存和還原
在建立和初始化時,提供惟一的還原id。還原id是字符串,對於藍牙庫和應用來講,還原id是用來標記central或peripheral manger的。你的代碼只關心這個字符串,但這個字符串告訴藍牙庫須要保存被標記對象的狀態。藍牙庫只保存那些有標記還原id的對象的狀態。
假如,選擇支持狀態保存和還原的應用只有一個CBCentralMnager對象實例實現了central角色,那麼在初始化時初始化options中增長CBCentralManagerOptionRestoreIdentifierKey 鍵,並賦值還原id.
myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{
CBCentralManagerOptionRestoreIdentifierKey: @"myCentralManagerIdentifier" }
];
peripheral manager的處理也是相似的,key是CBPeripheralManagerOptionRestoreIdentifierKey
注意:由於應用能夠有多個CBCentralManager 和 CBPeripheralManger實例。注意每一個還原id都是惟一的,這樣系統才能區分開來。
Reinstantiate Your Central and Peripheral Managers
復原central和peripheral manager
當應用被系統喚醒,你須要作的第一件事是使用還原id復原central and peripheral manager。若是應用中只有一個central or peripheral manager,而且在應用的整個生命週期中存在,那麼就簡單了。
若是應用使用多個central or peripheral manager 或若是應用使用的manager不是在app的整個生命週期中存在,那麼應用須要知道哪些managers須要復原。在實現application:didFinishLaunchingWithOptions: 這個代理方法時,經過使用參數launchoptions中的鍵(UIApplicationLaunchOptionsBluetoothCentralsKey or UIApplicationLaunchOptionsBluetoothPeripheralsKey) 能夠得到應用在終止時爲咱們保存的還原id列表。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSArray *centralManagerIdentifiers = launchOptions[UIApplicationLaunchOptionsBluetoothCentralsKey];
...
有了還原id列表後,就能夠復原出central manager 對象了。
注意:當應用被激活時,系統只提供那些應用終止時有藍牙任務的central and peripheral managers 的還原ids.
Implement the Appropriate Restoration Delegate Method
實現還原代理方法
在從新建立central and peripheral managers以後,須要經過藍牙系統還原他們的狀態。對於central managers,要實現centralManager:willRestoreState: 代理方法,對於peripheral managers 實現peripheralManager:willRestoreState: 方法。
重要:對於使用狀態保存和還原特性的應用,應用被激活到後臺的第一個代理調用是centralManager:willRestoreState: and peripheralManager:willRestoreState: 。對於未使用這一特性的應用,第一個代理調用是centralManagerDidUpdateState: and peripheralManagerDidUpdateState:。
在這些代理中,最後一個參數是dictionary,包含了應用被終止時managers的信息。可用鍵值參考 Central Manager State Restoration Options constants in CBCentralManagerDelegate Protocol Reference and the Peripheral_Manager_State_Restoration_Options constants in CBPeripheralManagerDelegate Protocol Reference
要還原CBCentralMnager 對象的狀態,要使用centralManager:willRestoreState: 方法中dictionary的鍵值對。舉個例子,假如centralmanger對象在app被終止時有acitve或pending鏈接,系統會繼續管理他們。就像下面代碼所示,可使用CBCentralManagerRestoredStatePeripheralsKey 鍵從dictionary中獲取全部設備的列表,這些設備就是central manger已鏈接或正在鏈接的設備。
- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)state {
NSArray *peripherals = state[CBCentralManagerRestoredStatePeripheralsKey];
...
如何使用這個列表要看具體狀況。好比,若是應用要維護central manger 已發現peripherals的列表,你可能就須要利用到它。參見Connecting to a Peripheral Device After You’ve Discovered It, 請注意在須要給peripheral設置相應的代理。
對於CBPeripheralManager 對象,也須要相似的處理,相應的代理方法是peripheralManager:willRestoreState: 。
Update Your Initialization Process
更新你的初始化進程
在前面的三個步驟以後,你可能想知道central and peripheral manager的初始化進程。雖然這是一個可選步驟,但若是想讓你的應用跑起來更流暢,這但是很重要的。假設應用在檢索peripheral的服務時被終止。當應用還原後,它不知道這個過程到底進行到哪一步了。你也想知道從哪一步繼續。
舉例,當在centralManagerDidUpdateState:方法中初始化你的應用時,你能夠查到在應用被終止時你是否成功發現被還原peripheral的某個service,以下:
NSUInteger serviceUUIDIndex = [peripheral.services indexOfObjectPassingTest:^BOOL(CBService *obj,NSUInteger index, BOOL *stop) {
return [obj.UUID isEqual:myServiceUUIDString];
}
];
if (serviceUUIDIndex == NSNotFound) {
[peripheral discoverServices:@[myServiceUUIDString]];
...
如上,若是系統在應用發現service以前終止它,那麼開始搜索peripheral的數據,使用discoverServices:搜索。若是應用在被終止前已搜索到service,那麼你須要檢查時候搜索到你要的characteristics,(若是有訂閱,也檢查是否已訂閱)。經過檢查初始化過程,能夠確保在這時調用到最合適的方法。