Stopping CoreLocation background updates - iphone

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.

Related

Using both startUpdatingLocation and startMonitoringSignificantChanges?

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.

Use of Standard location service for tracking traveled distance in a foreground/background app

I have to develop a kind of GPS navigation application that needs to constantly keep track of the position of the user, which is moving by car.
In the specific, I don't have to display the current location on a map but just to record its position with the best possible precision in order to calculate the total distance traveled.
Of course the application needs to continue its work in background if the user switch to another app, a phone call come in or something like that…
From the tests I have made and from what I have learned from this useful post (and from the documentation), it seems to me that the best choice in this case is the Standard location service, with the application configured with the UIBackgroundModes = location in the .plist file.
In this way it will continue to receive the location updates even if in background and it will never be suspended by the OS (this is actually true only if [locationManager startUpdatingLocation] has been called). This is also confirmed by this guys.
I have personally verified that is true simply by running the app with Instruments and the Memory monitor module where you can see the various flags about the app states, putting the app in background first with UIBackgroundModes set to location and startUpdatingLocation active, and after without it.
1) I'm now wondering what to do when the app is terminated when it is tracking the position. I don't want to loose any location updates so I need to wake up it again whenever a new update is available.
The documentation say:
Important: The applicationWillTerminate: method is not called if your
app is currently suspended.
But because in my case it will be never suspended (it will stay in background but not suspended), my logical conclusion is that applicationWillTerminate will be always called and so I could register for a Significant location update or Region monitoring inside of this method in order to be waked up and then restart the Standard location service.
Is applicationWillTerminate the right place to put this code?
2) An application working in background but not suspended could be terminated by the OS for no other reasons than a very low memory condition or for my app don't properly respond to a memory warning? (the user could also manually close it). I was concerned if applicationWillTerminate wouldn't be called in some way.
3) Could Apple not approve an app which constantly use the standard location services in background because of its quick battery drain?
Have you ever had approve problems for similar apps?
since you are asking many questions which you shoukd not do here, i cam give you only aswrs to a part of it.
if the app is terminated, then you cannot restart it anymore.
This is usually the case when the user terminates the app.
Dont worry Apple ( ios) will not terminate your app. your app will not use much memory, games with huge bitmap graphics are more likely to be termin.
evry gps app will drain the bat. that is not a reason for not aproving.
suspended means that app is not in background mode, it is sleeping. you will not receive Gps, so there is no need to call you on terminate. you have to save data before, see the apple docu on background modes and app life cycle.

iPhone running periodical process in the background - battery optimized way

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

applicationWillResignActive impact on application?

I am writing an application that records a users position at regular intervals whilst walking. I am using an NSTimers to schedule "startUpdatingLocation" followed by calling "stopUpdatingLocation" shortly afterwards to save as much battery as possible.
I want the user to be able to start the application and lock the phone thereby putting the application in an inactive state. My question is when this happens my application (when running via Xcode) seems to continue as normal, but I am curious if there are any differences in the way the application runs in this state as apposed to when the application is running as active?
From the docs it only mentions "applicationWillResignActive" with regards to the application passing through that state on its way to the background. I am more interested in how an application behaves when a used locks the UI and puts the phone away, I just want to make sure its going to keep doing what it should be doing or do I need to take extra measures?
When you app hits applicationWillResignActive it can continue to receive location updates if you use the UIBackgroundModes option in your apps info.plist.
Add the location key.
It is important that you do not use a timer in the background as timers will run but hold their "fire" until the app becomes active again. Thus you will only get one read when the user comes back to the app. The GPS location accuracy level is what will drive how much the battery is affected.
In your app description in the App Store, Apples requires:
Continued use of GPS running in the
background can dramatically decrease
battery life.
You app will not be allowed to go live until the above text is in the description for the user to read.
You should definitely be testing this on a device. The simulator doesn't auto-lock, for instance.
applicationWillResignActive is called when the user presses the home button, when another app fires a notification the user accepts (including when a call comes in), and when the device locks.
Look into the multitasking documentation, and what it has to say about background location updates.
My suggestion is that you conserve the user's battery by:
- starting a timer, which when fired, starts location updates (and stops the timer)
- when you get an adequately-accurate position record, stop location updates and restart the timer
- if location updates fail, restart the timer for a longer period. Maybe they're underground.
The most efficient approach is using significant location update service while your application is in the background or the screen is locked on your app. You might get one update every ten minutes or so.
Remember also, the user can disable your app's location services permissions. Especially these days...

Periodically 'ping' the iPhone GPS?

I'm trying to create an app similar to TravAlert which apparently 'pings' the GPS periodically to figure out where you are. Unfortunately, I'm having a heck of a time figuring out how to do it.
I can't use an NSTimer to fire off the GPS checks because NSTimer doesn't run in the background (which this app presumably must do). I can't use Local or Push notifications as "timers" because they automatically come with a notification and I don't want the use to know every single time that the GPS was queried.
I also tried using CoreLocation's startMonitoringSignificantLocationChanges and that works to a degree, but I can just see the case where the user happens to be in a region of poor cell service (apparently startMonitoringSignificantLocationChanges uses cell tower triangulation as a means of determining location) and thus the app fails to fire.
Any idea how TravAlert does it?
Thanks!
P.S. I'm not trying to rip off TravAlert by making a better app - this is for a college class and unfortunately neither my professor or anybody else in my class has the faintest idea as to how to replicate TravAlert's GPS "ping".
startMonitoringSignificantLocationChanges is the right choice for your app. You can get finer detailed location whilst your app is running. The other option to run the GPS in the background is intended for navigation apps hooked up in a car due to high power consumption.