iOS background task using NSURLSessionDataTask
Asked Answered
C

1

5

I have flight search feature in my application which is taking too long to get the data (more than 25 seconds). if application goes background or went to sleep mode, internet connection get disconnected.

I have written below logic using apple example to make api request keep going even though if app goes to background but it's not working.

self.session = [self backgroundSession];
self.mutableData = [NSMutableData data];

NSURL *downloadURL = [NSURL URLWithString:@"http://jsonplaceholder.typicode.com/photos"];
NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
self.dataTask = [self.session dataTaskWithRequest:request];
[self.dataTask resume];

- (NSURLSession *)backgroundSession
{
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.example.apple-samplecode.SimpleBackgroundTransfer.BackgroundSession"];
        session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
    });
    return session;
}

below are the delegate methods

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
 NSLog(@"response: %@", response.debugDescription);
 NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
    if (completionHandler) {
        completionHandler(disposition);
    }
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data {
    [self.mutableData appendData:data];
}


- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    BLog();

    if (error == nil)
    {
        NSData *data = nil;
        if (self.mutableData) {
            data = [self.mutableData copy];
            self.mutableData = nil;
        }

        NSError* error;
        NSArray* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
        if (!json) {
            NSLog(@"Error parsing JSON: %@", error);
        } else {
            NSLog(@"Data: %@", json);
        }
    }
    else
    {
        NSLog(@"Task: %@ completed with error: %@", task, [error localizedDescription]);
    }

    double progress = (double)task.countOfBytesReceived / (double)task.countOfBytesExpectedToReceive;
    dispatch_async(dispatch_get_main_queue(), ^{
        self.progressView.progress = progress;
    });

    self.dataTask =nil;
}

Everything works fine when application is in foreground but as soon as I put application on background getting below error message.

Completed with error: Lost connection to background transfer service

Chiefly answered 22/9, 2016 at 12:37 Comment(3)
Have you tried adding the Background Fetch capability from the Target "Capabilities" tab?Butta
once enable background fetch option in backgroundmodes . xcode - capabilities - Background modesDownpipe
Yes I did that but still I get the same error message.Chiefly
I
10

You cannot use data tasks for background transfers. Those must be done using download tasks:

Download tasks retrieve data in the form of a file, and support background downloads while the app is not running.

This is explained in Apple's documentation.

Also be sure to check out their background transfer considerations:

With background sessions, because the actual transfer is performed by a separate process and because restarting your app’s process is relatively expensive, a few features are unavailable, resulting in the following limitations...

The key here is that it's running in a separate process which cannot access the data you keep in memory. It must be routed through a file.

I collected a lot of information about background transfer on iOS in a (long) blog post.

Intension answered 22/9, 2016 at 13:5 Comment(8)
Thanks Krumelur! I modified the code with download task it's working fine.Chiefly
When internet got disconnected after downloadTask request, didCompleteWithError delegate method is not getting called. Once internet connection is back it's automatically resume. Is there a way to get internet disconnected error message.Chiefly
After reading apple document, looks like it's not possible to find the internet connection status while downloadTask executing. added below code for timeout sessionConfig.timeoutIntervalForRequest = 30.0; sessionConfig.timeoutIntervalForResource = 60.0;Chiefly
data task in bg should be supported: " Prior to iOS 8 and OS X 10.10, data tasks are not supported in background sessions." (from the linked docs)Lonnie
That's new. Interesting. Unsure how this would work. Thanks for pointing out.Intension
@Lonnie I think the data task is still not support on iOS 11. It's easy to verify this by creating a data task then put app into background: The data task will not be running. Not sure why apple put this confusing line in doc. I guess Apple means that "you can't create a dataTask on background session on iOS 8 and before but on iOS 9+ you can create dataTask then convert it to downloadTask when needed"Subtlety
@Chiefly Can you share how did you modified code with download task? I have an API which goes through lots of queries from different tables at back-end and so, response time is more than 5 minutes. If I lock the iPad or display is dimmed of automatically, I get error when I turn iPad back.. what should I do?Eldrida
@Eldrida Apologize for the late reply. Maybe this could help you for future reference. I have used Alamofire.download API’s to achieve the background data download. Please look at the below link for more information. github.com/tonyli508/AlamofireDomain#downloading-data-to-a-fileChiefly

© 2022 - 2024 — McMap. All rights reserved.