In the meantime, I solved it by using a custom UploadManager Class and store downloads in Core Data until the upload was successful: (Below Code is not complete, and only shows the basic concept. If anybody is interested in the full implementation, please let me know)
@implementation UploadManager
- (void) uploadImage:(UIImage *)image toUrl:(NSString *)uploadUrl insertIntoDB:(BOOL)insertIntoDB
{
if(insertIntoDB) {
[self insertUploadTaskIntoDBWithImage:image andUploadUrl:uploadUrl];
}
// Background upload only works with files
NSString *fileName = [NSString stringWithFormat:@"%@%@", [uploadUrl sha256], @".png"];
NSString *signatureFile = [NSString stringWithFormat:@"%@/%@", NSTemporaryDirectory(), fileName];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:signatureFile atomically:YES];
while (![[NSFileManager defaultManager] fileExistsAtPath:signatureFile]) {
[NSThread sleepForTimeInterval:.5];
}
NSURLSession *session = [self backgroundSession];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:uploadUrl]];
[request setHTTPMethod:@"POST"];
[request addValue:@"image/png" forHTTPHeaderField:@"Content-Type"];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromFile:[NSURL fileURLWithPath:signatureFile]];
[self showNetworkActivity:YES];
self.taskCount++;
[uploadTask resume];
}
-(void) uploadTasksInDatabase
{
NSArray* uploadTasks = [self getAllUploadTasksFromDatabase];
for(UploadTask *task in uploadTasks) {
UIImage *image = [UIImage imageWithData:task.signature];
[self uploadImage:image toUrl:task.uploadUrl insertIntoDB:NO];
}
}
/*
If an application has received an
application:handleEventsForBackgroundURLSession:completionHandler: message, the session
delegate will receive this message to indicate that all messages previously enqueued for this
session have been delivered. At this time it is safe to invoke the previously stored completion
handler, or to begin any internal updates that will result in invoking the completion handler.
*/
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
if (appDelegate.backgroundSessionCompletionHandler) {
void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
appDelegate.backgroundSessionCompletionHandler = nil;
completionHandler();
}
self.taskCount = 0;
NSDebug(@"All tasks are finished");
[self clearDatabase];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
BLog();
self.taskCount--;
[[NSNotificationCenter defaultCenter] postNotificationName:[task.originalRequest.URL description] object:self];
if(self.taskCount == 0) {
[self showNetworkActivity:NO];
}
if (error == nil)
{
NSLog(@"Task: %@ completed successfully", [task.originalRequest.URL description]);
[self deleteUploadTaskWithUploadUrl:[task.originalRequest.URL description]];
}
else
{
NSLog(@"Task: %@ completed with error: %@", [task.originalRequest.URL description], [error localizedDescription]);
}
}
In the App delegate insert the following:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Try to reupload all tasks in DB
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(backgroundQueue, ^{
[self.uploadManager uploadTasksInDatabase];
});
return YES;
}
This way it will try to reupload all unfinished tasks whenever the application is started again.