1

Our app utilizes didReceiveRemoteNotification: fetchCompletionHandler: methods UIApplicationDelegate to start a download when a content-available push notification is received.

The individual steps the app takes:

[1] Receive a notification

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    NSLog(@"Remote download push notification received");
    [AFHTTPSessionManager_Instance downloadFile:completionHandler];        
}

[2] Start a new download Task

- (void)downloadFile:(void (^)(UIBackgroundFetchResult))completionHandler {
    NSURLSessionDownloadTask *task = [AFHTTPSessionManager_Instance downloadTaskWithRequest:request progress:nil destination:nil completionHandler:nil];
    [task resume];
    NSLog(@"Starting download of %@", request.URL.absoluteString);

    // Some additional time to start the download
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        NSLog(@"Completion handler!");
        completionHandler(UIBackgroundFetchResultNewData);
});

[3] Handle the download

[self setDownloadTaskDidFinishDownloadingBlock:^NSURL *(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location) {
  NSLog(@"Download complete!");
  // ... Create save path
  return path;
}];

This results in a log like this:

2015-09-21 15:38:57.145 App[315:20933] Remote download push notification received
2015-09-21 15:38:57.485 App[315:20933] Starting download of http://domain.com/file.mov
2015-09-21 15:38:59.654 App[315:20933] Completion handler!
2015-09-21 15:39:06.315 App[315:20933] Download complete!

But sometimes (completely random) I see logs like this:

2015-09-21 15:38:57.145 App[315:20933] Remote download push notification received
2015-09-21 15:38:57.485 App[315:20933] Starting download of http://domain.com/file.mov
2015-09-21 15:38:59.654 App[315:20933] Completion handler!

In other words the download never completes, it looks like the app freezes its background session. Because when I put the app back into the foreground the download will finish at some point.

Has anyone seen this behavior before?
FYI: I enabled the right capabilities, used a correct provision profile and the app has permissions to run in the background.

Update: We've used answers/comments in AFNetworking 2.0 and background transfers when developing the background manager

Community
  • 1
  • 1
basvk
  • 4,437
  • 3
  • 29
  • 49

1 Answers1

1

You are calling the completion handler upon starting download! I'm pretty sure you should call the completion handler when the download is finished not 2 seconds after download started! in other words, you should call completionHandler(UIBackgroundFetchResultNewData); inside self setDownloadTaskDidFinishDownloadingBlock... and of corse pass the CompletionBlock somehow.

[self setDownloadTaskDidFinishDownloadingBlock:^NSURL *(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location) {

  NSLog(@"Download complete!");
  // ... Create save path
 NSLog(@"Completion handler!");
 completionHandler(UIBackgroundFetchResultNewData);

  return path;
}];

The correct log should be something like this:

2015-09-21 15:38:57.145 App[315:20933] Remote download push notification received

2015-09-21 15:38:57.485 App[315:20933] Starting download of http://domain.com/file.mov

2015-09-21 15:38:59.654 App[315:20933] Download complete!

2015-09-21 15:39:06.315 App[315:20933] Completion handler!

M. Porooshani
  • 1,797
  • 5
  • 34
  • 42
  • That means the download would have a maximum of 30 seconds to complete. Hence that backgroundFetching is a different thing then backgroundSessions: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/#//apple_ref/occ/intfm/UIApplicationDelegate/application:didReceiveRemoteNotification:fetchCompletionHandler: < Read the last paragraph under "application:didReceiveRemoteNotification:fetchCompletionHandler Discussion" – basvk Sep 21 '15 at 14:26
  • I'm completely aware of that fact, but I can't relate to your code. From what I'm seeing you are defining a download task with a completion handler of nil, start the task and 2 seconds after starting the download task you are calling the very completion block you're gonna have to call when you want to say to the background task you're done with the download task! In other words you are letting your background mode go just 2 seconds in. Am I missing something obvious here? You are passing the completionHandler block the push notification delegate method has given you and call it 2 seconds later – M. Porooshani Sep 21 '15 at 18:33
  • We've used answers/comments in http://stackoverflow.com/questions/21350125/afnetworking-2-0-and-background-transfers when developing the background manager – basvk Sep 22 '15 at 06:01
  • It's Ok to ignore my answer and I'm not sure which part of that long page you are referring to, but want you to read my answer again. To be more exhaustive, check the log you've provided in your question, All completion handlers are getting called before download is completed. Please refer to Apple's documentation: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/#//apple_ref/occ/intfm/UIApplicationDelegate/application:didReceiveRemoteNotification:fetchCompletionHandler: – M. Porooshani Sep 22 '15 at 06:10
  • It explicitly expresses that: `The block to execute when the download operation is complete. When calling this block, pass in the fetch result value that best describes the results of your download operation. You must call this handler and should do so as soon as possible. For a list of possible values, see the UIBackgroundFetchResult type.` – M. Porooshani Sep 22 '15 at 06:11
  • Okay let's say that's true and you should use backgroundFetch to download large files (instead of using a `NSURLSession`). How could you explain the fact that sometimes downloads actually complete: https://gist.github.com/basvankuijck/f683831df97257582fb0 (when the device is standby aka locked). – basvk Sep 22 '15 at 06:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/90290/discussion-between-m-porooshani-and-basvk). – M. Porooshani Sep 22 '15 at 07:01