iOS region monitoring, to monitor more than 20 locations - ios

I did lots of google search but haven't found any solotions that match my need.
So I came up with my own solutions but not sure if it's feasible or not.
I need to monitor more than 20 regions. So at the first time, I'll start monitoring the current user's location and I get 19 other available locations that I can monitor, let say the radius to monitor is 100 meters. So right now the delegate didEnterRegion should be called? I don't really care about this. But when user moves more than 100m from original location, delegate didExitLocation will be called, and by this time, I'll update new regions to monitor (by sending new current's user location to server and I'll get list of new regions to monitor), and I will still monitor this new user's location and still get 19 other regions that I can monitor.
Is this solution feasible? Have anyone tried?
Does this solution still work if the app is suspended, and if it consumes lots of battery?

This is actually Apple's suggestion Core Location Programming Guide:
To work around this limit, consider registering only those regions in
the user’s immediate vicinity. As the user’s location changes, you can
remove regions that are now farther way and add regions coming up on
the user’s path.
However, it's not clear how much time you get when didEnterRegion: is called in the background, so it's not clear if you have time to make a server call if running the background. The "significant-change location service" information says:
If you leave the significant-change location service running and your
iOS app is subsequently suspended or terminated, the service
automatically wakes up your app when new location data arrives. At
wake-up time, the app is put into the background and you are given a
small amount of time (around 10 seconds) to manually restart location
services and process the location data.... Because your app is in the
background, it must do minimal work and avoid any tasks (such as
querying the network) that might prevent it from returning before the
allocated time expires. If it does not, your app will be terminated.
If an iOS app needs more time to process the location data, it can
request more background execution time using the
beginBackgroundTaskWithName:expirationHandler: method of the
UIApplication class.
You could try the combination of region monitoring, making a server call in didEnterEter region and then calling beginBackgroundTaskWithName:expirationHandler: to make sure you have enough time. The combination of region monitoring + server calls + background processing is going to hit battery life, though.
EDIT: You could also create "mega regions" of a large area that contain many smaller regions. When the user enters those mega regions, set up and add all the smaller regions you are interested in, and when they exit, remove them.

Related

Getting continous user location and based on that sending information to server

