Xamarin - IOS - CLLocationManager - Timer stops when phone goes to sleep - ios

i have an application that uses the CLLocationManager in the background. It works as expected. I am trying multiple ways to optimize the battery because it needs to provide close-to-real-time location updates. I know that when the CLLocationManager is configured to work in the background, my app wakes-up everytime a location update happens.
So i was thinking about doing something like that: when a location update arrives and my event handler is called, i process the location, stop location updates and begin a timer that will start location updates again after 15 seconds.
This works pretty good as long as the phone is not sleeping or app is in background. When the phone goes to sleep, then the timer stops. Is there a way to avoid that? i was thinking that maybe as i am stopping location updates, IOS considers that the application is not allowed anymore in background so it stops all code execution, but actually i have no clue what is happening. Does anyone have a clue?
Edit: I have tested the below solution from Michal and it works like a charm. Even if the timer elapses in 15 seconds the effect on the battery are great. My app used to consume 50% of battery in a few hours. Now it doesn't even consume 5%.
This is the sequence I use:
Create a LocationManager and set it to work in the background with best accuracy
When the first gps fix arrives, set the accuracy to 3 kilometres and start a timer which elapses in 15 seconds
When the timer ticks set the accuracy back to best and upload to server all the received locations.

Take a look at this page of Apple documentation: pausesLocationUpdatesAutomatically. It describes that you can pause the location updates and then resume it. It it still doesn't solve your problem, then there's an additional note:
For apps that have in-use authorization, a pause to location updates
ends access to location changes until the app is launched again and
able to restart those updates. If you do not wish location updates to
stop entirely, consider disabling this property and changing location
accuracy to kCLLocationAccuracyThreeKilometers when your app moves to
the background. Doing so allows you to continue receiving location
updates in a power-friendly manner.
Maybe you can use this tip and do following:
1) Start with setting accuracy to your actual need (NearestTenMeters)
2) When the location update comes, process it, set the location accuracy to ThreeKilometers, then set a 15 minut timer after which you should change the accuracy back to NearestTenMeters

Related

Background fetch regularly

I want to upload the location in background every 30secs to 1min. Is it possible?
I have found that I can set UIApplicationBackgroundFetchIntervalMinimum. But I looked around this constant to tell the device to fetch about every 30mins. Any way to do that? Thanks.
I don't know the exact purpose of yours for uploading location for every 30 secs. It's not recommended to do so. I think you can go for MonitoringSignificationChanges in CoreLocation framework. It will give you update whenever there is a significant change in location. It helps in saving the battery.
Starts the generation of updates based on significant location changes by the following method:
func startMonitoringSignificantLocationChanges()
This method initiates the delivery of location events asynchronously, returning shortly after you call it. Location events are delivered to your delegate’s locationManager(_:didUpdateLocations:) method. The first event to be delivered is usually the most recently cached location event (if any) but may be a newer event in some circumstances. Obtaining a current location fix may take several additional seconds, so be sure to check the time stamps on the location events in your delegate method.
Fore more info: Apple Docs
Your approach has multiple problems. Most apps are not allowed to run continuously in the background like you want to do. You get ~3 minutes of background time, and then your app gets suspended. Navigation apps are an exception. If your app is a navigation app you are allowed to run continuously in the background.
Polling the GPS every 30 seconds is also a bad idea unless you're a navigation app. You'll quickly drain the user's battery.
Likewise uploading the user's location every 30 seconds will keep the cellular/WiFi radio on the phone powered up nearly constantly, which will drain the user's battery quite rapidly.

What strategy to adopt to monitor the user location in background?

