關於iOS的後臺下載和斷點續傳,說一說自己的理解
http://blog.csdn.net/openglnewbee/article/details/53887308
首先,後臺下載和斷點續傳是兩件事;這裡放在一起說是為了圖個方便,實際二者在技術實現上沒有什麼關聯。
目前我們的下載實現一般都是基於nsurlsession和iOS7+的,所以我們這裡不考慮iOS6和以前的老系統,主要技術實現也是基於nsurlsession.
先說後臺下載:
1. 在沒有特別關注的情況下,可能很多開發者使用afnetworking下載的姿勢並沒有考慮到後臺下載這一塊。在預設情況(不做特別設定)下,afnetworking並未啟用backgroundsession, 因此很可能你的app是不支援後臺下載的。
2. nsurlsession對後臺下載的支援主要通過 backgroundSessionConfiguration/backgroundSessionConfigurationWithIdentifier 型別的session來支援;通過該session來呼叫下載方法,實現幾個下載相關的回撥方法,也就可以實現基本的目的:應用切換到後臺時仍然在下載(但下載完成後得不到回撥和提醒)。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location;
@optional
/* Sent periodically to notify the delegate of download progress. */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
/* Sent when a download has been resumed. If a download failed with an
* error, the -userInfo dictionary of the error will contain an
* NSURLSessionDownloadTaskResumeData key, whose value is the resume
* data.
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes;
3. 如果需要下載完成後得到回撥和提醒,或者更高階一點(應用程式被系統幹掉等情況,還能夠通過下載任務拉起併發送回調和提醒,而且系統在後臺會生成一個快照,按home鍵檢視時就彷彿這個應用被啟動過一樣。這裡的內容是根據蘋果官方答覆和相關文件得到,系統幹掉的場景筆者並未模擬),我們就需要進行額外的設定了。
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
// 這裡返回了session的identifier和completionBlock;其中的identifier可以用於匹配session,而completionBlock我們需要儲存起來,到後面一個步驟需要呼叫之。
}
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
// 這裡需要執行上一步儲存的completionBlock:
根據蘋果員工的回覆,這裡蘋果需要用這個block實現兩個功能:
a. 系統後臺生成快照
b. 釋放阻止應用掛起的斷言(讓應用繼續在後臺執行,節約系統資源)
-
The system does two things in that completion handler:
-
It snapshots your UI for the benefit of the multitasking switcher
-
It releases the assertion that was preventing your app from being suspended
-
https://forums.developer.apple.com/thread/69825
}
在一次後臺下載中方法的執行時序為:a.handleEventsForBackgroundURLSession ->b. URLSession: downloadTask: didFinishDownloadingToURL->c. URLSessionDidFinishEventsForBackgroundURLSession.
建議傳送本地通知的動作統一放在b中,目前看放在a和c中應該也是可以的。
再來說一說斷點續傳:
1. 從協議層面來說,斷點續傳的實現都是通過http頭裡面的range來實現的。對於以前asi的實現和基於nsurlconnection的實現來說,我們都是通過手動儲存當前大小然後填充到range的策略來實現斷點續傳功能的。
2. nsurlsession內建了對於斷點續傳的api支援,主要是通過resumedata和tmp中間檔案。在nsurlsession暫停時,其中間檔案的相關資訊被儲存到resumedata,我們只要通過這個resumedata,即可從之前的下載進度中恢復。也就是說1中的細節被封裝在api內部了。
目前來看,基於nsurlsession的斷點續傳主要有兩個問題需要考慮:
a. 程式退出(手動kill等)時需要自動儲存resumedata,後續應用起來時再恢復之。
b. iOS10裡面的resumedata的儲存有點問題,需要特別處理,可以參考此demo:https://github.com/HustHank/BackgroundDownloadDemo.
其他細節暫時不再展開了,後面有機會再深入的說一說,大體方案就是這樣,大家可以儘量參考蘋果官方文件。
一些參考文件:
https://my.oschina.net/iOSliuhui/blog/469276 斷點下載流程講解
http://www.cocoachina.com/ios/20160503/16053.html 斷點續傳方案 ??? 不斷儲存?方案不可取! 程式被殺時主動儲存!這裡的ios應該為小寫,被自動格式化成大寫了
https://code.tutsplus.com/tutorials/ios-7-sdk-background-transfer-service--mobile-20595 後臺傳輸服務
http://www.jianshu.com/p/1211cf99dfc3 下載相關,BackgroundDownloadDemo作者的分享
蘋果論壇相關討論
https://forums.developer.apple.com/thread/14854
https://forums.developer.apple.com/thread/69825