Reputation: 41
here's yet another question on having GPS run in the background. Apparently, there are specific conditions where my app can run (seemingly indefinitely) in the background, and sometimes it will terminate after 3 minutes. My iPad is currently running on 9.3.2.
TL;DR: Did the necessary code and project configurations, but does not always run in background for longer than 3 minutes. Why?
My post will be lengthy. I have tried to keep it concise.
My app will need to send the GPS locations at every interval: 60 seconds if the user is "Logged in," and 900 seconds (15 minutes) if the user is "Logged out." I need these requirements; The program requirements are not decided by me. This app is not published to the app store either.
I understand that I need to add this in my plist:
<key>NSLocationAlwaysUsageDescription</key>
<string>Location information from this device is required for tracking purposes.</string>
Under the project capabilities, I have Background Modes -> Location updates selected, and also in the plist:
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
In my AppDelegate
, I also have these 2 (located inside application:didFinishLaunchingWithOptions:
):
if ([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
{
[locationManager requestAlwaysAuthorization];
NSLog(@"===>locationManager responds to requestAlwaysAuthorization<===");
}
else
{
NSLog(@"===>locationManager not responding to requestAlwaysAuthorization! :(<===");
}
if([locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
{
[locationManager setAllowsBackgroundLocationUpdates:YES];
NSLog(@"===>locationManager responds to setAllowsBackgroundLocationUpdates<===");
}
else
{
NSLog(@"===>locationManager not responding to setAllowsBackgroundLocationUpdates! :(<===");
}
In my applicationDidEnterBackground
, I have the beginBackgroundTaskWithExpirationHandler
function as follows:
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"ending background task. Background time remaining: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
//Do I need to uncomment the 2 lines below?
//[[UIApplication sharedApplication] endBackgroundTask:bgTask];
//bgTask = UIBackgroundTaskInvalid;
}];
So now, my biggest question is: What have I still not done yet/done wrong, that doesn't allow for background execution?
[[UIApplication sharedApplication] backgroundTimeRemaining]
remaining time.CLLocationManager *locationManager;
. When my app goes into the background, I make [locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
and then [locationManager startUpdatingLocation];
just to keep the app running in the background. A timer changes [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
when at the interval as stated above, and change it back to [locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers]
after that. All this is when the app is in the background, [locationManager stopUpdatingLocation];
only if the app is in the foreground. Do I actually need to keep the locationManager running so the app remains active in the background?applicationWillResignActive
and applicationDidEnterBackground
will be called nonetheless.beginBackgroundTaskWithExpirationHandler
in the correct place?[locationManager setAllowsBackgroundLocationUpdates:YES];
in the correct place (currently in the AppDelegaate)? Help is very much appreciated. o/
Upvotes: 1
Views: 538
Reputation: 41
Alright, so I have asked this 1 year ago and have not received any responses...
When I first asked this question, my intention was to turn off the GPS once the app has obtained the coordinates. So in pseudo code, the logic should go something like this:
applicationStart()
{
startTimer();
}
startTimer()
{
timer repeats: TRUE;
timer cycle: 60 seconds;
function to call: getGPS();
}
getGPS()
{
GPS start;
retrieve coordinates;
send coordinates to server;
GPS stop;
}
By doing this, I intended to save battery power, as GPS is a battery draining feature. However, by doing this, there is no guarantee that the GPS would constantly run in the background. On top of that, as I have mentioned, the results of running such logic is non-deterministic; sometimes it would run, sometimes it would not.
In the end, my current code goes as such (in pseudo code):
applicationStart()
{
GPS start;
GPS accuracy 3 kilometers;
startTimer();
}
startTimer()
{
timer repeats: TRUE;
timer cycle: 60 seconds;
function to call: getGPS();
}
getGPS()
{
GPS accuracy best;
retrieve coordinates;
send coordinates to server;
GPS accuracy 3 kilometers;
}
Notice that I do not actually turn off the GPS; in lieu of turning it off, I make it run constantly, but changed to [locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers]
when I do not need it.
Of course, I am still open to a better solution. At the point of asking this question, I was running iOS9. My above solution works on iOS10 right now, and with iOS11 round the corner, I'm not sure what other changes Apple will be bringing to the API relating to GPS.
Battery consumption? Well, so far so good; My users are not complaining.
Upvotes: 1