美文网首页iOS网络部分第三方工具类
iOS断点续传和后台下载(基于AFNetworking)

iOS断点续传和后台下载(基于AFNetworking)

作者: 空空小僧 | 来源:发表于2017-08-30 18:21 被阅读2542次

    先说说断点续传 :

    最近重构公司代码,公司需要做文件的断点续传,看了下之前的代码和网上的代码,大家还有好多是使用的NSURLConnection,


    image.png

    ,一点一点的拼接data,然后断开连接,再次连接的时候,将本地的data的长度,塞到请求头里面设置range
    [request setValue:rangeString forHTTPHeaderField:@"Range"];
    这种的,但是我们的网络请求是封装的AFNetworking的,也发现AFNetworking也有NSURLSessionDownLoadTask,我们就拿过来接着就用了,其实AFNetworking也支持断点续传,而且支持的我感觉还是很完美的.

    首先,我们创建一个管理下载的manager及下载的配置,注意那个后台任务的backgroundSessionConfigurationWithIdentifier是要确定的,要后台下载的时候使用

    image.png image.png

    注意代码中的一个AF的通知监听,特别重要,后台下载的回调及下载成功失败的回调,都是在这个通知里面(其实是AFNetworking封装了,把回调信息都是通过通知传递的,在这里真的佩服AFNetworking作者,把通知用的这么出神入化,我是在这里重新对通知的认知提高了一个大的阶段,这里只是上了一点发送通知的地方,通知的userInfo带了很多东西,详细的大家可以看下AF的源码)

    AFURLSessionManager开始一个下载的时候,有两个方法,分别是开始下载(重头下载),继续下载(需要传入一个resumeData)


    image.png

    看方法名,作者就给我们做了断点续传的功能

    介绍完这两个方法名,我们介绍下第一个方法是怎么使用,和第二个是什么使用的,并且resumeData是在哪里获取的

    1.当我们需要下载的时候,主动去调用downloadTaskWithRequest方法,根据下载地址url,去判断本地是否有resumeData,这个类似SDWebImage的实现,我们自己去维护这个对应关系,可以存到本地一个plist文件里面,键值对对应 url:resumeData ,

    1. 开始下载的时候,去判断当前是否存在这个url:resumeData,存在的话,看一下长度是否大于零(当用户开始下载的时候,如果什么都没下载到,就中断下载,resumeData是nil,如果直接写入plist是会崩溃的,我们可以写一个空字符串,虽然不是一个类型,但是length都可以使用,不会太影响),大于零,就使用resumeData调用downloadTaskWithResumeData这个方法,然后去开始我们的任务
    image.png

    上面是两个基本的方法介绍,这里介绍一下那个ResumeData在哪里获取,什么时候获取,
    还是上面提到的那个通知 (是在NSURLSessionTaskDelegate 这个协议里面的- (void)URLSession:(__unused NSURLSession *)session
    task:(NSURLSessionTask *)task
    didCompleteWithError:(NSError *)error 这个方法发出了的,其实downLoadTask的成功,失败,中断都会调用这个方法),所以,我们需要去刚刚那个通知里面去看看到底都传过来什么.

    image.png

    拿到了这个ResumeData,大家就可以区分使用什么时候开始断点续传,什么时候重新下载了

    大家可以主动去将task 提前结束来触发那个通知,一般不允许蜂窝下载的时候,会用到这个方法

    image.png

    后台下载 :

    后台下载呢,其实上面初始化那个manger的时候,配置那个后台配置的时候,已经实现了后台下载的过程,你可以尝试下,你调回前台,你的下载也在继续,只是这个时候,你的session被操作系统接过去了,操作系统去管理了,一旦你下载完成,会通知你(如果你的app还活着的时候),那么你的app死了的时候怎么办呢,操作系统会给你留着,持有者,等你的app再次复活的时候,并且再次创建NSURLSessionConfiguration,有后台任务,并且后台的backgroundSessionConfigurationWithIdentifier一致的话,操作系统会去调用你的原来的NSURLSessionTaskDelegate代理中的task的didCompleteWithError的方法,由于我们的使用的是AF封装的,所以那个代理被AF接到并且通过通知处理了,所以还是会在我们之前监听的那个通知里面,和我们app活着的时候一样一样的,去发送那个AFNetworkingTaskDidCompleteNotification的通知,在这里 我们原来的处理逻辑不需要改变,

    上面讲的是我们进入后台,app慢慢的被系统 杀死 或者没杀死的时候,那么,如果我正在下载着,app崩溃,或者被用户手动强退怎么办? 经过验证,其实是一样的,出现这个情况后,操作系统监听到被杀死或者被中断,也会帮我们持有这个session,然后把崩溃的一瞬间的ResumeData存着,等待我们再次创建相同后缀的session,那时候在调用回调---->af再发通知---->我们再存起来.


    image.png

    讲了这么多,大家是不是特别好奇,这个resumeData到底是什么?
    其实resumeData是一个data类型,大家可以转成字符串,看一下里面的内容
    他的本质是一个xml文件
    AF在下载的时候(其实是调用的系统的下载方法),会将文件先下载到沙盒目录下的temp文件夹中,生成一个后缀为tmp的文件,等我们下载完的时候,会将文件处理,然后移动到我们下载时设置的路径下,这样,我们的下载任务就完成了,

    image.png
    在上面的xml文件中,大家可以看到下载的url,当前接受的文件大小,第几次下载,还有临时文件名等信息,其实本质还是万变不离其宗,但是感觉这样用起来挺好的,既然用了AF了,就用到底吧,这样 ,我们基本的断点续传和后台下载是说完了,有错误希望大家指出,共同进步,谢谢
    对了,参考过一个同学关于后台下载的讲解,大家可以看一下
    参考文章 http://www.jianshu.com/p/1211cf99dfc3
    附带个人的demo地址 : https://github.com/yangfangkuo/downLoadTest/tree/master
    对大家致敬,感谢

    相关文章

      网友评论

      • PGOne爱吃饺子:楼主你的这个demo支持后台下载和断点下载么
        PGOne爱吃饺子:@空空小僧 你看一下你的这个demo,退到后台就不走了,应用杀死之后,即使已经下载过了,还是从头开始下载的。。。。
        空空小僧:@PGOne爱吃饺子 我不想回答你,
      • PGOne爱吃饺子:大佬,你的这个后台下载,是应用程序退到后台的时候还在下载么,苹果不是规定,应用退到后台的时候不能在执行代码了么??求教
        空空小僧:@PGOne爱吃饺子 自己去看资料吧,这个session的名字就是backgroundsession
        PGOne爱吃饺子:音乐 地图定位 这两个我知道,你的后台下载应该不可以吧
        空空小僧:@PGOne爱吃饺子 这个是在苹果的允许之内的 是有几类后台任务允许的
      • 亦有时:你好作者,你的demo现在有这个问题:暂停后,再点击下载,就会重新开始下载。开始下载,退出程序,再重新打开程序,也是重新开始下载。
        看了一下,暂停下载的时候,QDNetServerDownLoadTool的这个方法里- (void)downLoadData:(NSNotification *)notification,获取到的urlHost不是我原来的资源链接
        空空小僧:去看你们的服务器 是否支持断点续传 服务器支持断点续传是我们的代码的前提,你可以在那个通知里面 看一个那个续传使用的data是否有值,有值,说明你们的服务器支持断点续传,默认nginx的服务器是支持的,然后你看响应头里面是否有E-Tag或者last-modify参数,以及一个参数 值为byte的属性
      • 空空小僧:demo中资源出现问题 自己换一个可使用的资源吧
        空空小僧:@PGOne爱吃饺子 好的 谢谢
        PGOne爱吃饺子:我找到了一个 你放到你的demo里面吧,省的别人再找了 https://www.apple.com/105/media/cn/iphone-x/2017/01df5b43-28e4-4848-bf20-490c34a926a7/films/feature/iphone-x-feature-cn-20170912_1280x720h.mp4
        PGOne爱吃饺子:能不能提供一个可使用的资源啊,你的那个资源好像不能用了啊
      • xiari1991:作者有没有遇到过这种问题:开始下载,退出程序,再重新打开程序,通知并没有收到,所以当点击开始下载的时候,又重新开始下载了。
        空空小僧:@yf_js 你试试我写的那个demo是否可以收到回调,如果一样收不到回调,再反馈一下,我去看看,我印象中是可以收到的
        xiari1991:@空空小僧 我已经初始化了。不过还是会收不到:sweat:
        空空小僧:@yf_js 之所以收不到,是因为我们需要在app启动的时候,就去创建这个manager ,而且应该不可能收不到,如果manager 的后缀一致的话,当你创建这个manager 的时候,他的回调就会过来了,你可以试试,在app启动的时候,就初始化那个单例
      • 爱勤海之旅:楼主,你这domo断点续传有问题啊,我点几次暂停之后,下载下来的视频就不能看看,而且下载进度也跳跃式增加。
        爱勤海之旅:@空空小僧 不是的,楼主,你可以等他下载到一半左右,然后点击暂停再点继续,就这样快速的多点几次,你就知道了!
        空空小僧:我测试了一下 ,我的这个demo的正常使用逻辑是 开始下载--暂停下载--继续下载(或者开始下载),而不是你操作的那种,开始下载---开始下载,这样其实是回走2个下载任务,第一个由于没有暂停,所以再次下载的时候,不会有续传,而是又开始了一个新的下载任务,只是这两个进度都是操作的一个progressView,所以会乱,
        空空小僧:@爱勤海之旅 不是吧,那是你连续点击了2次吧,然后其实起了两个下载任务,你再试试
      • 巴赫海兹:有demo吗?能否发一份
        空空小僧:已经更新了 下载地址 https://github.com/yangfangkuo/downLoadTest/tree/master
        巴赫海兹:@空空小僧 好的,谢谢,310346124@qq.com
        空空小僧:我去给你简单的写一个吧

      本文标题:iOS断点续传和后台下载(基于AFNetworking)

      本文链接:https://www.haomeiwen.com/subject/shdxjxtx.html