原文:http://blog.csdn.net/swibyn/article/details/52096646
Core Bluetooth Background Processing for iOS Apps
iOS藍(lán)牙應(yīng)用的后臺處理
對于ios應(yīng)用,你必須要清楚它是在前臺運(yùn)行纹磺,還是在后臺運(yùn)行。因為資源有限鸟辅,你要對這兩種模式區(qū)別處理。
默認(rèn)情況下莺葫,當(dāng)應(yīng)用進(jìn)入后臺或掛起時匪凉,藍(lán)牙任務(wù)是不執(zhí)行的。但是捺檬,你可以把應(yīng)用聲明為支持藍(lán)牙后臺執(zhí)行模式再层,這樣當(dāng)有藍(lán)牙相關(guān)事件發(fā)生時,你的應(yīng)用就可以被喚醒來處理任務(wù)堡纬。即使你的應(yīng)用不要求后臺處理支持聂受,當(dāng)有重要的事件發(fā)生時,系統(tǒng)仍然可能跳出警告隐轩,要求處理饺饭。
即使你的應(yīng)用支持一種或兩種都支持后臺執(zhí)行模式,也不是就一定能永遠(yuǎn)執(zhí)行职车。在某些情況下,系統(tǒng)可能終止你的應(yīng)用以便為前臺應(yīng)用讓出內(nèi)存,這將導(dǎo)致當(dāng)前活動和連接等信息丟失悴灵。自ios7之后扛芽,藍(lán)牙庫支持保存狀態(tài)信息,并可在下次啟動app時還原狀態(tài)信息积瞒。你可以通過這個特性來實(shí)現(xiàn)長連接川尖。
Foreground-Only Apps
只支持前臺運(yùn)行的應(yīng)用
大部分的apps,除非你要求后臺運(yùn)行茫孔,在進(jìn)入后臺后叮喳,應(yīng)用會很快被掛起。在掛起狀態(tài)下缰贝,應(yīng)用無法處理藍(lán)牙相關(guān)任務(wù)馍悟,無法接收藍(lán)牙事件。直到重新回到前臺剩晴。
在central端锣咒,只支持前臺運(yùn)行的應(yīng)用,在進(jìn)入后臺或被掛起時就無法掃描和發(fā)現(xiàn)peripheral的廣播包赞弥。如果是在peripheral端毅整,廣播將停止,任何central想訪問characteristic的值都將收到異常信息绽左。
不同情況下悼嫉,默認(rèn)的行為可能會影響你的程序糙俗。比如锻霎,在你與peripheral交互數(shù)據(jù)時蔚出,應(yīng)用掛起(比如用戶切到另一個應(yīng)用)谈秫。這時連接可能會斷開章办,你并不會收到通知剃氧,直到應(yīng)用重新激活娱据。
Take Advantage of Peripheral Connection Options
利用peripheral連接選項
只支持前臺的藍(lán)牙應(yīng)用在掛起后發(fā)生的藍(lán)牙事件會被系統(tǒng)排隊仅叫,并在應(yīng)用進(jìn)入前臺時把事件發(fā)給應(yīng)用房交。當(dāng)特定的central事件發(fā)生時彻舰,藍(lán)牙庫可以提供一種方式來提示用戶。用戶可以根據(jù)這些提示來決定是否激活應(yīng)用候味。
若想利用使用這些提示刃唤,你需要在調(diào)用connectPeripheral:options: 方法時傳入如下參數(shù)。
CBConnectPeripheralOptionNotifyOnConnectionKey
: 在應(yīng)用掛起后白群,與指定的peripheral成功建立連接尚胞,則發(fā)出通知
CBConnectPeripheralOptionNotifyOnDisconnectionKey
: 在應(yīng)用掛起后,如果與指定的peripheral斷開連接帜慢,則發(fā)出通知
CBConnectPeripheralOptionNotifyOnNotificationKey
: 在應(yīng)用掛起后笼裳,指定的peripheral有任何通知都進(jìn)行提示
Core Bluetooth Background Execution Modes
后臺執(zhí)行模式
如果你的應(yīng)用在后臺時也需要處理藍(lán)牙事件唯卖,就必須在Info.plist中聲明應(yīng)用要支持藍(lán)牙后臺模式,這樣躬柬,當(dāng)有藍(lán)牙事件發(fā)生時拜轨,系統(tǒng)會喚醒應(yīng)用來處理。
有兩種藍(lán)牙后臺模式允青,一種為central角色橄碾,另一種為peripheral角色。如果應(yīng)用需要兩種角色颠锉,則可以聲明支持兩種模式法牲。
聲明方式:增加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中會顯示為更加人性化的文本拒垃,不是直接顯示實(shí)際的鍵值對。如要顯示實(shí)際值眉枕,可右鍵恶复,或control點(diǎn)擊,在彈出菜單中選擇Show Raw Keys/Values
The bluetooth-central Background Execution Mode
支持central后臺運(yùn)行的模式
如果你的應(yīng)用支持central角色的后臺模式速挑,也就是Info.plist中UIBackgroundModes鍵的值中包含bluetooth-central值谤牡。那么應(yīng)用將可以在后臺處理特定的藍(lán)牙相關(guān)事件。即使在后臺姥宝,你仍然可以發(fā)現(xiàn)和連接peripherals翅萤,可以檢索和讀寫數(shù)據(jù)。并且當(dāng)有CBCentralManagerDelegate or CBPeripheralDelegate 代理事件發(fā)生時腊满,系統(tǒng)會喚醒應(yīng)用來處理套么。
需要注意的是,進(jìn)入后臺時碳蛋,掃描的處理有些區(qū)別: 1胚泌, CBCentralManagerScanOptionAllowDuplicatesKey
這個鍵會被忽略,多次發(fā)現(xiàn)同一peripheral會被合并成一個發(fā)現(xiàn)事件肃弟。 2玷室,如果所有掃描中的應(yīng)用都在后臺,那么你應(yīng)用的掃描間隙會延長笤受。結(jié)果是穷缤,掃描到peripheral的時間可能會延長。
這樣做是為了減少輻射節(jié)省電量箩兽。
The bluetooth-peripheral Background Execution Mode
支持peripheral后臺運(yùn)行的模式
如果要支持peripheral角色的后臺模式津肛,你需要在Info.plist中的增加UIBackgroundModes鍵并在值中包含bluetooth-peripheral值。這樣系統(tǒng)會喚醒應(yīng)用來處理讀寫和訂閱事件汗贫。
藍(lán)牙框架(Core Bluetooth framework)不僅允許你的應(yīng)用被喚醒來處理讀寫和訂閱請求身坐,還允許你的應(yīng)用在后臺狀態(tài)下發(fā)送廣播秸脱。但你必須注意后臺時廣播與前臺時廣播是不同的。即便如此掀亥,你必須注意后臺與前臺時廣播處理的區(qū)別撞反。特別是當(dāng)你的應(yīng)用需要在后臺發(fā)送廣播妥色。
1搪花,CBAdvertisementDataLocalNameKey
這個鍵會被忽略,并且peripheral的local name不會被廣播
2嘹害,CBAdvertisementDataServiceUUIDsKey
的值中包含的所有service uuids都會被放到“overflow”區(qū)域撮竿;只有ios設(shè)備顯示指明在搜索它時才會搜索到這些值。
3笔呀,如果所有的處于廣播狀態(tài)的應(yīng)用都在后臺幢踏,廣播頻率將降低。
Use Background Execution Modes Wisely
明智使用后臺運(yùn)行模式
雖然為了完成某些事情许师,有必要把你的應(yīng)用聲明成支持后臺運(yùn)行模式房蝉,你也應(yīng)該要能有效處理后臺任務(wù)。因為執(zhí)行藍(lán)牙任務(wù)會使用無線電微渠,從而耗費(fèi)電池電量搭幻,所以盡量最小化后臺任務(wù)。應(yīng)用被藍(lán)牙事件喚醒后應(yīng)能盡快處理好任務(wù)逞盆,以便被重新掛起檀蹋。
支持后臺運(yùn)行的任務(wù)要遵循幾個原則 1,應(yīng)用應(yīng)該是基于會話的云芦,并提供接口讓用戶決定何時開始或停止藍(lán)牙事件俯逾。 2,應(yīng)用被喚醒后舅逸,大約有10秒鐘的時間來完成任務(wù)桌肴,所以應(yīng)該盡快完成任務(wù)并重新掛起。若在后臺花費(fèi)太多時間琉历,則將受到系統(tǒng)的遏制甚至被扼殺坠七。 3,應(yīng)用不應(yīng)該使用這種被喚醒的機(jī)會來執(zhí)行與之無關(guān)的事情善已。
Performing Long-Term Actions in the Background
后臺長時間執(zhí)行
一些應(yīng)用需要長時間后臺運(yùn)行灼捂。舉個例子,你可發(fā)一款家庭安全應(yīng)用换团,ios設(shè)備與藍(lán)牙門鎖通訊悉稠。當(dāng)用戶離開家時自動鎖門,當(dāng)用戶回到家時門自動打開艘包,整個過程應(yīng)用都是后臺運(yùn)行的猛。當(dāng)用戶離開家時耀盗,ios與門鎖斷開連接。這是應(yīng)用只簡單調(diào)用connectPeripheral:options:
卦尊,因為連接沒有超時叛拷,ios設(shè)備將在用戶回到家時重新連接上。 假設(shè)用戶離開家好幾天岂却,并假設(shè)app被系統(tǒng)終止忿薇,應(yīng)用將無法在用戶回到家時重連門鎖,這時用戶將無法開門躏哩。對于這類應(yīng)用署浩,很重要的一點(diǎn)要能夠繼續(xù)使用藍(lán)牙執(zhí)行長時事件,如管理活動和懸停連接扫尺。
State Preservation and Restoration
狀態(tài)保存和還原
因為狀態(tài)保存和還原是藍(lán)牙內(nèi)在支持的筋栋,你的應(yīng)用可選擇支持這一特征來讓系統(tǒng)保存central和peripheral manager的狀態(tài),并繼續(xù)執(zhí)行藍(lán)牙任務(wù)正驻,即使你的應(yīng)用不在運(yùn)行弊攘。當(dāng)任務(wù)完成,系統(tǒng)重新激活應(yīng)用到后臺姑曙,讓你的應(yīng)用有機(jī)會還原狀態(tài)并處理事件襟交。上面說的家庭安全應(yīng)用,系統(tǒng)可以管理連接請求渣磷,并在用戶回到家重新連接上藍(lán)牙時重新激活應(yīng)用來處理 centralManager:didConnectPeripheral:
代理回調(diào)婿着。
藍(lán)牙庫支持狀態(tài)保存和還原,支持central角色醋界,peripheral角色竟宋。當(dāng)應(yīng)用實(shí)現(xiàn)central角色并增加支持狀態(tài)保存和還原,系統(tǒng)就會在終止應(yīng)用釋放內(nèi)存前保存central manager對象的狀態(tài)形纺,如果應(yīng)用有多個central managers,你可選擇哪些對象你希望系統(tǒng)為你維護(hù)丘侠。對于CBcentralManger 對象,系統(tǒng)維護(hù)這些:
1逐样,central manager掃描的services和對應(yīng)的options
2蜗字,已連接的和未連接上的peripherals
3,訂閱的characteristics
實(shí)現(xiàn)peirpheral角色的應(yīng)用類似處理脂新。對于CBPeripheralManager對象挪捕,系統(tǒng)維護(hù)這些:
1,廣播的數(shù)據(jù)
2争便,peripheral manager發(fā)布到設(shè)備數(shù)據(jù)庫的services和characteristic
3级零,那些訂閱了你characteristics的值得centrals
當(dāng)應(yīng)用被系統(tǒng)重新激活到后臺,假如應(yīng)用之前有發(fā)現(xiàn)peripheral滞乙,你可以重新創(chuàng)建應(yīng)用的central和peripheral manager奏纪,并還原他們的狀態(tài)鉴嗤。后面將繼續(xù)說明如何利用狀態(tài)保存與還原。
Adding Support for State Preservation and Restoration
添加狀態(tài)保存與還原的支持
這一特性是可選的序调,增加步驟如下:
1醉锅,(必須)在創(chuàng)建和初始化時選擇支持狀態(tài)保存和還原。Opt In to State Preservation and Restoration 這一節(jié)將更詳細(xì)描述
2发绢,(必須)在應(yīng)用被系統(tǒng)喚醒時復(fù)原central或peripheral manager對象硬耍。Reinstantiate Your Central and Peripheral Managers 這里將繼續(xù)描述
3,(必須)實(shí)現(xiàn)還原代理方法朴摊。Implement the Appropriate Restoration Delegate Method. 這里將繼續(xù)說明
4默垄,(可選)更新central和peripheral managers的初始化過程此虑。Update Your Initialization Process甚纲。這里將繼續(xù)說明
Opt In to State Preservation and Restoration
狀態(tài)保存和還原的設(shè)置
在創(chuàng)建和初始化時,提供唯一的還原id朦前。還原id是字符串介杆,對于藍(lán)牙庫和應(yīng)用來說,還原id是用來標(biāo)記central或peripheral manger的韭寸。你的代碼只關(guān)心這個字符串春哨,但這個字符串告訴藍(lán)牙庫需要保存被標(biāo)記對象的狀態(tài)。藍(lán)牙庫只保存那些有標(biāo)記還原id的對象的狀態(tài)恩伺。
假如赴背,選擇支持狀態(tài)保存和還原的應(yīng)用只有一個CBCentralMnager對象實(shí)例實(shí)現(xiàn)了central角色,那么在初始化時初始化options中增加CBCentralManagerOptionRestoreIdentifierKey 鍵晶渠,并賦值還原id.
/*
NSString * const CBCentralManagerOptionShowPowerAlertKey 對應(yīng)一個NSNumber類型的bool值凰荚,用于設(shè)置是否在關(guān)閉藍(lán)牙時彈出用戶提示
NSString * const CBCentralManagerOptionRestoreIdentifierKey 對應(yīng)一個NSString對象,設(shè)置管理中心的后臺模式恢復(fù)標(biāo)識符ID
*/
myCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{ CBCentralManagerOptionRestoreIdentifierKey: @"myCentralManagerIdentifier" }];
peripheral manager的處理也是類似的褒脯,key是CBPeripheralManagerOptionRestoreIdentifierKey
注意:因為應(yīng)用可以有多個CBCentralManager 和 CBPeripheralManger實(shí)例便瑟。注意每個還原id都是唯一的,這樣系統(tǒng)才能區(qū)分開來番川。
Reinstantiate Your Central and Peripheral Managers
還原central和peripheral manager
當(dāng)應(yīng)用被系統(tǒng)喚醒到涂,你需要做的第一件事是使用還原id復(fù)原central and peripheral manager。如果應(yīng)用中只有一個central or peripheral manager颁督,并且在應(yīng)用的整個生命周期中存在践啄,那么就簡單了。 如果應(yīng)用使用多個central or peripheral manager 或如果應(yīng)用使用的manager不是在app的整個生命周期中存在沉御,那么應(yīng)用需要知道哪些managers需要復(fù)原屿讽。在實(shí)現(xiàn)application:didFinishLaunchingWithOptions:
這個代理方法時,通過使用參數(shù)launchoptions中的鍵(UIApplicationLaunchOptionsBluetoothCentralsKey
or UIApplicationLaunchOptionsBluetoothPeripheralsKey
) 可以獲得應(yīng)用在終止時為我們保存的還原id列表嚷节。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSArray *centralManagerIdentifiers = launchOptions[UIApplicationLaunchOptionsBluetoothCentralsKey]; ...
有了還原id列表后聂儒,就可以復(fù)原出central manager 對象了虎锚。
注意:當(dāng)應(yīng)用被激活時,系統(tǒng)只提供那些應(yīng)用終止時有藍(lán)牙任務(wù)的central and peripheral managers 的還原ids.
Implement the Appropriate Restoration Delegate Method
實(shí)現(xiàn)還原代理方法
在重新創(chuàng)建central and peripheral managers之后衩婚,需要通過藍(lán)牙系統(tǒng)還原他們的狀態(tài)窜护。對于central managers,要實(shí)現(xiàn)centralManager:willRestoreState:
代理方法非春,對于peripheral managers 實(shí)現(xiàn)peripheralManager:willRestoreState:
方法柱徙。
重要:對于使用狀態(tài)保存和還原特性的應(yīng)用,應(yīng)用被激活到后臺的第一個代理調(diào)用是centralManager:willRestoreState: and peripheralManager:willRestoreState:
奇昙。對于未使用這一特性的應(yīng)用护侮,第一個代理調(diào)用是centralManagerDidUpdateState: and peripheralManagerDidUpdateState:
。
在這些代理中储耐,最后一個參數(shù)是dictionary羊初,包含了應(yīng)用被終止時managers的信息∈蚕妫可用鍵值參考 Central Manager State Restoration Options constants in CBCentralManagerDelegate Protocol Reference and the Peripheral_Manager_State_Restoration_Options constants in CBPeripheralManagerDelegate Protocol Reference
要還原CBCentralMnager 對象的狀態(tài)长赞,要使用centralManager:willRestoreState:
方法中dictionary的鍵值對。舉個例子闽撤,假如centralmanger對象在app被終止時有acitve或pending連接得哆,系統(tǒng)會繼續(xù)管理他們。就像下面代碼所示哟旗,可以使用CBCentralManagerRestoredStatePeripheralsKey
鍵從dictionary中獲取所有設(shè)備的列表贩据,這些設(shè)備就是central manger已連接或正在連接的設(shè)備。
//dict中會傳入如下鍵值對
/*
//恢復(fù)連接的外設(shè)數(shù)組
NSString *const CBCentralManagerRestoredStatePeripheralsKey;
//恢復(fù)連接的服務(wù)UUID數(shù)組
NSString *const CBCentralManagerRestoredStateScanServicesKey;
//恢復(fù)連接的外設(shè)掃描屬性字典數(shù)組
NSString *const CBCentralManagerRestoredStateScanOptionsKey;
*/
- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)state {NSArray *peripherals = state[CBCentralManagerRestoredStatePeripheralsKey];...
如何使用這個列表要看具體情況闸餐。比如饱亮,如果應(yīng)用要維護(hù)central manger 已發(fā)現(xiàn)peripherals的列表,你可能就需要利用到它绎巨。參見Connecting to a Peripheral Device After You’ve Discovered It, 請注意在需要給peripheral設(shè)置相應(yīng)的代理近尚。
對于CBPeripheralManager 對象,也需要類似的處理场勤,相應(yīng)的代理方法是peripheralManager:willRestoreState:
戈锻。
Update Your Initialization Process
更新你的初始化進(jìn)程
在前面的三個步驟之后,你可能想知道central and peripheral manager的初始化進(jìn)程和媳。雖然這是一個可選步驟格遭,但如果想讓你的應(yīng)用跑起來更流暢,這可是很重要的留瞳。假設(shè)應(yīng)用在檢索peripheral的服務(wù)時被終止拒迅。當(dāng)應(yīng)用還原后,它不知道這個過程到底進(jìn)行到哪一步了。你也想知道從哪一步繼續(xù)璧微。
舉例作箍,當(dāng)在centralManagerDidUpdateState:
方法中初始化你的應(yīng)用時,你可以查到在應(yīng)用被終止時你是否成功發(fā)現(xiàn)被還原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]]; ...
如上胞得,如果系統(tǒng)在應(yīng)用發(fā)現(xiàn)service之前終止它,那么開始搜索peripheral的數(shù)據(jù)屹电,使用discoverServices:搜索阶剑。如果應(yīng)用在被終止前已搜索到service,那么你需要檢查時候搜索到你要的characteristics危号,(如果有訂閱牧愁,也檢查是否已訂閱)。通過檢查初始化過程外莲,可以確保在這時調(diào)用到最合適的方法猪半。