Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

iOS7 NSURLSession 实现批量下载,支持后台下载功能(进度展示、暂停、重启等)

Notifications You must be signed in to change notification settings

kingundertree/XZDownloadTask

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

13 Commits

Repository files navigation

###先上效果图 XZDownloadTask

###github地址

https://github.com/kingundertree/XZDownloadTask

###说明 之前坐过几版下载的demo,要么不支持多任务、要么不支持后台下载或者对设计不满意。

这次重新设计新的模块,支持单任务、多任务、后台下载。

保留一个彩蛋,供下次优化。

###功能

  1. 支持单个任务下载,实现下载、暂停、重新下载、取消等。
  2. 单个任务支持后台下载,下载内容存储和下载信息回调,包括下载存储url和下载进度
  3. 支持多任务下载,包括批量下载、批量暂停、批量取消、批量重启。支持单个任务设置是否后台下载。同样支持单个任务的进度等信息回调。

###实现机制

  1. 下载基于iOS7 NSURLSessionDownloadTask 实现,通过配置NSUrlSession实现
  2. 通过NSURLSession配置backgroundSessionConfigurationWithIdentifier,实现后台下载
  3. 通过NSURLSession配置defaultSessionConfiguration,实现普通下载
  4. 通过NSURLSessionDownloadDelegate的代理方法,获取下载进度进度、下载成功失败以及后台下载完成信息

###设计模式

XZDownloadTask.........................下载类
	XZDownloadManager..................下载主功能实现区
	XZDownloadGroupManager.............多人下载管理类
	XZDownloadElement..................每个下载任务的辅助类
	XZDownloadResponse.................下载成功失败进度的响应类

###单任务下载实现 1.创建下载任务 通过isDownloadBackground分别创建常规下载任务或后台下载任务。

- (void)configDownloadInfo:(NSString *) downloadStr isDownloadBackground:(BOOL)isDownloadBackground identifier:(NSString *)identifier succuss:(void (^)(XZDownloadResponse *response)) succuss fail:(void(^)(XZDownloadResponse *response)) fail progress:(void(^)(XZDownloadResponse *response)) progress cancle:(void(^)(XZDownloadResponse *response)) cancle pause:(void(^)(XZDownloadResponse *response)) pause resume:(void(^)(XZDownloadResponse *response)) resume{
 self.downloadSuccuss = succuss;
 self.downloadFail = fail;
 self.downloadProgress = progress;
 self.downloadCancle = cancle;
 self.downloadPause = pause;
 self.downloadResume = resume;
 
 self.identifier = identifier ? identifier : [[NSProcessInfo processInfo] globallyUniqueString];
 
 if (isDownloadBackground) {
 [self startBackgroundDownload:downloadStr identifier:self.identifier];
 } else {
 [self startNormalDownload:downloadStr];
 }
}

2.常规下载任务

- (void)startNormalDownload:(NSString *)downloadStr {
 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadStr]];
 self.normalSessionTask = [self.normalSession downloadTaskWithRequest:request];
 [self.normalSessionTask resume];
}
- (NSURLSession *)normalSession {
 if (!_normalSession) {
 NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
 _normalSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
 _normalSession.sessionDescription = @"normal NSURLSession";
 }
 
 return _normalSession;
}

3.后台下载任务

- (void)startBackgroundDownload:(NSString *)downloadStr identifier:(NSString *)identifier {
 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadStr]];
 self.backgroundSession = [self getBackgroundSession:identifier];
 self.backgroundSessionTask = [self.backgroundSession downloadTaskWithRequest:request];
 [self.backgroundSessionTask resume];
}
- (NSURLSession *)getBackgroundSession:(NSString *)identifier {
 NSURLSession *backgroundSession = nil;
 NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:[NSString stringWithFormat:@"background-NSURLSession-%@",identifier]];
 config.HTTPMaximumConnectionsPerHost = 5;
 backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
 
 return backgroundSession;
}

4.暂停下载任务

核心方法cancelByProducingResumeData

- (void)pauseDownload {
 __weak typeof(self) this = self;
 if (self.normalSessionTask) {
 [self.normalSessionTask cancelByProducingResumeData:^(NSData *resumeData) {
 this.partialData = resumeData;
 this.normalSessionTask = nil;
 }];
 } else if (self.backgroundSessionTask) {
 [self.backgroundSessionTask cancelByProducingResumeData:^(NSData *resumeData) {
 this.partialData = resumeData;
 }];
 }
}

4.重启下载任务

核心方法downloadTaskWithResumeData

- (void)resumeDownload {
 if (!self.resumeSessionTask) {
 if (self.partialData) {
 self.resumeSessionTask = [self.normalSession downloadTaskWithResumeData:self.partialData];
 
 [self.resumeSessionTask resume];
 }
 }
}	

5.取消下载任务

核心方法cancel

- (void)cancleDownload {
 if (self.normalSessionTask) {
 [self.normalSessionTask cancel];
 self.normalSessionTask = nil;
 } else if (self.resumeSessionTask) {
 self.partialData = nil;
 [self.resumeSessionTask cancel];
 self.resumeSessionTask = nil;
 } else if (self.backgroundSessionTask) {
 [self.backgroundSessionTask cancel];
 self.backgroundSessionTask = nil;
 } 
}			

6.后台下载成功后回调

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
 self.backgroundURLSessionCompletionHandler = completionHandler;
}

