I'm using 'AFNetworking', '2.0.0'
for download data.
I need to download large file. When user lock screen or press home button it should go pause (or continue downloading in background) and if I return to app it should resume.
Also I need to show progress of downloading.
I search a lot of examples but don't find anything 'AFNetworking', '2.0.0'
.
I create app for iOS version 6.0+, so I can't use AFHTTPSessionManager
or AFURLSessionManager
.
For downloading in background on iOS 7 or higher i'am using NSURLSession
with their NSURLSessionDownloadTask
.
Switch on BackgroundMode in ProjectNavigator->YourProject->YourTarget->Capabilities (tab)->Background Modes
Add to your AppDelegate method - (BOOL)application:(UIApplication* )application didFinishLaunchingWithOptions:(NSDictionary* )launchOptions
an initialiser for NSURLSessin
with next code:
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]];
Of course, don't forget to declare session
property with:
@property (nonatomic, strong) NSURLSession session;
Also add completion handler property (it will be needed if you want to get callback of background download process after Application termination or crash):
@property (nonatomic, copy) void(^backgroundTransferCompletionHandler)();
Add delegate methods in 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;
}
And declare that your class (in AppDelegate.h file for my example) conforms to protocol NSURLSessionDelegate
like here:
@interface AppDelegate : UIResponder <UIApplicationDelegate, NSURLSessionDelegate>
Then add download task somewhere with:
NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:[NSURL URLWithString:urlString]];
task.taskDescription = [NSString stringWithFormat:@"Downloading file %@", [urlString lastPathComponent]];
[task resume];
So when your application started after termination, your session will be restored and delegate methods will be fired. Also if your application will waked up from background to the foreground your application delegate methods will be fired too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With