I wonder whether it is possible to have multiple downloads when background fetch is happening (iOS7 Background Fetch). Currently I have an app which download data from around 6 RESTful api. These API calls use NSURLSession and download data parallelly. This works when the app is in foreground. I have implemented the background fetch feature with my application where app can update while it's in background. Unfortunately when background fetch is happening only the first API is calling six time. I really appreciate if anyone can help me on this.
This is the code for download tasks.
- (void)start {
self.responseData = [NSMutableData data];
self.isLoginRequest = YES;
self.dateFormatter = [[NSDateFormatter alloc] init];
[self.dateFormatter setDateStyle:NSDateFormatterMediumStyle];
self.apiList = [NSMutableArray array];
NSArray *apis = [self fetchAPIData];
for (API *api in apis) {
NSString *fullURL = [NSString stringWithFormat:@"%@/%@",BASE_URL, api.url];
switch ([api.type integerValue]) {
case 1:
[self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestLeadstatus andDownloadSource:fullURL]];
break;
case 2:
[self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestParam andDownloadSource:fullURL]];
break;
case 3:
[self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestLeadprofiles andDownloadSource:fullURL]];
break;
case 4:
[self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestInstallations andDownloadSource:fullURL]];
break;
case 5:
[self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestLeadproviders andDownloadSource:fullURL]];
break;
case 6:
[self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestSaleorders andDownloadSource:fullURL]];
break;
default:
break;
}
}
[self startAllDownloads:nil];
}
- (void)startAllDownloads:(id)sender {
self.session = [self backgroundSession];
// Access all download info objects using a loop.
for (int i=0; i<[self.apiList count]; i++) {
BSJSONInfo *jsonInfo = [self.apiList objectAtIndex:i];
// Check if a file is already being downloaded or not.
if (!jsonInfo.isDownloading) {
if (jsonInfo.taskIdentifier == -1) {
jsonInfo.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:jsonInfo.downloadSource]];
}
else{
jsonInfo.downloadTask = [self.session downloadTaskWithResumeData:jsonInfo.taskResumeData];
}
jsonInfo.taskIdentifier = jsonInfo.downloadTask.taskIdentifier;
[jsonInfo.downloadTask resume];
jsonInfo.isDownloading = YES;
}
}
}
-(int)getFileDownloadInfoIndexWithTaskIdentifier:(unsigned long)taskIdentifier{
int index = 0;
for (int i=0; i<[self.apiList count]; i++) {
BSJSONInfo *jsonInfo = [self.apiList objectAtIndex:i];
if (jsonInfo.taskIdentifier == taskIdentifier) {
index = i;
break;
}
}
return index;
}
- (NSURLSession *)backgroundSession
{
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:[NSString stringWithFormat:@"%@", SESSION_STRING]];
configuration.timeoutIntervalForRequest = 30.0;
configuration.timeoutIntervalForResource = 60.0;
session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
});
return session;
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *URLs = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *documentsDirectory = [URLs objectAtIndex:0];
NSURL *originalURL = [[downloadTask originalRequest] URL];
NSURL *destinationURL = [documentsDirectory URLByAppendingPathComponent:[originalURL lastPathComponent]];
NSError *errorCopy;
[fileManager removeItemAtURL:destinationURL error:NULL];
BOOL success = [fileManager copyItemAtURL:downloadURL toURL:destinationURL error:&errorCopy];
if (success){
int index = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier];
BSJSONInfo *jsonInfo = [self.apiList objectAtIndex:index];
jsonInfo.isDownloading = NO;
jsonInfo.downloadComplete = YES;
jsonInfo.taskIdentifier = -1;
jsonInfo.taskResumeData = nil;
//Let parser to parse the JSON
dispatch_async(dispatch_get_main_queue(), ^{
self.responseData = [NSData dataWithContentsOfURL:destinationURL];
[self parsingJSONResponse:self.responseData withType:jsonInfo.type];
});
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
if (error != nil) {
self.networkError = error;
[self.delegate downloadingError:[error localizedDescription]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate downloadingError:[NSString stringWithFormat:@"%@ for type %lu", [error localizedDescription], self.bsType]];
return;
});
}
self.downloadTask = nil;
}
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
BSAppDelegate *appDelegate = (BSAppDelegate *)[[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.backgroundSessionCompletionHandler != nil) {
void(^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
appDelegate.backgroundSessionCompletionHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
completionHandler();
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = @"All files have been downloaded!";
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}];
}
}
}];
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{
// BLog();
}
Thanks