當(dāng)在后臺時引起用戶注意
通知是一種應(yīng)用被掛起、或在后臺運行、或沒有運行的情況下引起用戶注意的方式。應(yīng)用可以使用本地通知來顯示警告、播放聲音、印章化應(yīng)用的圖標、或者三者的組合。例如,一個鬧鐘應(yīng)用可以使用本地通知來播放鬧鐘聲音并顯示一個警告來關(guān)掉鬧鐘。當(dāng)一個通知被傳遞給用戶的時候,用戶必須根據(jù)信息決定是否讓應(yīng)用回到前臺。(如果應(yīng)用已經(jīng)運行在前臺,本地通知只會安靜的傳遞給應(yīng)用而不會顯示給用戶。)
為了安排本地通知的傳遞,創(chuàng)建一個UILocalNotification類的實例,配置通知參數(shù),并使用UIApplication類的方法來安排它。本地通知對象包含關(guān)于用來傳遞的通知類型(聲音、警告、或者徽章)的信息以及發(fā)送它的時間(當(dāng)合適時)。UIApplication類的方法為立刻或在安排的時間傳遞通知提供了選項。
代碼清單3-2顯示了一個使用用戶設(shè)定的日期和時間安排一個單次警告的例子。這個例子只配置了一次警告,并在安排一個新的警告之前取消了之前的警告。(你自己的應(yīng)用可以在任何時刻有不超過128個的本地通知,其中任何一個都可以配置為以指定間隔重復(fù)。)警告本身由一個警告框和一個聲音文件組成;當(dāng)警告觸發(fā)時,如果應(yīng)用在不運行或者在后臺運行的時候,聲音文件會播放。如果應(yīng)用正處于活動狀態(tài),因此正在前臺運行,作為替代,應(yīng)用委托的application:didReceiveLocalNotification:方法被調(diào)用
代碼清單3-2 安排警告通知
- (void)scheduleAlarmForDate:(NSDate*)theDate
{
UIApplication* app = [UIApplication sharedApplication];
NSArray* oldNotifications = [app scheduledLocalNotifications];
// Clear out the old notification before scheduling a new one.
if ([oldNotifications count] > 0)
[app cancelAllLocalNotifications];
// Create a new notification.
UILocalNotification* alarm = [[UILocalNotification alloc] init];
if (alarm)
{
alarm.fireDate = theDate;
alarm.timeZone = [NSTimeZone defaultTimeZone];
alarm.repeatInterval = 0;
alarm.soundName = @"alarmsound.caf";
alarm.alertBody = @"Time to wake up!";
[app scheduleLocalNotification:alarm];
}
}
用于本地通知的聲音文件和用于推送通知的聲音文件具有相同的要求。自定義的聲音文件必須被放置在應(yīng)用的主束中,并且支持下面格式中的一種:Linear PCM, MA4, μ-Law, 或 a-Law。你也可以指定UILocalNotificationDefaultSoundName常量來為設(shè)備播放默認的聲音。當(dāng)這個通知被發(fā)送且聲音被播放時,系統(tǒng)也會在支持震動的設(shè)備上觸發(fā)震動。
你可以使用UIApplication類的方法來取消安排通知,或者得到通知的列表。更多關(guān)于這些方法的信息,參見UIApplication Class Reference。關(guān)于配置本地通知的額外信息,參見Local and Remote Notification Programming Guide。
理解你的應(yīng)用何時在后臺啟動
支持后臺執(zhí)行的應(yīng)用可以通過系統(tǒng)重啟來處理傳入的事件。如果應(yīng)用由于除用戶強退之外的原因而被終止,系統(tǒng)會在下面這些事件發(fā)生的時候重啟應(yīng)用:
- 對于位置應(yīng)用:
- 系統(tǒng)接收到一個與應(yīng)用所配置的傳送標準匹配的位置更新。
- 設(shè)備進入或退出一個注冊區(qū)域。(區(qū)域可以是地理區(qū)域或iBeacon區(qū)域。)
- 對于音頻應(yīng)用,音頻框架需要應(yīng)用來處理一些數(shù)據(jù)。(音頻應(yīng)用包括那些播放或使用麥克風(fēng)的應(yīng)用。)
- 對于藍牙應(yīng)用:
- 應(yīng)用扮演從連接的外設(shè)獲取數(shù)據(jù)的中心角色。
- 應(yīng)用扮演從連接中心獲取命令的外設(shè)角色。
- 對于后臺下載應(yīng)用:
- 應(yīng)用的推送通知到達,它的通知內(nèi)容包含值為1的content-available鍵。
- 系統(tǒng)在有機會的時刻喚醒應(yīng)用來開始下載新內(nèi)容。
- 對于使用NSURLSession類在后臺下載內(nèi)容的應(yīng)用,所有與會話對象關(guān)聯(lián)的任務(wù)都成功完成或接收到一個錯誤。
- Newsstand應(yīng)用啟動的下載任務(wù)完成。
在大多數(shù)情況下,系統(tǒng)會不在用戶強退應(yīng)用后重啟應(yīng)用。一個例外是位置應(yīng)用,在iOS 8及更新的版本中,它能在用戶強退之后被重啟。然而在其它情況下,用戶必須明確啟動應(yīng)用或在應(yīng)用能被系統(tǒng)從后臺自動啟動之前重啟設(shè)備。當(dāng)設(shè)備啟用密碼保護時,系統(tǒng)在用戶首次解鎖設(shè)備之前無法從后臺啟動應(yīng)用。
做一個負責(zé)任的后臺應(yīng)用
在使用系統(tǒng)資源和硬件時,前臺應(yīng)用總是優(yōu)先于后臺應(yīng)用。運行在后臺的應(yīng)用需要為這種差異做好準備,并在它們運行在后臺的時候調(diào)整其行為。具體來說,應(yīng)用在進入到后臺的時候應(yīng)該遵循下面的指導(dǎo):
- 不要從代碼進行任何OpenGL ES的調(diào)用。當(dāng)運行在后臺的時候,你不能創(chuàng)建EAGLContext對象或者發(fā)出任何OpenGL ES繪圖命令。使用這些調(diào)用會導(dǎo)致應(yīng)用被立刻殺死。應(yīng)用還必須確保任何之前提交的命令在進入后臺之前都已完成。關(guān)于如何在進入或移出后臺的時候處理OpenGL ES的信息,參見 OpenGL ES Programming Guide中的Implementing a Multitasking-aware OpenGL ES Application。
- 在被掛起前取消所有Bonjour相關(guān)的服務(wù)。當(dāng)應(yīng)用進入后臺,并在被掛起前,它應(yīng)該從Bonjour注銷,并關(guān)閉任何與網(wǎng)絡(luò)服務(wù)相關(guān)的socket監(jiān)聽。掛起的應(yīng)用不能響應(yīng)任何傳入的服務(wù)請求。關(guān)閉這些服務(wù)保護它們在其事實上不可用的時候被顯示為可用。如果你沒有關(guān)閉Bonjour服務(wù),系統(tǒng)會在應(yīng)用被掛起的時候自動關(guān)閉這些服務(wù)。
- 在基于網(wǎng)絡(luò)socket中為處理連接失敗做好準備。系統(tǒng)會在應(yīng)用被各種原因掛起的時候拆除socket連接。只要你的基于socket的代碼為其他網(wǎng)絡(luò)失敗的類型做好了準備,例如信號丟失或者網(wǎng)絡(luò)轉(zhuǎn)換,則不會導(dǎo)致任何異常問題。當(dāng)應(yīng)用恢復(fù)時,如果在使用socket的時候遇到故障,值需要重新建立連鍵即可。
- 在進入后臺之前保存應(yīng)用的狀態(tài)。在低內(nèi)存條件下,后臺應(yīng)用可以被從內(nèi)存清除以釋放更多空間。掛起的應(yīng)用首先會被清除,而且在被清除之前不會有任何通知。因此,應(yīng)用應(yīng)該利用iOS 6及更高版本的狀態(tài)保存機制來保存它們的界面狀態(tài)到磁盤。關(guān)于如何支持這個功能的信息,參見Preserving Your App’s Visual Appearance Across Launches。
- 在進入后臺的時候移除不必要對象的強引用。如果應(yīng)用維持一個占用大量內(nèi)存的對象(特別是圖片)的緩存,那就在進入后臺的時候移除所有值像這些緩存的強引用。更多信息,參見Reduce Your Memory Footprint。
- 在被掛起之前停止使用共享系統(tǒng)資源。與共享系統(tǒng)資源,例如地址簿或日歷數(shù)據(jù)庫,進行交互的應(yīng)用,應(yīng)該在被掛起之前停止使用這些資源。這些資源總是優(yōu)先提供給前臺應(yīng)用。當(dāng)應(yīng)用被掛起時,如果它被發(fā)現(xiàn)正在使用共享資源,應(yīng)用會被殺死。
- 避免更新你的窗口和視圖。因為當(dāng)應(yīng)用在后臺的時候,它的窗口可視圖不可見,所以你應(yīng)該避免更新它們。只有在你獲取應(yīng)用快照之前需更更新窗口內(nèi)容的情況下才可以例外。
- 響應(yīng)連接或斷開外部配件的通知。與外部配件連接的應(yīng)用,系統(tǒng)會在應(yīng)用進入后臺的時候自動發(fā)送一個斷開連接通知。該應(yīng)用必須注冊這個通知,以便用它來關(guān)閉當(dāng)前的配件會話。當(dāng)應(yīng)用返回到前臺的時候,一個匹配的連接通知會被發(fā)送,給應(yīng)用一個機會來重新連接。更多處理配件連接和斷開通知的信息,參見External Accessory Programming Topics。
- 當(dāng)進入后臺的時候清除活動警告的資源。為了在應(yīng)用之間切換的時候保護內(nèi)容,系統(tǒng)不會在應(yīng)用進入后臺的時候自動關(guān)閉操作表單(UIActionSheet)或警告視圖(UIAlertView)。在進入后臺之前,由你提供適當(dāng)?shù)厍謇硇袨?。例如,你可能想通過編碼的方式取消活動表單或者警告視圖,或者保存足夠的上下文信息以便稍后恢復(fù)視圖(在應(yīng)用程序被終止的情況下)。
- 在進入后臺之前,刪除視圖上的敏感信息。當(dāng)應(yīng)用轉(zhuǎn)換到后臺,系統(tǒng)得到應(yīng)用主窗口的一張快照,然后應(yīng)用轉(zhuǎn)換回到前臺的時候快照會短暫顯示。在從applicationDidEnterBackground:方法返回之前,你應(yīng)該隱藏或者遮擋密碼以及其它可能被快照捕獲的敏感的個人信息。
- 在后臺運行的時候盡可能少做事。給予后臺應(yīng)用的執(zhí)行時間比器前臺應(yīng)用要受到更多的限制。在后臺花費很多時間運行的應(yīng)用可能會被系統(tǒng)限制或終止。
如果你正在后臺執(zhí)行一個音頻應(yīng)用,或者允許在后臺運行的其他類型應(yīng)用,應(yīng)用可以照常的響應(yīng)傳入消息。換句話說,系統(tǒng)可能會在發(fā)生低內(nèi)存警告的時候通知應(yīng)用。在這種情況下系統(tǒng)需要終止應(yīng)用來釋放更多的內(nèi)存,該應(yīng)用會調(diào)用它的applicationWillTerminate:委托方法來執(zhí)行退出前的最后任務(wù)。
選擇不在后臺執(zhí)行
如果你不想讓應(yīng)用在后臺執(zhí)行,你可以通過將UIApplicationExitsOnSuspend鍵(值為YES)添加到在Info.plist 文件來明確的選擇不進入后臺。當(dāng)應(yīng)用選擇不進入時,應(yīng)用會在不運行、非活動、以及活動狀態(tài)之間循環(huán),而不會進入到后臺或者掛起狀態(tài)。當(dāng)應(yīng)用按下Home按鈕退出應(yīng)用的時候,applicationWillTerminate:方法會被調(diào)用,并且在應(yīng)用終止并進入不運行狀態(tài)之前,有大約5秒鐘的時間來清理及退出。
強烈不推薦選擇不進入后臺執(zhí)行,但是在某些特定情況下可能是首選。具體來說,如果為后臺執(zhí)行的編碼增加了應(yīng)用很大的復(fù)雜性,終止應(yīng)用或許是一個更簡便的方案。此外,如果你的應(yīng)用消耗大量的內(nèi)存并且無法輕松釋放它,系統(tǒng)會迅速的殺死你的應(yīng)用來為其他應(yīng)用騰出空間。因此,選擇終止,而不是切換到后臺,可能會產(chǎn)生相同的結(jié)果,并節(jié)省開發(fā)的時間和精力。
更過關(guān)于能包含到Info.plist文件中的鍵的信息,參見Information Property List Key Reference。
(本節(jié)結(jié)束)