我們知道iOS開啟背景工作後可以獲得最多600秒的執行時間,而一些需要在後台下載或者與伺服器保持串連的App是如何突破600秒的限制的呢?像網易公開課就可以在後台持續下載,優酷也可以在後台持續緩衝,這是怎麼做到的呢?一般來說,要實現iOS長時間後台運行,需要聲明VOIP、Audio或GPS。 Audiosession 實現方法很簡單,就是在後台一直播放一個無聲的音樂檔案,這樣就相當於聲明了Audio,就可以輕鬆突破600秒的限制了。 通過播放“靜默”音讓程式在後台執行的做法(即在audiounit回呼函數中使用kAudioUnitRenderAction_OutputIsSilence標誌位),雖然確實可以實現後台執行,但實踐中限制很多。最大的問題就在於程式的audiosession不能被打斷。當程式執行在後台時,只要另一個程式使用kAudioSessionCategory_RecordAndPlay(比如Skype)或者kAudioSessionCategory_SoloAmbientSound(印象中使用這個session的不多),那麼本程式就會被立即打斷。 打斷本身不是問題,但當播放程式被打斷時,唯一能夠獲得的只有處理audiosessioninterruption的很短一段時間。我的實驗測試大概是3到5秒,但因為程式隨後立即暫停,無法掛調試器,所以很難準確估計,然後程式就會被立即轉入休眠狀態。這點時間和applicationDidEnterBackground回呼函數所用的時間大體相當,但是因為這個打斷中間還伴隨一個播音的回調動作,程式結構不是很好組織,在很多情況下是不夠做現場儲存工作的。 不推薦播放“靜默”音的另一個問題它的恢複播放需要的情境非常麻煩。比如當一個iOS程式在後台被VOIP喚醒時,它是不能直接獲得audiounit重新開始播音的。如果此時調用AudioOutputUnitStart(),會返回一個錯誤碼,哪怕前台沒有任何一個程式在運行也是如此。此時你不可能讓程式重新進入穩定運行狀態。有些沒經驗的程式員喜歡利用audiosessioninterruptionhandler做所謂的自動播放恢複,但他們其實都沒有注意到audiosessioninterruption的狀態恢複回調並不會保證被調用。目前實測能自動回復調用的,大概也就只有內建的電話撥號程式,以及一些非常特殊的情境(比如你用一個MP3播放器打斷audiosession,然後殺掉MP3播放器進程,然後把被打斷的程式重新置回前台)。這樣經常導致的結果,就是你開心地發現程式沒問題,然後在放進生產環境中發現各種時不時的崩潰或啟動失敗。 VOIPsocket VOIPSocket可以在後台運行。當程式進入後台時,事實上整個程式被暫停運行,但VOIPsocket因為受系統控制而不在此列。我的觀察是,每次有新的資料來臨時,程式會被喚醒並執行大約幾秒鐘,然後再次進入休眠。Stackoverflow上的說法是10秒鐘,但我不確定,可能是我的實驗不夠精確。 參考資料:知乎 StackOverFlow AppleDevCenter
http://www.cocoachina.com/applenews/devnews/2012/1212/5313.html