.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