I want to track the user location in background, in the purpose to show him an alert when he is close to one of his friend.
So i start with CLLocationManager. As far as i know their is only one reliable way to let the app know about the location update even if the user reboot the Iphone or kill the app: startMonitoringSignificantLocationChanges. But the problem is that even inside a city with many wifi, startMonitoringSignificantLocationChanges fire the DidUpdateLocations when the user move around 1km and that is really too much for my need
on the other way startUpdatingLocation is firing DidUpdateLocations at good interval (even too much because even when the user do not move it's fire quite often DidUpdateLocations). But startUpdatingLocation not survive to iphone reboot or app being killed by the user. Also I suspect that even with an accuracy of 100m, startUpdatingLocation use lot of battery consumption.
So the question: What strategy i can use in my app to track efficiently without draining too much the battery the user location at full time? I need an accuracy of around 100m and if possible an interval between 2.5 - 5 min for each track (i didn't find any option to specify a delay to wait before to catch a new location)
Actually i think to do something like this :
2 locationManager, 1 GPS and 1 Significant Changes
when app start I do with significantChangesLocationManager: startMonitoringSignificantLocationChanges and startMonitoringVisits
I also call GPSLocationManager startUpdatingLocation to retrieve the accurate user position. I set up PausesLocationUpdatesAutomatically(true) so that the GPSLocationManager will stop by himself soon or late
on DidUpdateLocations raise by the GPSLocationManager I start monitoring region enter/exit (100m radius around the obtained latitude/longiture) with significantChangesLocationManager
What do you think of such strategy ?
Even though you will receive more triggers than you need, as you already said, you can use startMonitoringSignificantLocationChanges. It is implemented in a very energy efficient way. It allows the app to be terminated and only be woken up again when iOS thinks the device has moved significantly. Another advantage would be that your app doesn't need the location background mode, which could raise questions during an app review.
The startUpdatingLocation let's the app continuously update the location of the device, even though you only receive a couple didUpdateLocations: events. Also, iOS cannot shutdown the app while updating is active, so it consumes a lot of battery.
You can also consider geofencing, with an exit geofence around the current location. However, significant location updates will be more reliable. Exit geofences won't trigger anymore once you're already out of a geofence, which could happen when the phone is turned off inside a geofence and turned back on outside. This solution has the same advantage of not needing a background mode.
As far as I understand your use case, startMonitoringSignificantLocationChanges sounds as the best option. You won't have control over the exact time interval and distance it triggers, but it is very energy efficient and easy to use.
As mentioned in comments, here are some approach I had to do in order to get the expected result in our app.
Significant Location Updates - is good to wake your app up once it gets finished by some reason that you can't control, so even if you lose some points, it will get back in some seconds/minutes.
This is not good if you need a good accuracy, as you cannot control the distance / time or whatever, iOS will update locations when mobile antenna is changed, wifi connection, turn air plane mode off and on but will not give a sequence of gps points.
Start Location Updates - Best accuracy but battery drainer. So you can't just turn it on let it go. You must implement some controls over it.
Background tasks - The only way I've found to keep my app alive.
The way you can combine is:
Have 2 location managers isolated, one for significant location change and one for start updating location;
Start your app with both turned on;
Inside your didUpdateLocations you can create your logic to start and stop your background tasks;
Create methods to start and pause your location manager and create your timers to control that;
inside your bg task you will start or pause your update locations, but never stop it, just if for example, your user logs out and you want to stop location;
keep significant location update location manager alive forever, if for some reason iOS decide to kill your app when in bg, it will ensure that in a given moment your app will come back to life;
For battery live, try do not use kCLLocationAccuracyBestForNavigation for accuracy as when it starts it eat a LOT of resources, most of time, kCLLocationAccuracyBest is more then enough and if you can use kCLLocationAccuracyNearestTenMeters;
Your didUpdateLocations will give you mostly a bunch of points, try to get only those with good horizontalAccuracy, around 20 meters for us was good enough, so let it work and once you have a point with good accuracy, you can pause it again.
Below you have some links that helped me a lot to implement our solution, none of those have a "as is" solution, as I said, I had to mix all of them and test a lot to understand its behaviour and make the necessary adjustments.
https://github.com/voyage11/Location
http://mobileoop.com/background-location-update-programming-for-ios-7
http://zaachi.com/2013/09/30/ios-locationmanager-location-update-in-my-own-interval-with-application-in-the-background.html
In addition to Mark's answer I would like you to explore pausesLocationUpdatesAutomatically which can help you save battery from draining when user has stopped Apple Documentation
Allowing the location manager to pause updates can improve battery life on the target device without sacrificing location data. When this property is set to true, the location manager pauses updates (and powers down the appropriate hardware) at times when the location data is unlikely to change. For example, if the user stops for food while using a navigation app, the location manager might pause updates for a period of time. You can help the determination of when to pause location updates by assigning a value to the activityType property.

iOS: How to use location tracking during predefined time period while saving battery life?

iOS: How to use location tracking during predefined time period while saving battery life?
I need to activate location tracking during predefined time periods (does not matter if app in background or foreground) and need to be sure that battery life is not impacted too much?
PS:
Please not that running location in background with tracking significant changes does not suits because it gives you location after 10 min and only when you passed reasonable amount of distance ... so during driving 40 km I got location only 3 times that will not allow me to catch user movement near some point. If running location more often ...that drains battery upto 40 percent per 6 hours...
I've researched all background modes in iOS very thoroughly recently.
The only deterministic way that will allow you to do that, without location background mode are silent pushes.
You send a silent push to the user and the user returns a location.
You could also use background fetch. But it's very non-deterministic. You can't predict if it indeed will wake up your app, or not.
EDIT:
Please note, that this will not wake up the app that was forcefully terminated.
However, the system does not automatically launch your app if the user
has force-quit it. In that situation, the user must relaunch your app
or restart the device before the system attempts to launch your app
automatically again.

How long does it takes to start receiving location updates after iOS device reboot?

I have an app that does geofencing/beacon region monitoring. The app functions well in - foreground, background and killed state.
The problem: I have been noticing a delay in the beacon/geofence events(entry/exit) after I restart the phone(without killing the app) and do not launch the app manually upon restart. I only start getting the entry/exit events after 3-4 minutes of restart, even if I enter the region before.
Is it normal behaviour?
Thanks
This is normal. I have noticed this delay of several minutes since CoreLocation added iBeacon support in version 7. The exact amount of time varies from one hardware model to the next, and even between reboots on the same hardware model.
While it might be possible to statistically characterize the delay with repeated tests, this is very time consuming to do. In the end, there is nothing you can do about it anyway.

Why are SLC updates always 5 minutes?

Both on the simulator and the device, my delegate for LocationManager is getting didUpdateToLocation:fromLocation: exactly every 5 minutes while traveling while monitoring SLC. Why is this?
According to the CLLocationManager Class Reference:
For applications that do not need a regular stream of location events,
consider using the startMonitoringSignificantLocationChanges method to
start the delivery of events instead. This method is more appropriate
for the majority of applications that just need an initial user
location fix and need updates only when the user moves a significant
distance. This interface delivers new events only when it detects
changes to the device’s associated cell towers, resulting in less
frequent updates and significantly lower power usage.
My guess is that when your app is running in the background, iOS only "wakes" the app every 5 minutes to check whether you have made a Significant Location Change, in order to conserve battery life
There might be some useful information for you also in this previous question.

Resources