轉載出處: http://www.lxweimin.com/p/d3e279de2e32
iOS 后臺運行的規則
應用的運行狀態分為以下五種:
Not running:應用還沒有啟動,或者應用正在運行但是途中被系統停止。
Inactive:當前應用正在前臺運行,但是并不接收事件(當前或許正在執行其它代碼)。一般每當應用要從一個狀態切換到另一個不同的狀態時,中途過渡會短暫停留在此狀態。唯一在此狀態停留時間比較長的情況是:當用戶鎖屏時,或者系統提示用戶去響應某些(諸如電話來電、有未讀短信等)事件的時候。
Active:當前應用正在前臺運行,并且接收事件。這是應用正在前臺運行時所處的正常狀態
Suspended:應用處在后臺,并且已停止執行代碼。系統自動的將應用移入此狀態,且在此舉之前不會對應用做任何通知。當處在此狀態時,應用依然駐留內存但不執行任何程序代碼。當系統發生低內存告警時,系統將會將處于 Suspended 狀態的應用清除出內存以為正在前臺運行的應用提供足夠的內存。
Background:應用處在后臺,并且還在執行代碼。一般的應用,都只會在這個狀態短暫停留(最多十分鐘),然后就會被系統強制進入 Suspended 狀態。而 iOS 為了在某些情況下提供更好的體驗,提供了一些選項,只要滿足這些選項的條件,就可以在后臺運行很長的一段時間,下面我們將重點討論可以使應用在后臺長時間運行的方法。
iOS 應用狀態切換示意圖
iOS 提供的后臺運行方式
iOS 提供的后臺運行方式列表
上圖為iOS 提供的后臺運行方式列表,如果需要,可在 Xcode 的項目設置中開啟對應的選項。App Store 的審核人員會檢查應用中是否有必要開啟該后臺運行模式選項,如果應用中不需要,而又開啟了這個選項,可能會被拒。
Audio, AirPlay and Picture in Picture
此個選項包含四種場景,分別是:音頻的播放,錄音,AirPlay 及畫中畫的視頻播放。
音頻的播放:在播放音頻時,即使應用退到后臺,只要一直有音頻在播放,那應用就可以一直在后臺運行。
代碼實現可參考:http://www.linuxidc.com/Linux/2012-08/68364.htm
錄音:應用可以請求使用麥克風,而當開啟了此后臺選項,應用在使用麥克風的時候,即使退到后臺,也可以一直后臺運行,通過查看微信安裝包中的 plist 文件,微信的語音聊天,就是通過這種方式實現的。而當該類應用退到后臺后,iOS 系統的狀態欄會變成紅色,并在狀態欄中顯示正在使用麥克風的應用的名稱,如下圖所示。
正在使用麥克風提示
AirPlay:AirPlay 是指將 iOS 設備,或者 Mac 設備上的音視頻,同步到另一個設備中播放。舉兩個例子,第一個是把 iPhone 上的音樂通過藍牙的方式在汽車的藍牙音響播放,第二個是把 iPhone 上的視頻,同步到智能電視屏幕上播放。此功能一般用于多端及多屏的交互。
關于 AirPlay 的開發文檔:http://nto.github.io/AirPlay.html
畫中畫的視頻播放:畫中畫是 iPad 版本的 iOS 9 新增加的功能,可以在 iOS 的桌面,或者其他應用的界面的上面播放視頻,從而該視頻區域所屬的應用就可以后臺運行了。此功能現在只在 iPad 應用中提供。
代碼實現可參考:http://www.cocoachina.com/ios/20150714/12558.html
Location updates
一般用于導航應用中,開啟此選項后,應用退到后臺,還可以得到系統的定位更新,從而使得應用可以根據定位的變化做出不同的反應。
代碼實現可參考:https://github.com/voyage11/Location
Voice over IP
VOIP 類的應用允許用戶使用網絡而不是手機打電話,因此這一類的應用需要保持同它相關的服務的網絡連接,用以收到來電事件和其他數據。iOS 不是通過一直讓該應用處于激活狀態來達到這個目的,而是同樣也會將這類的應用掛起,但同時會在應用被掛起期間由系統接管它的 VOIP 的 Socket,當這個 Socket 有數據通信時,系統會再次喚醒處于掛起狀態的應用,同時將 Socket 的控制權交還給該應用,以讓其正常的處理來電事件和其他數據。
Newsstand downloads
在 iOS 開發中,有一類叫報刊雜志類應用比較特別,在 iOS 9 之前的系統中,此類應用會統一收在系統內置的「報刊雜志」應用中,在 iOS 9 中則去掉了內置的「報刊雜志」應用,此類應用得以以單獨的圖標入口出現在桌面中。
此后臺運行的選項就是提供給報刊雜志類應用可以在后臺下載及處理報刊雜志內容,而下載的過程需要使用 NewsstandKit 中的 NKAssetDownload 進行下載。需要注意的是,下載的過程中,應用可能還是會被掛起,甚至應用被退出,而 iOS 會在 Wi-Fi 環境下繼續下載,直到下載完成。而一旦下載完成,如果應用只是被掛起,則iOS 會喚醒對應的應用,回調對應的事件;如果應用已經退出,則會啟動應用,在啟動參數中會帶上對應的標識表示這次啟動是因為下載報刊雜志內容完成。
代碼實現可參考:http://www.viggiosoft.com/blog/blog/2011/10/17/ios-newsstand-tutorial/
External Accessory communication
此選項提供給一些 MFi 外設通過藍牙,或者 Lightning 接頭等方式與 iOS 設備連接,從而可在外設發送消息時,喚醒已經被掛起的應用。而一旦被喚醒,一般情況下, 應用只有最多 10 秒鐘的執行時間。
MFi 外設:是指通過蘋果 MFi 認證的設備,而 MFi 認證是對其授權配件廠商生產的外置配件的一種標識使用許可,是 Made for iOS 的英文縮寫。
Uses Bluetooth LE accessories
此選項與 External Accessory communication 類似,只是此選項無需限制 MFi 外設,而需要的是 Bluetooth LE 設備。
Acts as a Bluetooth LE accessory
此選項是指 iOS 設備作為一個藍牙外設連接時,對應的應用可以后臺運行,但是使用此模式需要用戶進行授權認證。
Background fetch
iOS 7 新增加的一個選項,用于即使在后臺,也需要頻繁更新數據的應用。例如一個 PM2.5 的應用,需要幾個小時更新一次數據,那么可以開啟此選項,設置一個時間間隔,從而讓 iOS 在間隔時間內在后臺啟動該應用,執行指定數據的獲取工作,而此過程最多只能執行 30 秒鐘。
代碼實現可參考:http://objccn.io/issue-5-5/
Remote notifications
iOS 7 新增加的一個選項,是一種靜默推送,它有別于一般的推送,應用收到此類推送后,不會有任何的界面提示,而當應用退出或者掛起時收到此類推送,iOS 也會啟動或者喚醒對應的應用。
例如一個閱讀應用,用戶訂閱的博客更新了,那么可以先發一個靜默推送,應用收到此種推送后,可以先把用戶訂閱的博客內容都下載好,再通知用戶,這樣用戶一打開應用就可以馬上開始閱讀。
收到靜默推送,會回調對應的回調方法,而此回調方法最多只能執行 30 秒鐘。
代碼實現可參考:http://objccn.io/issue-5-5/
基于 NSURLSession 的后臺傳輸
此為 iOS 7 新增加的特性,用于在后臺下載或者上傳大文件,步驟如下:創建后臺傳輸用的 NSURLSession 對象;向這個對象中加入對應的傳輸的 NSURLSessionTask,并開始傳輸;在實現 AppDelegate 里實現 -application:handleEventsForBackgroundURLSession:completionHandler: 方法,以刷新 UI 及通知系統傳輸結束。
一旦后臺傳輸的狀態發生變化(包括正常結束和失敗)的時候,應用將被喚醒并運行 AppDelegate 中的回調。
但是也有一些限制,后臺傳輸只會通過 Wi-Fi 來進行。后臺下載的時間與以前的關閉應用后X分鐘的模式不一樣,而是為了節省電力變為離散式的下載。
代碼實現可以參考:http://onevcat.com/2013/08/ios7-background-multitask/
其他后臺運行黑魔法
一直循環播放一段沒聲音的音頻
可以在后臺選項中選擇「Audio, AirPlay and Picture in Picture」,而開始循環播放一段是沒聲音的音頻,即在 Audio Unit 回調函數中使用 kAudioUnitRenderAction_OutputIsSilence 標志位,但是這種方式兩個大的缺點:
1. 蘋果的審核人員如果發現,會被拒;
2. 應用程序的 Audio Session 不能被打斷。當應用執行在后臺時,只要另一個應用使用 kAudioSessionCategory_RecordAndPlay (比如 Skype)或者 kAudioSessionCategory_SoloAmbientSound,那么該應用就會被立即打斷。
代碼實現可參考:https://github.com/marcop/MMPDeepSleepPreventer
越獄下開發 System 級別的應用
一般的應用都是 Mobile 級別的,在越獄的情況下,可以開發一個 System 級別的應用,從而使得應用不受 iOS 一般應用的限制,實現真正的后臺運行,但是缺點就是應用只能運行在越獄設備上,也不能上 App Store。