I've got a concept of adding feature to my app which will register user location in interval of few seconds. Then sending this coordinates through cellular or Wi-Fi all when staying active in background. I need to send this in almost real time, so the app can't be killed in backgorund.
I know this concept is very power consuming but it is only a conception.
The conception of getting constant location in backgorund is in this theard https://forums.developer.apple.com/thread/69152
so I think it is possible.
But refreshing only the process in my app of sending coordinates to server it's a little bit difficult. I could not get straight answer that it is possible to set the time interval in which the app will refresh in backgrund.
Is there a method for telling the app how often it should refresh in background?
Apple won't let your app idea onto the app store. They're quite strict about which types of apps are allowed to run in the background, and are allowed to use continuous GPS. (Both of those things really drain the user's battery.) Sending a continuous stream of location updates to a server will also keep the cellular/WiFi transmitter powered up, making things even worse.
For your own experimentation, though, you can probably set up your app to be a navigation app. Those are allowed to keep the GPS "lit" constantly and to run in the background. You could then set up the location manager with the highest accuracy setting and start updating your location.
I don't think you have the ability to control how often you get location updates though. You could create a timer that fires on a regular interval and fetches the current location from the location manager. However I don't think there's much value in that, since you WILL get called when the user's location changes, and fetching the current location more often will just give you the same answers repeatedly.

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.

Processing network calls from background. Is it allowed by Apple?

We are working in a groupon-like app where alerts are displayed to the user when he/she enters in the range of an offer.
The client insists on having alerts even when the app is in the background.
Due to the architecture of the system, the app gets the location of the client at intervals and checks with the server if there is any new alert. If so, the app does some processing in the local database and displays a notification.
APN cannot be used since changes in the server are out of reach for this project.
My question is whether Apple would accept it in AppleStore as I have read different opinions about it and Apple discourages its use as in this extract from iOS Developer Library
http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html
At wake-up time, your app is put into the background and given a small amount of time to process the location data. Because your app is in the background, it should do minimal work and avoid any tasks (such as querying the network) that might prevent it from returning before the allocated time expires. If it does not, your app may be terminated
Thanks
How often does your app get location from the user? According to Apple's Background Execution and Multitasking, if you are getting the location updates on a regular schedule (I think it's less than 10 minutes), your app can still process in the background if you add location to UIBackgroundModes in your info.plist. With those CLLocation coordinates, you can then process your web service requests.
I personally have not done something like this, so I can't tell you for sure if Apple will reject your app or not. However, if everything is within the guideline and requirements set by Apple, I don't see why they would reject your app.
EDIT:
From the Apple doc:
An app that provides continuous location updates to the user (even
when in the background) can enable background location services by
including the UIBackgroundModes key (with the location value) in its
Info.plist file. The inclusion of this value in the UIBackgroundModes
key does not preclude the system from suspending the app, but it does
tell the system that it should wake up the app whenever there is new
location data to deliver. Thus, this key effectively lets the app run
in the background to process location updates whenever they occur.
I guess even if the app is suspended, it will wake up whenever there is a new location data to deliver.
I think you should reconsider your approach for this application. It sounds like you have decided to build a set of features which are not necessarily well informed by, or a good fit for, the characteristics of the devices the app will run on.
You write that "the app gets the location every n minutes" but that's not how iOS location services work. Querying location services for the current location occasionally is a good approach when your app is running in the foreground but that's not an option once it is suspended or terminated. Instead you need to subscribe to location events, at some level of accuracy, and your app will be notified when the device's location changes. There are no guarantees about the schedule on which you receive these events and it varies depending on the accuracy you request and the speed at which the device is moving.
Additionally, obtaining a location is an expensive operation and can quickly drain the device's battery. Burning through a user's available battery power in an hour or two is a very good way to get your app uninstalled quickly. Where possible you should be using the significant location change service to get low accuracy location updates with minimal power consumption. If you need more precision then consider using boundary crossing events for a defined region or at least reduce the accuracy your have requested as much as possible.
With all that out of the way you still need to work within the limited time your app has to run once started by a location update. That's probably not long enough to make a round trip to the server. If a network connection is already active and the device happens to have low latency you will probably get a response some of the time but I would expect to see the app terminated by the OS frequently. When that happens I don't know that you will continue to receive location updates which might otherwise re-launch the app.
Instead of downloading a list of alerts and displaying them locally a better solution might be to attempt to send your current location to the server via UDP when you see a significant location change. That way you can fire off a network request without waiting for a response. Only some of those requests will still succeed but at least your app won't be terminated. You can then process the locations you receive on the server and send push notifications when appropriate.
I realize that you don't seem to be able to make server side changes. In that case the best you might be able to do is pre-fetch alerts for the nearby region when the app runs (and if you ever manage to complete a round-trip while in the background). That way you could compare location updates to that list and not need to fire off a network request on every location update. Unfortunately it sounds like you might be backed into a corner here with no reliable solution available under your current constraints.

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.

How much time is an iOS app given when unsuspended or relaunched by a background service?

I have a location-based iOS 4 app that relies on significant location change monitoring while in the background. Apple's docs state:
At wake-up time, your application is
put into the background and given a
small amount of time to process the
location data. Because your
application is in the background, it
should do minimal work and avoid any
tasks (such as querying the network)
that might prevent it from returning
before the allocated time expires.
Does anyone know how long "a small amount of time is?" Specifically, I'm wondering if I have enough time to call startUpdatingLocation on a location manager in order to get a more accurate fix than what might be provided by the initial location event. (My background location events almost always report their horizontalAccuracy as 1000m.)
If Apple's "small amount of time" would be insufficient for that purpose, am I allowed to call beginBackgroundTaskWithExpirationHandler: from a backgrounded application in order to request more time? I know that usually gives you an additional 600s, which is more than adequate.
Do you absolutely need to find a more accurate fix during application re-launch, or can you do this heavy lifting after your app has been moved into the foreground, and show a "Loading..." type screen while the work happens? That would eliminate any concerns regarding timeouts.

Resources