Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ApplicationWillTerminate NSURLSession Possible?

I am attempting to do a quick POST via NSURLSession at application termination. Application termination is defined as the user swipes it out when on the home screen. Furthermore, applicationWillTerminate is demonstratively called (so that's not in question).

My intent is to inform the server that this user is now going offline.

This, however, does not work .. as I don't receive a POST on my backend. I am trying to figure out why this doesn't work.. or even if it should? According to Apple docs, this should work if it can execute within 5 seconds.. although I don't even have a completion handler so it should be executed. Any help or advice will be greatly appreciated.

My implementation is as follows (for reference).

- (void)applicationWillTerminate:(UIApplication *)application {

    NSMutableDictionary * gatherAllInputs = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
                                             @"[email protected], @"emailEntry",
                                             @"False", @"isPersonAvailable",
                                             nil];

    NSError *error;
    NSData *gatherAllInputsJSON = [NSJSONSerialization dataWithJSONObject:gatherAllInputs options:0 error:&error];

    NSString* theDataSentToServer;
    theDataSentToServer = [[NSString alloc] initWithData:gatherAllInputsJSON encoding:NSUTF8StringEncoding];

    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *postingSession = [NSURLSession sessionWithConfiguration:sessionConfiguration];

    NSURL *url = [NSURL URLWithString:@"https://blahblahblah.com/someblah"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:[theDataSentToServer dataUsingEncoding:NSUTF8StringEncoding]];

    NSURLSessionDataTask *postSomething = [postingSession dataTaskWithRequest:request];
    [postSomething resume]; 
    NSLog(@"Got here!"); //<-- THIS GETS OUTPUTTED.. SO I KNOW THIS CODE IS BEING CALLED!

}

EDIT:

Similarly, We've messaging app with XMPP framework. Require to terminate/Disconnect the XMPP connection on applicationWIllTerminate delegate. Indeed, applicationWIllTerminate will be called when an app is in foreground and user switched to multitasking UI(double tap home button). tried by calling XMPP Disconnection but no luck.

Can't use WillResignActive for disconnection, Where in DidEnteredBackground delegate is not allowed this case for any time extension.

Server-client Ping pong acts every 2 minutes so cont relay on that as well.

Looking out a feasible solution to disconnect XMPP at user force quits an app.

like image 370
user330739 Avatar asked Feb 11 '15 22:02

user330739


3 Answers

A number of things could be happening:

First, Apple says :"Your implementation of this method has approximately five seconds to perform any tasks and return." Apple Docs

I emphasised "approximately" because taking these 5 seconds for granted is not something that you would normally want to do. This timeout could rely on a number of factors such as the overall availability of resources (impacted by specifics your app has no control over such as other apps running).

Secondly, you say: "although I don't even have a completion handler so it should be executed".

This means that you are executing a synchronous call i.e. a call that has to wait before letting go. Are you sure that zero to approximately 5 seconds is enough for this call? I know it sounds like too much time, but network availability/reliability/speed is also something that we should generally not take for granted.

Did you try doing something else instead of a network call there? Write something to user defaults for example? Put a timer and look for any variations in how much time you are really given.

like image 94
joakim Avatar answered Nov 20 '22 09:11

joakim


The issue is not, that 5 seconds (or something like 5 seconds) isn't enough time. And you do not start a task synchronously, because you have no handler. It is still a asynchronous call.

-applicationWillTerminate: is send on shut-down of the app. When it returns, the app is shot-down, even there are additional background tasks. So the background task is stopped, too. Therefore the background task only has milliseconds or less to finish.

You could use a synchronous request, so -applicationWillTerminate: does not return, before the request is done. However, this is never a got idea and for sure not in -applicationWillTerminate:. If you want to tell the server, that the app is gone, simply implement a heart beat. This has the additional advantage, that apps that quits without sending -applicationWillTerminate: are unregistered, too. (I. e. in case of crash.)

like image 29
Amin Negm-Awad Avatar answered Nov 20 '22 09:11

Amin Negm-Awad


I met exactly the same situation: NSURLSession just does not work in the applicationWillTerminate: procedure.

But if iOS does not give you 5 seconds to finish your tasks, you can take them by yourself:

sleep (3);

in the end of applicationWillTerminate: gave me enough time to perform all final network activity. Actually even 1 second delay works fine.

like image 2
Kibernetik Avatar answered Nov 20 '22 07:11

Kibernetik