.h文件
#import <Foundation/Foundation.h> #import <FileProvider/FileProvider.h> #define FileStorePath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:FileName] #define TotalLengthPlist [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"DownTask.plist"] #define DownloadLength [[[NSFileManager defaultManager] attributesOfItemAtPath:FileStorePath error:nil][NSFileSize] integerValue] //typedef void (^successBlock) (NSString *fileStorePath); //typedef void (^failBlock) (NSError*error); //typedef void (^progressBlock) (float progress); @interface DownLoadFileManager : NSObject<NSURLSessionDataDelegate> @property(copy,nonatomic)void (^successBlock)(NSString*fileStorePath,NSString*url) ; @property(copy,nonatomic)void (^failBlock)(NSError *error,NSString*url) ; @property(copy,nonatomic)void (^progressBlock)(float progress,NSString*url); //本地下载列表 @property(nonatomic,strong)NSMutableArray *downLoadList; //session数组 @property(nonatomic,strong)NSMutableArray <NSURLSession*> *sessionArr; //sessionTask数组 @property(nonatomic,strong)NSMutableArray <NSURLSessionDataTask*>*sessionTaskArr; @property(nonatomic,strong)NSMutableArray<NSOutputStream*>*outputStreamArr; -(void)downloadWithUrl:(NSString *)url progress:(void (^)(float progress,NSString*url))progressBlock success:(void(^)(NSString *filePath,NSString*url))successBlock fail:(void(^)(NSError*error,NSString*url))failBlock; -(void)stopTask; +(instancetype)shareManager; //添加下载任务,本地plist数组,增加一个元素,元素为字典,字典:name文件名,size文件总大小,finished是否下载完毕,url下载链接。 // @end
.m文件
#import "DownLoadFileManager.h" @implementation DownLoadFileManager static id _instance; //单例 +(instancetype)shareManager{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } //检测本地下载列表是否有未完成的任务 -(NSMutableArray *)downLoadList{ if (!_downLoadList) { _downLoadList = [NSMutableArray array]; [_downLoadList arrayByAddingObjectsFromArray:[NSArray arrayWithContentsOfFile:TotalLengthPlist]]; } return _downLoadList; } //开启所有未完成的下载任务 -(void)startAllTaskWithprogress:(void (^)(float progress,NSString*url))progressBlock success:(void (^)(NSString *filepath,NSString*url))successBlock fail:(void (^)(NSError *error,NSString*url))failBlock{ self.successBlock = successBlock; self.failBlock = failBlock; self.progressBlock = progressBlock; for (int i = 0; i<self.downLoadList.count; i++) { NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:self.downLoadList[i]]; if ([dic[@"finished"] isEqualToString:@"0"]) { //获取到有未下载完成的任务时 //生成新的task,task的url从本地存储的里边去取 [self addATaskToArrWithUrl:dic[@"url"] name:dic[@"name"]]; } } } -(void)addATaskToArrWithUrl:(NSString*)url name:(NSString*)name { NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init] ]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]]; NSString *range = [NSString stringWithFormat:@"bytes=%ld-",[[[NSFileManager defaultManager] attributesOfItemAtPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:name] error:nil][NSFileSize] integerValue]]; [request setValue:range forHTTPHeaderField:@"range"]; NSURLSessionDataTask *task = [session dataTaskWithRequest:request]; NSOutputStream*outStream = [NSOutputStream outputStreamToFileAtPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:name] append:YES]; [self.outputStreamArr addObject:outStream]; [task resume]; [self.sessionArr addObject:session]; [self.sessionTaskArr addObject:task]; } //添加一个单个下载任务 -(void)downloadWithUrl:(NSString *)url progress:(void (^)(float progress,NSString*url))progressBlock success:(void(^)(NSString *filePath,NSString*url))successBlock fail:(void(^)(NSError*error,NSString*url))failBlock{ self.successBlock = successBlock; self.failBlock = failBlock; self.progressBlock = progressBlock; NSMutableDictionary *newDownLoadTaskDic = [NSMutableDictionary dictionaryWithDictionary:@{@"name":[self getHashTypeStrWithUrl:url],@"url":url,@"size":@"0",@"finished":@"0"}]; [self.downLoadList addObject:newDownLoadTaskDic]; [self.downLoadList writeToFile:TotalLengthPlist atomically:YES]; [self addATaskToArrWithUrl:url name:[self getHashTypeStrWithUrl:url]]; } -(void)stopTask{ //取出相应的task,并暂停 // [self.task suspend]; } -(NSMutableArray<NSOutputStream *> *)outputStreamArr{ if (!_outputStreamArr) { _outputStreamArr = [[NSMutableArray alloc] init]; } return _outputStreamArr; } -(NSMutableArray<NSURLSession *> *)sessionArr{ if (!_sessionArr) { _sessionArr = [[NSMutableArray alloc] init]; } return _sessionArr; } -(NSMutableArray<NSURLSessionDataTask *> *)sessionTaskArr{ if (!_sessionTaskArr) { _sessionTaskArr = [[NSMutableArray alloc] init]; } return _sessionTaskArr; } -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{ for (int i = 0; i<self.sessionArr.count; i++) { if (session==[self.sessionArr objectAtIndex:i]) { //output获取,然后开始书写 [self.outputStreamArr[i] write:data.bytes maxLength:data.length]; float progress = 1.0*([[[NSFileManager defaultManager] attributesOfItemAtPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@",[self.downLoadList[i] objectForKey:@"name"] ]] error:nil][NSFileSize] integerValue])/[NSString stringWithFormat:@"%@",[self.downLoadList[i] objectForKey:@"size"] ].intValue; if (self.progressBlock) { self.progressBlock(progress, [NSString stringWithFormat:@"%@",[self.downLoadList[i] objectForKey:@"url"]]); } } } } -(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler{ completionHandler(NSURLSessionAuthChallengeUseCredential,[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); } -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{ NSString *url = response.URL.absoluteString; for (int i = 0; i<self.downLoadList.count; i++) { if ([url isEqualToString:[self.downLoadList[i] objectForKey:@"url"]]) { [self.outputStreamArr[i] open]; NSInteger totallength = response.expectedContentLength+[[[NSFileManager defaultManager] attributesOfItemAtPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[self.downLoadList[i] objectForKey:@"size"] ] error:nil][NSFileSize] integerValue]; NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:self.downLoadList[i]]; [dic setObject:[NSString stringWithFormat:@"%ld",totallength] forKey:@"size"]; [self.downLoadList replaceObjectAtIndex:i withObject:dic]; [self.downLoadList writeToFile:TotalLengthPlist atomically:YES]; } } completionHandler(NSURLSessionResponseAllow); } -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ return; if (error) { if (self.failBlock) { // self.failBlock(error); self.successBlock = nil; self.progressBlock = nil; self.failBlock = nil; } //取出相应的写入流,task,并置空释放,或关闭 // self.stream = nil; // self.task = nil; }else{ if (self.successBlock) { // self.successBlock(FileStorePath); self.successBlock = nil; self.failBlock = nil; self.progressBlock = nil; } //取出相应的写入流,task,并置空释放,或关闭 // [self.stream close]; // self.stream = nil; // self.task = nil; } } -(NSString*)getHashStrWithUrl:(NSString*)url{ return [NSString stringWithFormat:@"%lu",(unsigned long)[url hash]]; } //hash.m4a,文件类型后缀名 -(NSString*)getHashTypeStrWithUrl:(NSString*)url{ NSArray*strArr = [url componentsSeparatedByString:@"."]; if (strArr.count>1) { url = [NSString stringWithFormat:@"%@.%@",[self getHashStrWithUrl:url],strArr[strArr.count-1]]; return url; }else{ return [self getHashStrWithUrl:url]; } return [self getHashStrWithUrl:url]; } @end
调用方法,开启一个下载任务:
(要开启几个下载任务,就使用添加几个downloadWithUrl方法,URL是你要下载的资源的远程地址):
- (IBAction)startDownload:(id)sender { NSString *url = @"http://audio.xmcdn.com/group11/M01/93/AF/wKgDa1dzzJLBL0gCAPUzeJqK84Y539.m4a"; [[DownLoadFileManager shareManager] downloadWithUrl:url progress:^(float progress, NSString *url) { NSLog(@"progress: %f \n URL:%@",progress,url); } success:^(NSString *filePath, NSString *url) { NSLog(@"filepath: %@ \n URL:%@",filePath,url); } fail:^(NSError *error, NSString *url) { NSLog(@"error: %@ \n URL:%@",error.userInfo[NSLocalizedDescriptionKey],url); }]; NSString *url1 = @"https://wqs.jd.com/promote/superfestival/superfestival.mp4"; [[DownLoadFileManager shareManager] downloadWithUrl:url1 progress:^(float progress, NSString *url) { NSLog(@"progress: %f \n URL:%@",progress,url); } success:^(NSString *filePath, NSString *url) { NSLog(@"filepath: %@ \n URL:%@",filePath,url); } fail:^(NSError *error, NSString *url) { NSLog(@"error: %@ \n URL:%@",error.userInfo[NSLocalizedDescriptionKey],url); }]; } - (IBAction)pauseDownload:(id)sender { [[DownLoadFileManager shareManager] stopTask]; }
更多问题,欢迎加群讨论:565191947