5

I have an application which sends data to the server while app is in the background. Here is the code responsible for data sending:

-(bool) sendStats: (MCStatsSender*) val{

    if(![self checkInternet]){ //Using Reachability here

        return false;
    }

    NSDictionary *inputData = [NSDictionary dictionaryWithObjectsAndKeys:
                               self.propertyA.value, "key1",
                               val.data, "key2",
                               nil];


    [myNetworkManager doRequest:[myRequestManager createWithStringAndDictionary:MY_URL Data:inputData handler:myHandler user:val]];
    return true;
}

So the inputData is a simple dictionary with strings.

A method doRequest is based on a NSURLSession and basically looks like this:

-(void) doRequest: (MCRequest*) request{

    [tasks addObject:request];

    if(m_session == nil){
        NSURLSessionConfiguration* config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:[NSString stringWithFormat:@"key-%lu",reqid]];
        m_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
    }

    NSURLSessionDataTask* task = [m_session dataTaskWithRequest:request.generatedRequest];
    request.reqId = task.taskIdentifier;
    [task resume];  
}

As I said, everything works through Wi-Fi, the app goes into background, and after few minutes, a custom bluetooth device sends some data and wakes an application from a suspended mode. After the data has been received by iOS application, it fails to send it to a server if a device is connected over 3G. I am positive that data sent via bluetooth is received because it is stored in local database.

Also there is one other important fact. If an application is run through the Xcode, even if a device is connected over 3G, the application will send a data from background. To do this, I run an app, then tap a Home button to put it into background.

Don't know what is the difference and why app acts differently when it is attached with a cable to Mac, and why data is not sent via 3G (or even 2G) ?

Additional info:

I am not trying to upload a file, but rather just send a JSON to a server.

Whirlwind
  • 14,286
  • 11
  • 68
  • 157
  • after how much time you got bluetooth data in your device ?? – CodeChanger Nov 11 '16 at 09:01
  • @CodeChanger An app is getting data from a bluetooth every five minutes or less. I am certain that data from a bluetooth is received because I store it in a local sqlite database. – Whirlwind Nov 11 '16 at 09:02
  • Ok so as per my knowledge after 3.0 Min app is suspended and you have to handle that mode and call your service with `bgTask`. – CodeChanger Nov 11 '16 at 09:06

1 Answers1

4

It seems likely that this is about power usage. The background upload offered by URL session is a convenience, and it's offered to you at the discression of the OS - it offers to send the data but it gets to choose when.

Things which affect when the data will be sent include wether the device is connected to power, the quality of the data connection (how long and how much power will it take to send the data), what else the device is doing (can it combine multiple uploads)...

So, you can't guess or rely on any task being actioned at any particular time while in the background.

This kind of testing should really be done on a device only, and not connected to Xcode because it influences the test. Instead, use something like Charles proxy to log the network requests and use the device, leaving it for periods of time and maybe opening and using some other app. You should see the data get sent eventually, but you will have to wait.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • Yeah, I did some more research and digging about this, and it is about power and Wi-Fi mostly which are two main factors when iOS determines if app is in a good state to execute discretionary tasks. Of course, there are some other factors as well, as you said ... – Whirlwind Nov 13 '16 at 10:46
  • Still, the problem is that no data is ever sent if app is in the background, not after 1 minute, not after 1 hour. The thing is that I am not the one who wrote a class which handle requests, so I can't be 100% sure at the moment that everything is configured correctly (hopefully the class itself is problematic). I will make some tests and let you know about results. I was testing on a device connected to the computer just to see if battery has something with this. Of course, I will disconnect a device later on. – Whirlwind Nov 13 '16 at 11:00
  • I just tried a Charles proxy for fun, it is a handy app, but it is not that helpful in my case. Because it requires a Wi-Fi connection. My network requests are sent ( like I mentioned in my question) when a device is connected through Wi-Fi. The problem is with cellular (3G) connection. Anyways, I don't actually need that app, because I already see on my server if a request was successful or not. I think I will experiment a bit with NSURLSession, its configuration and background tasks. – Whirlwind Nov 13 '16 at 18:36
  • @Whirlwind : You need to check that the API is firing or not under 3G. Based on server entry you can't be sure that the API isn't firing because may be its getting timed out in 3G connection. Besides, have you implemented `handleEventsForBackgroundURLSession` in appdelegate? – Poles Nov 15 '16 at 08:01
  • @Poles Yeah, I do have implemented handleEventsForBackgroundURLSession in AppDelegate. As far as looking into docs, I never found a statement that says this is impossible on 3G. As I said, I did some research and talks, and this behaviour is related to discretionary tasks. When you create a configuration using +backgroundSessionConfigurationWithIdentifier: (when you do that in the background), a task is inferred by the iOS as discretionary. Discretionary task will run only if app is in a "good state" to run them. Like Wain said, a battery has a big role in this (as well as many other things). – Whirlwind Nov 15 '16 at 08:47