I want to run a specific task in the background. This task takes few seconds to complete (it writes some GPS location data to a file). This task should run once every 1 hour.
As I understand from the SDK, I do not have a way to INITIATE something in the background unless I run Location Services forever. When this service runs, it gives me an event from time to time, and I'm able to run my code during these calls. I tried it, and even with the minimal precision possible, my battery goes down very quickly.
So, I'm looking for a way to run Location Services for few seconds every hour. All the rest of the time I do NOT want to run Location Services and I do NOT want to use the battery.
Can you help here please?
Thanks,
Gena
What do you actually want to know every hour? Are you trying to determine the location accurately, or just determine if the phone has moved significantly? startMonitoringSignificantLocationChanges will notify you when the phone moves "significantly" (which generally means changing cell towers). In cities this can happen quite often. startMonitoringForRegion:desiredAccuracy: will only notify you when you move outside of a given radius.
startMonitoringSignificantLocationChanges is pretty cheap. It mostly relies on the cell antenna, which is generally on anyway. If it fires more than once an hour, you could always just skip processing and return. But there's no guarantee that you'll be called once an hour, particularly in rural areas.
If you are a VoIP app, then you may register a periodic "checkin" interval when you may run code. But you cannot do this for location apps.
Have you profiled your code using the Energy Diagnostics instrument? What's actually eating time and power? Are you chewing on the radio, the CPU, the disk?
EDIT
When the app dies, Significant Changes still continue to run and leave a small direction arrow icon next to the percentage on the top toolbar of the iPhone. My users complain that the icons remains after killing the app
After the app dies, if you were registered for significant changes, you would expect to be relaunched in response to them. If you want to unregister in cases where you are terminated, you can add stopMonitoring... to your applicationWillTerminate: method. This isn't guaranteed to be called, but it is a good thing to do, and I believe it will be called if the user terminates you directly and you were not suspended (haven't tested that).
Again, significant location changes should be extremely cheap in terms of battery life as long as there is cell coverage. They should not force the GPS to stay on.
Your best bet is to use significant location changes ... here are some links you can get help from -
http://developer.apple.com/library/ios/#documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html
http://www.switchonthecode.com/tutorials/getting-your-location-in-an-iphone-application
http://longweekendmobile.com/2010/07/22/iphone-background-gps-accurate-to-500-meters-not-enough-for-foot-traffic/#more-480
Related
Is it advisable or any issues with calling both startUpdatingLocation and startMonitoringSignificantChanges vs. one or the other? I understand the benefits of the significant changes call re: battery life, but when using it am seeing inconsistency with it firing the didUpdateToLocation, sometimes doesn't fire at all even though I know I've setup locations where I know it should fire when I'm at the location but doesn't. I'm able to verify my results for my app vs. another app that does very similar behavior, including both mine and the other app running in the background (UIBackgroundModes does have the 'App registers for location updates' setting in the plist). If I try using just the significant changes, the results are not consistent. If I use both, I get accurate results + the added benefit (need) for getting notified if/when the app is terminated. I want to not kill the battery life by using the startUpdatingLocation, and have tried calling the stopUpdatingLocation and then subsequently calling the startMonitoringSignificantChanges in the applicationDidEnterBackground in order to help conserve battery life while in the background, but can't seem to understand why relying on the significant changes is not working consistently.
Apple suggests that you use -startUpdatingLocation while your app is in the foreground, and -startMonitoringSignificantChanges while in the background. Using both while the app is in the foreground is likely just a waste and more likely to be more work to handle the events than just monitoring -didUpdateToLocation. Upon backgrounding, you can switch off the GPS mode and switch to something more low powered. You have to assume that the user won't care as much for accuracy once you've been backgrounded or closed.
I am trying to set up an app that will be able to check people's locations in the background, see if they are at a given location, and send a ping to a server if they are. We do not want to drain the energy of our users, so we are attempting to figure out the best solution.
I've done substantial reading and I have not found very much information on these methods. I'll go through the pros and cons as I understand them right now
startMonitoringForSignificantChanges
Description: Based off of wi-fi and cell tower changes the system wakes up the app.
Docs:
Apps can expect a notification as soon as the device moves 500 meters
or more from its previous notification. It should not expect
notifications more frequently than once every five minutes. If the
device is able to retrieve data from the network, the location manager
is much more likely to deliver notifications in a timely manner.
Pros:
Most battery efficient
Cons:
Dependent on wi-fi/cell tower changes
Can only assume that this will be called every 200m to 2km (if not more in certain areas)
More on accuracy
Thus, inconsistent and imprecise
10-minute start-updating or "n-minute updating":
Description: This basically asks the app for more time, when that extra time is about to expire, it calls [self.locationManager startUpdating], grabs the location and extends the background thread for 10 more minutes.
Pros:
Consistent
Can be as accurate as you want it to be as consistently as you
want it
Cons:
Has to do a call every ten minutes or less to keep the app running in the
background (ie n can't be greater than 10 for the calls)
Questions:
What effect does this have on the battery? Does waking up the GPS and shutting it off hurt the battery more? I couldn't imagine running a brief location check in the background would drain the battery that much... but then again, I don't know what goes into powering up the GPS and getting a usable signal.
startMonitoringForRegion (geo-fencing):
Simply put, your app gets woken up when you enter into a pre-defined region. This is the oddball of them, it is more recent and there is less documentation on it. I can't find a good description on how the "system monitors" the boundary crossing. For all I know it is some really smart algorithm, or they are constantly pinging the GPS which would make it less effective than the other methods for doing this.
Pros:
Simple implementation
Managed by the system so you don't have to invent your own ad hoc geo-fences Only triggers on boundary crossing... no unnecessary data to just throw out in exchange for a battery hit
Thus, should be the best for this sort of thing, accurate, managed by the system
Cons:
People question its effectiveness
Huge conflicts on whether or not it is good for battery life or if it
drains battery life terribly.
How is the system monitoring this!?
Basically, indeterminate behavior.
I guess my question boils down to how does startMonitoringForRegion: compare to these other methods of testing user location in the background when it comes to battery life, consistency, and precision. Has anyone thoroughly tested this? Or used it in their app and gotten at least some feedback? Likely, for my purposes, the trade-off is between geo-fencing and the 10 minute update method. (Also given what Apple has publicly said about iOS7 there will be some background tasks... will this change the calculus for the trade-off between these two methods?) Does anyone have an idea of how these two compare?
Thanks so much! Looking forward to seeing if we can get to the bottom of how to compare these methods.
I've been working on vehicle tracking using GPS for 2 years. Learned a lot the hard way... In my experience startMonitoringForRegion or Geo-fencing depends upon cell change events, didEnter or didExit events doesn't fire up until there is a cell/wifi change event. So it doesn't make any difference w.r.t battery consumption. However it does extra computation which depends on how many regions currently are being monitored. Even Apple's Reminder app doesn't give good results for location based reminders because it uses geo-fencing.
The other approach starting GPS for n minutes after each m-minutes is good option, it should not affect the battery life, if done wisely. What exactly effect the battery is constant GPS activation in high precision mode. Like for instance If you enable GPS with kCLLocationAccuracyBest and distance-filter = 0, you can literally observe battery drainage and soon your device will also start getting hotter.
If I was you, I would go for activating GPS after every 10 minutes for 5 sec with kCLLocationAccuracyBest (or may kCLLocationAccuracyNearestTenMeters to use less battery, if accuracy is not that much important) and distance-filter = 5 (meters). Battery consumption in this case will be unnoticeable. You can play around with similar settings which can address your specific case and finally find out what is best you.
BTW: iPhone uses AGPS, A-GPS additionally uses network resources to locate and use the satellites in poor signal conditions. So, when you do startUpdatingLocation it will also use nearby cell tower information. see http://en.wikipedia.org/wiki/Assisted_GPS
I want to create an (game based) iPhone application which sends your GPS location on a specific time (like 3-5 times a day) to a server. I found an apple page explaining some functionality to run in the background like location, music and VOIP.
I need the GPS to be accurate on the meter.
Can someone help me with a small example?
It really depends on your usage of the location. If you monitor actively, kiss the battery of your user goodbye. Very detailed accuracy, even bigger hit to battery. The backgrounding of location is all or nothing as far as accuracy goes.
Less hit, less accuracy is -startMonitoringForSignificantLocationChange. May not be accurate enough for you.
Better depending on usage, region monitoring. Triggers event on entry or exit of defined region.
You don't have the benefit of accuracy and timed location based events. You can do it, but is going to require a lot more effort on your end.
While this is untested, I am planning an app with a similar need. My solution is that on a significant location change, the app will determine what interval exists between the update timestamp, and when I care to know the users location (5pm for instance). If that's below some threshold, it will go into startUpdatingLocation mode (full power, battery draining, which is why that threshold is important) and then, on each location update, check if that target time has passed. if SO, send the update to your server, and go back to monitoring for significant changes. The catch is that if it still requires some movement to trigger the significant change update...so it isn't a perfectly reliable solution, but it may work depending on how you're using the data
You can't "schedule background work". iOS doesn't allow it.
The solution is to set yourself up for notification on significant change (which is some hit to the battery, but it's not horrible), and then only DO anything with that at occasional intervals.
A common exploit in casual games is to artificially advance the system clock to jump ahead in gameplay. How can such user clock advancement be detected by an app on an iOS device?
Must not involve network communication
Must not assume app is open (running or suspended) while clock is advanced
Must detect clock advancement, detecting clock rollback is not sufficient
Ideally, the solution would be robust against reboots, but that is not a requirement.
CACurrentMediaTime & mach_absolute_time
Take a look at this questions:
iOS: How to measure passed time, independent of clock and time zone changes?
Calculating number of seconds between two points in time, in Cocoa, even when system clock has changed mid-way
CACurrentMediaTime uses mach_absolute_time:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreAnimation_functions/Reference/reference.html
Here you have an example on how to use CACurrentMediaTime:
http://www.informit.com/blogs/blog.aspx?b=02b4e309-308c-468a-bab1-cebb1404be6a
Here you have a more information on mach_absolute_time:
http://developer.apple.com/library/mac/#qa/qa1398/_index.html
http://shiftedbits.org/2008/10/01/mach_absolute_time-on-the-iphone/
I was thinking about the fact that the CoreLocation stuff could do this if that part of the GPS data was exposed to you. However that got me thinking.
My only (far fetched) suggestion is to put something into background processing - which has to be for one of a small specific set of reasons, for example to track location in the background. As a side effect of that, try to detect a clock change on a regular timer. Apple might reject it as it may be clear that its not using the location information and its just a reason to exploit background processing.
Any solution not involving networking is so much harder to implement, I wonder why you're not using it.
Whilst I don't think it's possible to reliably determine whether or not a user has manually turned their clock forward without network access, you can of course reliably determine if they've travelled back in time. And since we know this to be physically impossible it can therefore be assumed they have manipulated their clock to cheat.
What I mean by this is, isn't the usual process to trigger some action in-app that requires a period of waiting, exit the app and turn the clock forward, re-launch the app to gain whatever they were waiting for and then reset the clock back to the actual time?
If this is indeed the case, then to build on the suggestion by #smgambel, you could store the physical time and current time-zone on each launch and compare with the previously stored time and time-zone. If the time is behind the previously stored time, and the time-zone of the device hasn't changed then you can safely assume the user has manipulated the clock.
My app registers for background location updates (not Significant Change. I need more granularity than kilometers)
That part works fine. I just want to stop the updates after the app has been in the background for 60 minutes. The way I'm doing it right now is to call stopUpdatingLocation in my CLLocationManager delegate.
However, I am unsure if this will actually stop my app from receiving background location updates, or if it will, but will just ignore them. Ideally, I'd like to not have my app be responsible for battery drain except for a small period of time after user activity.
Apple's documentation tends to send me in circles on this one. Right when I think "Executing Code in the Background" is about to spill the answer, it directs me to "Location Awareness Programming Guide." Right when that one is about to get specific about this question, it sends me back to "Executing Code in the Background." :)
I'm not sure whether your app has total control over this, but the docs for stopUpdatingLocation do state the following ...
Disabling event delivery gives the receiver the option of disabling the appropriate hardware (and thereby saving power) when no clients need location data
Which would suggest that should your app be the only one requesting background location data, and you request it to stop the GPS receiver would disable the appropriate hardware to save on power, which I think it was you're looking for.
What I can suggest is that you enable Power logging in Settings -> Developer, then run your app for an hour or so to a point where you think GPS is disabled, run for another hour and then compare the power usage in Instruments. This should provide you with a much clearer picture.
Calling stopUpdatingLocation will indeed stop GPS and so on, but if you place this call inside locationManager:didUpdateToLocation:fromLocation of your CLLocationManager delegate, then it might never be called.
Keep in mind that this method is only executed whenever a more accurate position or a (according to the active distance filter) significantly different position is available. If the device does not move at all and if the circumstances affecting the accuracy also do not change, it may not be called for hours (I have verified it for several minutes myself) and GPS will also stay enabled for this long.
For apps that only work in the foreground, you can use an NSTimer of 60minutes, but for apps that run in the background, the closest to a working solution that I have found so far, is a scheduled UILocalNotification. But even that requires the user to confirm an alert, before the app is restarted and able to turn the GPS off.
Maybe beginBackgroundTaskWithExpirationHandler: is the key to a better solution, but I have not completely figured it out, yet.