My NSURLSessionDelegate methods are not getting called during a background download

cocoa-touch, ios, ios7, nsurlsession, objective-c

Solution

You won't see download delegate events called while the individual downloads finish in the background, but rather only after the app is restarted. e.g., when all of the downloads are successfully finished (when `handleEventsForBackgroundURLSession` is called) or when you manually restart the app.

As to why you're not seeing `handleEventsForBackgroundURLSession` called, I can only think of a couple (admittedly, unlikely) possibilities:

Make sure that the signature of the `handleEventsForBackgroundURLSession` in your app delegate is absolutely correct (capitalization, spelling, etc.). A minor typo will not generate any warning, but it will result in its not getting called. So it should be:

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
    // save the completionHandler here
}

Are you sure that all of your background downloads are finishing? If one of them hangs or fails for some reason, that will prevent the completion of the background session to be triggered, and because the delegate method is only called when everything is done, that means that your app will not be activated. I recommend carefully checking that all of the downloads have finished.

Have you checked the device's console? (You can see this if you go to the "Devices" section of the Xcode "Organizer".) Sometimes there are interesting diagnostic error messages which the background daemon will log for you. Check that out if you haven't already. Lots of interesting stuff there.

If you manually kill the app via SpringBoard (double tapping on physical home button, hold down app icon until its jiggling, click on red "x"), that will kill the background download tasks, and therefore you won't get notification that all of the downloads are done. Make sure you implement `URLSession:task:didCompleteWithError:` so you can see this error (and any others).

If, however, I programmatically crash the app as illustrated in the WWDC 2013 video What’s New in Foundation Networking, or if it is terminated by the system, then the background downloads finish correctly and the app delegate method is getting called correctly.

Just a few ideas to consider.

Problem

I'm trying to set up a download using `NSURLSession` that will continue in the background. I have a singleton class called `DownloadManager` which builds the `NSURLSession` and starts a download task like this: ``` - (id)init { self = [super init]; if (self) { self.queue = [[NSOperationQueue alloc] init]; self.queue.maxConcurrentOperationCount = 1; // Initialize the background session. self.session = [self backgroundSession]; } return self; } - (NSURLSession *)backgroundSession { static NSURLSession *session = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.mycompany.myapp.BackgroundSession"]; session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:self.queue]; }); return session; } - (void)startDownload:(Download *)download { NSURL *remoteURL = ... NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:remoteURL]; [task resume]; } ``` I've implemented the `NSURLSessionDelegate` and `NSURLSessionDownloadDelegate` methods including `URLSessionDidFinishEventsForBackgroundURLSession:`. Additionally, my application delegate implements `application:handleEventsForBackgroundURLSession:completionHandler:`. However, when I move my application to the background by pressing the home button after starting a download, all download delegate methods stop firing and `application:handleEventsForBackgroundURLSession:completionHandler:` is never called. The download continues, and if I wait long enough for it to finish then `URLSession:downloadTask:didFinishDownloadingToURL:` is called the moment I bring my app back to the foreground. This means that I can't do any post-processing in the background (e.g. save to core data, start a new download, etc.). I tried adding the 'Background fetch' background mode to my plist in case that was required, and I tried changing my the identifier used to create the `NSURLSessionConfiguration` background configuration as suggested in this answer. Have I made a mistake in setting this up, or am I not supposed to be able to handle download delegate events in the background?

Original source

Related problems