AFNetworking 2.0.0 后台下载
Posted
技术标签:
【中文标题】AFNetworking 2.0.0 后台下载【英文标题】:AFNetworking 2.0.0 download in background 【发布时间】:2014-03-13 09:50:07 【问题描述】:我正在使用'AFNetworking', '2.0.0'
下载数据。
我需要下载大文件。当用户锁定屏幕或按下主页按钮时,它应该暂停(或在后台继续下载),如果我返回应用程序,它应该恢复。
我还需要显示下载进度。
我搜索了很多示例,但没有找到任何东西 'AFNetworking', '2.0.0'
。
我为 ios 6.0+ 版本创建应用程序,所以我不能使用 AFHTTPSessionManager
或 AFURLSessionManager
。
【问题讨论】:
也许你可以在这里找到解决方案:***.com/questions/12563753/… 【参考方案1】:为了在 iOS 7 或更高版本的后台下载,我使用NSURLSession
和他们的NSURLSessionDownloadTask
。
在 ProjectNavigator->YourProject->YourTarget->Capabilities (tab)->Background Modes 中打开 BackgroundMode
将NSURLSessin
的初始化器添加到您的 AppDelegate 方法 - (BOOL)application:(UIApplication* )application didFinishLaunchingWithOptions:(NSDictionary* )launchOptions
和下一个代码:
NSURLSessionConfiguration *sessionConfiguration;
NSString *someUniqieIdentifierForSession = @"com.etbook.background.DownloadManager";
if ([[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."] firstObject] integerValue] >= 8)
//This code for iOS 8 and greater
sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:someUniqieIdentifierForSession];
else
this code for iOS 7
sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:someUniqieIdentifierForSession];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
当然,不要忘记声明session
属性:
@property (nonatomic, strong) NSURLSession session;
还添加完成处理属性(如果您想在应用程序终止或崩溃后获取后台下载过程的回调,则需要它):
@property (nonatomic, copy) void(^backgroundTransferCompletionHandler)();
在 AppDelegate 中添加委托方法:
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *destinationFilename = downloadTask.originalRequest.URL.lastPathComponent;
NSURL *destinationURL = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:destinationFilename];
if ([fileManager fileExistsAtPath:[destinationURL path]])
[fileManager removeItemAtURL:destinationURL error:nil];
[fileManager copyItemAtURL:location
toURL:destinationURL
error:&error];
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
if (error != nil)
NSLog(@"Download completed with error: %@", [error localizedDescription]);
else
NSLog(@"Download finished successfully.");
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown)
NSLog(@"Unknown transfer size");
else
NSLog(@"progress = %lld Mb of %lld Mb", totalBytesWritten/1024/1024, totalBytesExpectedToWrite/1024/1024);
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
ETBAppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
// Check if all download tasks have been finished.
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks)
if ([downloadTasks count] == 0)
if (appDelegate.backgroundTransferCompletionHandler != nil)
// Copy locally the completion handler.
void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;
// Make nil the backgroundTransferCompletionHandler.
appDelegate.backgroundTransferCompletionHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^
// Call the completion handler to tell the system that there are no other background transfers.
completionHandler();
// Show a local notification when all downloads are over.
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = @"All files have been downloaded!";
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
];
];
//Background download support (THIS IMPORTANT METHOD APPLICABLE ONLY IN YOUR AppDelegate.m FILE!!!)
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
self.backgroundTransferCompletionHandler = completionHandler;
并声明您的类(在我的示例中的 AppDelegate.h 文件中)符合协议NSURLSessionDelegate
,如下所示:
@interface AppDelegate : UIResponder <UIApplicationDelegate, NSURLSessionDelegate>
然后在某处添加下载任务:
NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:[NSURL URLWithString:urlString]];
task.taskDescription = [NSString stringWithFormat:@"Downloading file %@", [urlString lastPathComponent]];
[task resume];
因此,当您的应用程序在终止后启动时,您的会话将被恢复并且委托方法将被触发。此外,如果您的应用程序将从后台唤醒到前台,您的应用程序委托方法也将被触发。
【讨论】:
【参考方案2】:当您的应用程序进入后台暂停/停止下载操作时,当进入前台时恢复您在 NSOperation 队列中暂停的下载操作。 阅读这几行代码可能会对您有所帮助:
AFDownloadRequestOperation *operation = [[AFDownloadRequestOperation alloc] initWithRequest:request targetPath:filePath shouldResume:YES];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
//handel completion
[operations removeObjectForKey:audioItem.filename];
failure:^(AFHTTPRequestOperation *operation, NSError *error)
//handel failure
operation = [operations objectForKey:audioItem.filename];
[operation cancel];
[operations removeObjectForKey:audioItem.filename];
if (error.code != NSURLErrorCancelled)
[self showErrorAlert];
NSLog(@"Error: %@", error);
];
[operation setProgressiveDownloadProgressBlock:^(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpected, long long totalBytesReadForFile, long long totalBytesExpectedToReadForFile)
//handel progress
NSNumber *progress = [NSNumber numberWithFloat:((float)totalBytesReadForFile / (float)totalBytesExpectedToReadForFile)];
float progress=progress.floatValue;
[self performSelectorOnMainThread:@selector(updateProgressBar:) withObject:[NSArray arrayWithObjects:audioItem, progress, nil] waitUntilDone: YES];
];
[operation setShouldExecuteAsBackgroundTaskWithExpirationHandler:^
// TODO: Clean up operations
NSLog(@"App has been in background too long, need to clean up any connections!");
];
[operations setValue:operation forKey:@"key"]; // store the NSOperation for further use in application to track its status.
[downloadQueue addOperation:operation];//here downloadQueue is NSOperationQueue instance that manages NSOperations.
要暂停下载操作,请使用:
[operation pause];
要恢复使用这种行:
[operation resume];
【讨论】:
什么是“操作”? "operations" 在这里是 NSMutableDictionary,存储文件名作为键和 NSOperation 对象作为值。【参考方案3】:也许您最好使用 DTDownload: https://github.com/Cocoanetics/DTDownload
据我所知,它没有任何可报告的进度。
编辑:AppCoda 上有一个很好的教程,关于使用 NSURLSessionTask: http://www.appcoda.com/background-transfer-service-ios7/
【讨论】:
以上是关于AFNetworking 2.0.0 后台下载的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 AFNetworking 2.x 管理许多 (>500) 后台 URLSession 下载?