关于iOS的后台下载和断点续传,说一说自己的理解

首先,后台下载和断点续传是两件事;这里放在一起说是为了图个方便,实际二者在技术实现上没有什么关联。

目前我们的下载实现一般都是基于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. 释放阻止应用挂起的断言(让应用继续在后台运行,节约系统资源)

  1. 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





上一篇:后台(34)——MyBatis概述


下一篇:Python 的 Lambda 函数怎么用?