9

I was trying to use the new ios7 background transfer api to upload some photos to a server. what it happened now is 1) we upload the bytes to s3 2) call a service api to 'complete' the upload

i looked at this doc and it seems background NSURLSession doesn't support 'data' task. does that mean i can't do the step 2 in background after the actual upload is done?

Erben Mo
  • 3,528
  • 3
  • 19
  • 32
  • did u get any answer on this. I have the same issue – Ekra Oct 30 '13 at 13:38
  • yes.. i found that I can use a NSURLSessionDownloadTask for the service call. it is very similar to the NSURLSessionDataTask except that the service response xml/json will be stored on disk... – Erben Mo Oct 31 '13 at 06:54
  • So what is your solution to this? Did you create the second NSURLSession task in NSURLSession:task:didCompleteWithError: ? – honcheng Apr 27 '14 at 02:47
  • althought background NSURLSession doesn't support dataTask, it does support download task. And you can use a background downloadTask to send a POST request. see here http://stackoverflow.com/questions/19700572/ios-7-background-upload-and-post-requests/20089346#20089346 – Erben Mo Apr 27 '14 at 22:28
  • on the other hand, since a POST request is usually very fast, you can send use a foreground NSURLSession to create a dataTask to send a POST request. you can do it in your NSURLSession:task:didCompleteWithError callback since that callback usually gives you 15 seconds to make foreground call. – Erben Mo Apr 27 '14 at 22:30

4 Answers4

4

If you want a simpler solution than repurposing NSURLSessionDownloadTask for your "completed" API call, you can round trip a quick http call during the callback in:

-URLSession:task:didCompleteWithError:

Clay Bridges
  • 11,602
  • 10
  • 68
  • 118
3

For S3 with background task see my answer here

Another good resource is the apple sample code here and look for "Simple Background Transfer"

You have to create an upload task and upload from local file. While your app is running the NSURLSessionTaskDelegate delegate methods will be called on completion specifically at upload completion:

    /* Sent as the last message related to a specific task.  Error may be
    * nil, which implies that no error occurred and this task is complete. 
    */
    -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                       didCompleteWithError:(NSError *)error;

If your app went to the background or even was killed by iOS (and not by the user), your app would be waken up with

URLSessionDidFinishEventsForBackgroundURLSession

And then your NSURLsession delegate method would be called

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session

The way you should build it is as follow, in your appDelegate add

        - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
       {
           /*
            Store the completion handler. The completion handler is invoked by the view            controller's checkForAllDownloadsHavingCompleted method (if all the download tasks have been            completed).
            */
        self.backgroundSessionCompletionHandler = completionHandler;
       }

Then in your controller/model class add

    /*
     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
    {
        APLAppDelegate *appDelegate = (APLAppDelegate *)[[UIApplication sharedApplication] delegate];
        if (appDelegate.backgroundSessionCompletionHandler) {
            void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
            appDelegate.backgroundSessionCompletionHandler = nil;
            completionHandler();
        }

        NSLog(@"All tasks are finished");
    }
Community
  • 1
  • 1
Zeev Vax
  • 914
  • 7
  • 13
0

NSURLSessions has a delegate method URLSessionDidFinishEventsForBackgroundURLSession which is called after session completes all its tasks. I believe you should perform an api call out there.

Maciej Oczko
  • 1,225
  • 8
  • 11
-2
- (void)applicationDidEnterBackground:(UIApplication *)application
{

if([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)])
{
    NSLog(@"Multitasking Supported");

    __block UIBackgroundTaskIdentifier background_task;
    background_task = [application beginBackgroundTaskWithExpirationHandler:^ {

        //Clean up code. Tell the system that we are done.
        [application endBackgroundTask: background_task];
        background_task = UIBackgroundTaskInvalid;
    }];

    //To make the code block asynchronous
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        //### background task starts
        NSLog(@"Running in the background\n");
        while(TRUE)
        {
            NSLog(@"Background time Remaining: %f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
            [NSThread sleepForTimeInterval:1]; //wait for 1 sec
        }
        //#### background task ends

        //Clean up code. Tell the system that we are done.
        [application endBackgroundTask: background_task];
        background_task = UIBackgroundTaskInvalid; 
    });
}
else
{
    NSLog(@"Multitasking Not Supported");
}
}

put this code into appdelegate.m file

Try this code , hope it will help.

praveen
  • 1
  • 2
  • This wouldn't work well in iOS7 especially with a task that takes a long time to complete. The question is about NSURLSession – honcheng Apr 27 '14 at 02:45