IOS,单文件,断点下载,退出app再进入还可以继续下载

来源:互联网 发布:网络销售前景 编辑:程序博客网 时间:2024/05/01 12:57

更新2016_11_1

以下Demo是存在问题的,不过不是代码问题,而是下载功能不能放在ViewController中,我的处理方法是单独建立了一个单例模式的类来控制下载过程,这样保证了后台下载的功能。

不过还是有很严重的问题:网上大多都说使用cancelByProducingResumeData方法来缓存,在IOS9中是可以的,但是因为项目需求,测试了IOS7和IOS10,在这两个版本上都是无法缓存的,再次下载时会重新下载,我之前试着打印过resumeData,发现在IOS9中打印是完整的,可是IOS7和IOS10中打印只能打印一部分,导致resumeData无法使用,我至今没发现有大神提过这个问题。

我后来是用的暂停来处理的,因为使用一个单例类来下载,就不存在暂停后销毁downloadTask和session的问题,所以直接用暂停/继续就可以了,不需要缓存,但是如果关闭手机,或者强行退出app,就会重新下载,实际上并没有实现缓存的功能,因为app赶时间,这个下载功能只是很小的一部分,所以我当时只能那样处理,如果用户强行关闭app或者断网,就必须重新下载,总之,我得到一个结论,这种简单的NSURLSession下载方式依然无法解决所谓的断点下载的问题。

————————————————————————————————————————————————————————

最近被这个功能搞死了,先是找各种框架,最初用的AFNetworking然后尝试ASIHttp,都以失败告终,网上有很多教程之类的,不是代码繁琐就是没点逻辑,感觉都是复制粘贴党,因为项目急,真是弄的我好烦,好不容易找到一片不错的,介绍的也很简单,不过也多亏了那一篇文章让我知道了两个关键的类NSURLSessionDownloadTask和NSURLSession

我这里只贴关键代码和思路,因为各个项目需求不同,其实很简单,就几行代码

一。申明变量,第一个是显示进度文字,第二个是进度条,第三四个变量是控制下载的

@property (weak, nonatomic) IBOutlet UILabel *progress;@property (weak, nonatomic) IBOutlet UIProgressView *progressBar;@property(nonatomic,strong)NSURLSessionDownloadTask *downloadTask;@property(nonatomic,strong)NSURLSession *session;
二。下载的方法,这里请记住一个重要参数,resumeData,我把它存入了userdefault中,这是断点下载的关键,这个方法传入字符串urlString就行了,就是你的文件所在地址:比如http://xxx.xxx.xx/xxx.zip这种就行了,下载的时候判断userDefault中的resumeData是否存在,如果存在就使用downloadTaskWithResumeData的方法来下载(可以理解为从中途开始下载),如果为nil,那么就新建一个下载

#pragma mark - 下载-(void)downloadWithUrl:(NSString*)urlString{    NSURL* url = [NSURL URLWithString:urlString];    // 得到session对象    NSURLSessionConfiguration* cfg = [NSURLSessionConfiguration defaultSessionConfiguration]; // 默认配置    self.session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSOperationQueue mainQueue]];    // 创建任务    //获取上一次下载的地方    NSData *resumeData=[[NSUserDefaults standardUserDefaults] valueForKey:@"resumeData"];    if(resumeData!=nil){        self.downloadTask=[self.session downloadTaskWithResumeData:resumeData];    }else{        self.downloadTask = [self.session downloadTaskWithURL:url];    }    // 开始任务    [self.downloadTask resume];}


三。实现代理,这里忘了说了,要让你的viewcontroller实现NSURLSessionDownloadDelegate,这个代理主要监听两个方法,第一个是下载进度的监听,在里面更新进度条和文字,第二个是下载结束后的监听,注意:下载结束后把userDefault中的resumeData置为nil,主要是防止如果你删除了这个文件,下次重新下载如果不为nil,他会继续从resumeData的位置开始下载,此时resumeData记录的位置已经是100%了,那么他根本就不会下载了

/** *  每次写入沙盒完毕调用 *  在这里面监听下载进度,totalBytesWritten/totalBytesExpectedToWrite * *  @param bytesWritten              这次写入的大小 *  @param totalBytesWritten         已经写入沙盒的大小 *  @param totalBytesExpectedToWrite 文件总大小 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{    float progressF=(float)totalBytesWritten/(float)totalBytesExpectedToWrite;    self.progress.text=[NSString stringWithFormat:@"已下载%d%",(int)(progressF*100)];    [self.progressBar setProgress:progressF];}/** *  下载完毕时调用 * *  @param location 下载后的地址 */- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTaskdidFinishDownloadingToURL:(NSURL *)location{ //做你要做的事情    [[NSUserDefaults standardUserDefaults] setObject:nil forKey:@"resumeData"];}

四。取消下载,这里最关键了!首先我点击取消下载按钮进入这个方法,直接dismiss这个界面,那些什么downloadtask之类的东西就都没了,网上那些暂停继续又没退出界面能称之为断点下载吗??咳咳吐个槽,实在被搞得很烦。注意了,cancelByProducingResumeData这个方法很重要,这个block中又一个resumeData,你可以理解为它就是记录当前下载到的位置的指针,既然有了下载位置,那就简单了,把它存入userdefault中,下载下载直接取出来,然后接着下载就行了啊,看到这里,你可以在往回看一看,应该就能明白了

- (IBAction)pauseDl:(UIButton *)sender {    [self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {        NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];        [userDefault setObject:resumeData forKey:@"resumeData"];        [userDefault synchronize];        self.downloadTask = nil;    }];    [self dismissViewControllerAnimated:NO completion:nil];}





0 0