NSURLSession断点下载
#import <Foundation/Foundation.h> @class XHDownLoadManager; #pragma mark - delegate Method @protocol XHDownLoadManagerDelegate <NSObject> /** 下载失败*/ - (void)downLoadFailed:(XHDownLoadManager *)downLoadManager withError:(NSError *)error; /** 下载进度:0.00%*/ - (void)downLoad:(XHDownLoadManager *)downLoadManager withProgress:(float)progress; /** 下载完成进度:0/1*/ - (void)downLoadFinished:(XHDownLoadManager *)downLoadManager withFinishedCount:(NSInteger)finishedCount andTotalCount:(NSInteger)totalCount; @end #pragma mark - Object @interface XHDownLoadManager : NSObject /** documentName(要保存的文件夹的名字,不能为空)*/ @property (nonatomic, copy) NSString *documentName; /** delegate*/ @property (nonatomic, weak) id<XHDownLoadManagerDelegate> delegate; /** downLoadUrlStr*/ @property (nonatomic, copy) NSString *downLoadUrlStr; /** downLoadUrlStrArray*/ @property (nonatomic, copy) NSArray *downLoadUrlStrArray; /** 下载管理者*/ + (instancetype)downLoadManager; /** 下载文件*/ //单文件下载 - (void)downLoadFileWithUrlStr:(NSString *)urlStr; //数组下载 - (void)downLoadFilesWithUrlStrArray:(NSArray *)urlStrArray; /** 暂停下载*/ - (void)pauseDownLoad; /** 取消下载*/ - (void)cancleDownLoad; /** 恢复下载*/ - (void)resumeDownLoad; @end
#import "XHDownLoadManager.h" @interface XHDownLoadManager ()<NSURLSessionDelegate,NSURLSessionDownloadDelegate> { NSInteger _totalCount;//总任务数 NSInteger _finishedCount;//当前完成数 } //单任务使用 /** session*/ @property (nonatomic,strong) NSURLSession *downLoadSession; /** downLoadTask*/ @property (nonatomic,strong) NSURLSessionDownloadTask *downLoadTask; /** resumeData*/ @property (nonatomic,copy) NSData *resumeData; //多任务下载使用:暂不使用 /** downLoadTaskArray*/ @property (nonatomic,strong) NSMutableArray *downLoadTaskArray; /** resumeDataArray*/ @property (nonatomic,strong) NSMutableArray *resumeDataArray; @end @implementation XHDownLoadManager #pragma mark - LazyLoad - (NSMutableArray *)resumeDataArray{ if (_resumeDataArray == nil) { self.resumeDataArray = [NSMutableArray new]; } return _resumeDataArray; } - (NSMutableArray *)downLoadTaskArray{ if (_downLoadTaskArray == nil) { self.downLoadTaskArray = [NSMutableArray new]; } return _downLoadTaskArray; } - (NSURLSession *)downLoadSession{ if (_downLoadSession == nil) { NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]]; self.downLoadSession = session; _downLoadSession = session; } return _downLoadSession; } /** 管理对象*/ + (instancetype)downLoadManager{ return [[self alloc] init]; } #pragma mark - custom Method /** 暂停下载*/ - (void)pauseDownLoad{ __weak typeof (self) weakSelf = self; /** 保存下载进度*/ [self.downLoadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) { weakSelf.resumeData = resumeData; weakSelf.downLoadTask = nil; }]; } /** 取消下载*/ - (void)cancleDownLoad{ if (self.downLoadSession) { _finishedCount = 0; [self.delegate downLoad:self withProgress:0]; [self.delegate downLoadFinished:self withFinishedCount:_finishedCount andTotalCount:_totalCount]; /** 清除本地存储*/ [self saveDownloadDataYesOrClearDownLoadDataNo:NO withLocalUrl:nil]; /** 取消下载*/ self.resumeData = nil; [self.downLoadTask cancel]; self.downLoadTask = nil; } } /** 恢复下载*/ - (void)resumeDownLoad{ if (self.resumeData) {//有缓存数据,即需要恢复下载 /** 从缓存处恢复下载*/ self.downLoadTask = [self.downLoadSession downloadTaskWithResumeData:self.resumeData]; /** 恢复下载*/ [self.downLoadTask resume]; /** 缓存置空*/ self.resumeData = nil; } } /** 单个Url下载*/ - (void)downLoadFileWithUrlStr:(NSString *)urlStr{ self.downLoadUrlStr = urlStr; } /** 数组下载*/ - (void)downLoadFilesWithUrlStrArray:(NSArray *)urlStrArray{ self.downLoadUrlStrArray = urlStrArray; } #pragma mark - setter and getter /** 单个地址下载*/ - (void)setDownLoadUrlStr:(NSString *)downLoadUrlStr{ /** 设置总下载个数*/ if (!_totalCount) { _totalCount = 1; [self.delegate downLoadFinished:self withFinishedCount:_finishedCount andTotalCount:_totalCount]; } _downLoadUrlStr = downLoadUrlStr; /** 判断是否当前地址已经下载,如果已下载直接开启下一个任务*/ NSString *fileStr = [downLoadUrlStr componentsSeparatedByString:@"#"].firstObject; NSString *urlStr = [fileStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSURL *URL = [NSURL URLWithString:urlStr]; NSURLSessionDownloadTask *downLoadTask = [self.downLoadSession downloadTaskWithURL:URL]; self.downLoadTask = downLoadTask; [downLoadTask resume]; } /** 数组下载*/ - (void)setDownLoadUrlStrArray:(NSArray *)downLoadUrlStrArray{ _downLoadUrlStrArray = downLoadUrlStrArray; _totalCount = downLoadUrlStrArray.count; /** 同时下载*/ /* for (int i = 0; i < downLoadUrlStrArray.count; i ++) { NSURL *URL = [NSURL URLWithString:URLPATH]; NSURLSessionDownloadTask *downLoadTask = [self.downLoadSession downloadTaskWithURL:URL]; [self.downLoadTaskArray addObject:downLoadTask]; [downLoadTask resume]; } */ /** 非同时下载*/ if (_totalCount) { [self.delegate downLoadFinished:self withFinishedCount:_finishedCount andTotalCount:_totalCount]; [self downLoadFileWithUrlStr:[downLoadUrlStrArray firstObject]]; } } #pragma mark - delegate /** 下载成功*/ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{ //1.保存下载 [self saveDownloadDataYesOrClearDownLoadDataNo:YES withLocalUrl:location]; //2.开启另一个任务 [self startAnotherTask]; } /** 下载完成、中断或失败调用*/ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ if (error) {//下载错误 if ([error.localizedDescription isEqualToString:@"cancelled"]) { NSLog(@"用户取消/暂停下载"); }else{ /** 返回错误原因*/ [self.delegate downLoadFailed:self withError:error]; /** 开启另一个下载*/ [self startAnotherTask]; } } } /** 下载进度: 0.00% */ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ float currentRatio = totalBytesWritten * 1.0 / totalBytesExpectedToWrite; [self.delegate downLoad:self withProgress:currentRatio]; } #pragma mark - downLoad /** 开启另一个下载*/ - (void)startAnotherTask{ _finishedCount ++; /** 返回当前已下载(包括下载失败的)*/ [self.delegate downLoadFinished:self withFinishedCount:_finishedCount andTotalCount:_totalCount]; /** 开启另一个下载*/ if (_finishedCount < _totalCount) { //开启另一个下载 [self downLoadFileWithUrlStr:self.downLoadUrlStrArray[_finishedCount]]; }else{ _finishedCount = 0; NSLog(@"已完成所有下载!"); } } /** 保存或删除本地数据*/ - (void)saveDownloadDataYesOrClearDownLoadDataNo:(BOOL)isSaveData withLocalUrl:(NSURL *)location{ NSFileManager *fileManager = [NSFileManager defaultManager];//文件管理 //文件夹路径 NSString *documentPath = [NSString stringWithFormat:@"%@%@",[NSHomeDirectory() stringByAppendingString:@"/Documents/"],self.documentName]; /** 创建文件夹*/ if (![fileManager fileExistsAtPath:documentPath]) { [fileManager createDirectoryAtPath:documentPath withIntermediateDirectories:YES attributes:nil error:nil]; } //文件路径 NSString *filePath = [NSString stringWithFormat:@"%@/%ld.mp3",documentPath,_finishedCount]; //转换为地址 NSURL *fileUrl=[NSURL fileURLWithPath:filePath]; NSError *error; BOOL succeed; if (isSaveData) { //移除原先 [fileManager removeItemAtURL:fileUrl error:nil]; //保存单个 succeed = [fileManager moveItemAtURL:location toURL:fileUrl error:&error]; if (succeed) { NSLog(@"保存文件成功:%@",fileUrl); } else{ NSLog(@"保存文件失败:%@",error); } }else{ //删除所有 succeed = [fileManager removeItemAtPath:documentPath error:&error]; if (succeed) { NSLog(@"删除文件夹成功:%@",documentPath); } else{ NSLog(@"删除文件夹失败:%@",error); } } } @end