7.后台下载成功后回调

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
 self.backgroundURLSessionCompletionHandler = completionHandler;
}

8.后台下载成功后回调NSURLSessionDownloadDelegate

下载中,处理下载进度

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
 double currentProgress = totalBytesWritten / (double)totalBytesExpectedToWrite;
 NSLog(@"%@---%0.2f",self.identifier,currentProgress);
}

下载失败

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
 // 下载失败
}

下载成功

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
 // 下载成功后文件处理
 NSFileManager *fileManager = [NSFileManager defaultManager];
 
 NSArray *URLs = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
 NSURL *documentsDirectory = URLs[0];
 
 NSURL *destinationPath = [documentsDirectory URLByAppendingPathComponent:self.identifier];
 NSError *error;
 
 [fileManager removeItemAtURL:destinationPath error:NULL];
 BOOL success = [fileManager copyItemAtURL:location toURL:destinationPath error:&error];
 
 if (success) {
 dispatch_async(dispatch_get_main_queue(), ^{
 // 此处可更新UI
 });
 } else {
 }
	
	// 下载成功后,下载任务处理,包括后台任务和普通任务区别,以及重启任务	 
 if(downloadTask == self.normalSessionTask) {
 self.normalSessionTask = nil;
 } else if (downloadTask == self.resumeSessionTask) {
 self.resumeSessionTask = nil;
 self.partialData = nil;
 } else if (session == self.backgroundSession) {
 self.backgroundSessionTask = nil;
 AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
 if(appDelegate.backgroundURLSessionCompletionHandler) {
 void (^handler)() = appDelegate.backgroundURLSessionCompletionHandler;
 appDelegate.backgroundURLSessionCompletionHandler = nil;
 handler();
 
 NSLog(@"后台下载完成");
 }	 
 }
}

9.后台下载完成,本地通知

- (void)showLocalNotification:(BOOL)downloadSuc {
 UILocalNotification *notification = [[UILocalNotification alloc] init];
 if (notification!=nil) {
 
 NSDate *now=[NSDate new];
 notification.fireDate=[now dateByAddingTimeInterval:6]; 
 notification.repeatInterval = 0; 
 
 notification.timeZone = [NSTimeZone defaultTimeZone];
 notification.soundName = UILocalNotificationDefaultSoundName;
 notification.alertBody = downloadSuc ? @"后台下载成功啦" : @"下载失败";
 notification.alertAction = @"打开"; 
 notification.hasAction = YES;
 notification.applicationIconBadgeNumber =+ 1; 
 
 NSDictionary* infoDic = [NSDictionary dictionaryWithObject:@"value" forKey:@"key"];
 notification.userInfo = infoDic;
 [[UIApplication sharedApplication] scheduleLocalNotification:notification];
 }
}	

###多任务下载

多任务下载,基于单独任务下载实现。只是提供了统一的方法进行管理。

多任务下载采用单例管理

1.调用多任务下载,需要手动传入下载请求

需要手动添加identifier,并通过identifier作为唯一标识,处理后续下载任务。

NSString *identifier = [[NSProcessInfo processInfo] globallyUniqueString];
[[XZDownloadGroupManager shareInstance] addDownloadRequest:[musicUrlArr objectAtIndex:index] identifier:identifier targetSelf:self showProgress:YES isDownloadBackground:YES downloadResponse:^(XZDownloadResponse *response) {
	[this handleResponse:response];
}];

2.下载任务处理

这是下载模块处理最频繁的方法

- (void)handleResponse:(XZDownloadResponse *)response {
 if (response.downloadStatus == XZDownloading) {
 NSLog(@"下载任务ing%@",response.identifier);
 XZDownloadView *downloadView = [self getDownloadView:response.identifier];
 dispatch_async(dispatch_get_main_queue(), ^{
 downloadView.progressV = response.progress;
 });
 } else if (response.downloadStatus == XZDownloadSuccuss) {
 NSLog(@"下载任务成功%@",response.identifier);
 XZDownloadView *downloadView = [self getDownloadView:response.identifier];
 downloadView.progressV = 1.0;
 } else if (response.downloadStatus == XZDownloadBackgroudSuccuss) {
 NSLog(@"后台下载任务成功%@",response.identifier);
 [self showLocalNotification:YES];
 XZDownloadView *downloadView = [self getDownloadView:response.identifier];
 downloadView.progressV = 1.0;
 } else if (response.downloadStatus == XZDownloadFail) {
 NSLog(@"下载任务失败%@",response.identifier);
 [self showLocalNotification:NO];
 } else if (response.downloadStatus == XZDownloadCancle) {
 NSLog(@"下载任务取消%@",response.identifier);
 } else if (response.downloadStatus == XZDownloadPause) {
 NSLog(@"下载任务暂停%@",response.identifier);
 } else if (response.downloadStatus == XZDownloadResume) {
 NSLog(@"下载任务重启%@",response.identifier);
 }
}

3.多任务的暂停、重启、取消

暂停

[[XZDownloadGroupManager shareInstance] pauseAllDownloadRequest];

重启

[[XZDownloadGroupManager shareInstance] resumeAllDownloadRequest];

取消

[[XZDownloadGroupManager shareInstance] cancleAllDownloadRequest];

About

iOS7 NSURLSession 实现批量下载,支持后台下载功能(进度展示、暂停、重启等)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /