get an accurate coordinate from didExitRegion - iphone

i'm implementing an app where i need to track user's location by the following:
track user's location while the app is in the background or closed
if the user's location is changed for about 2000 meters i should perform an API call.
my approach for this problem is the following:
the first time the user launches the app i start monitoring for a region using his current location
if the didExitRegion is triggered, i perform the API call and replace the current monitored region by a new region using the current location as the center of the new region.
this works fine when the app is in the foreground as the location that is returned from the location manager is accurate.
But if the app is in the background then the location manager will not return an accurate location since it's running for the first time and the first coordinates that are returned are not accurate.
the question is how can i get an accurate location of the user when the didExitRegion is triggered in the background?
thanks

I have not had a lot of luck with didExitRegion: firing reliably; it often fires much further away than the edge of my region.
I'd suggest you use CLLocationManager's -startMonitoringSignificantLocationChanges, if you just need an API call every 2km or so. If your accuracy/precision is important, just register location services as a necessary background state (UIBackgroundModes in your app plist; you may need to do this to use the significant change API from the background, too), and use the normal -startUpdatingLocation, with appropriate distanceFilter and desiredAccuracy field values on your CLLocationManager instance.

Several things happening here.
You mentioned that the region change trigger is a little variable. This is deliberate; to avoid high numbers of triggers being fired as you walk down the boundary between two regions, there is some stickiness to the triggering, in both time and position.
From the documentation (http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW1)
The system does not report boundary crossings until the boundary plus a designated cushion distance is exceeded. You specify the desired cushion distance for a region when you register it using the startMonitoringForRegion:desiredAccuracy: method. This cushion value prevents the system from generating numerous entered and exited events in quick succession while the user is traveling close the edge of the boundary.
Getting an accurate position is no different from normal. You start up the location manager and wait until you get a location update with the desired accuracy. Shut down the manager and use the position.
Because you're running in the background, you only have ten minutes to do this, and you have to tell the OS that you're doing background processing using UIApplication's startBackgroundTaskWithExceptionHandler. Plenty of documentation on that elsewhere.
Hope that helps.

Related

iOS what is the best way to notify user about event in geofence?

Problem is discussed bellow :
1: User can register multiple events using my app with trigger distance and address.
how can i fire multiple events on the basis of location , when user near by , or leave or cross the registered event place .
where i have to manage the events and alert him.
i am using CLLocationManger delegate method didUpdateLocation for trace the location distance
please help me
iOS native support for Location is expansively explained in Location Awareness Programming Guide. As you go through it, you will see that your didUpdateLocation is nothing but a step in tracking user's location.
That said, there are number of other steps involved:
[locationManager startUpdatingLocation] - Triggers Location Manager to start monitoring for location updates.
didUpdateLocations - Delegate to be notified about location updates. Note that your method didUpdateLocation is valid for versions < iOS 6.
[locationManager startMonitoringSignificantLocationChanges] - fires location update events so that accurate monitoring is available with good power savings.
Region monitoring - this is what you want for geofence requirement.
regionMonitoringAvailable decides if hardware supports monitoring shape based regions.
startMonitoringForRegion method starts monitoring a specific region.
Similarly, stopMonitoringForRegion stops monitoring for a region.
Finally, didEnterRegion and didExitRegion gives you the geofence triggering you want.
That said, there are number of third party iOS sdk providers who provide high level support for region monitoring inside your iOS app. Geoloqi and Parse are two of them. You can visit their api pages to know more about how simplistic or complex their monitoring is, and choose based on pricing,complexity etc.
Nirav gave you a good overview whats included in the API, i concentrate here more on the things you will not find in apple docu:
To detect enter and leave of a geographical area, you can use
Circles, Rectangles and closed Polygons.
You store them with the latitude, longitude coordinates of that geo area.
To detect enter event:
if current location state changes from outside to inside area.
To detect leave event:
if current location state changes from inside to outside area.
calculate inside:
Inside Polygon: search here on Stackoverflow for point in polygon algorithm
Inside Rectangle: use API
Inside Circle: use API: distance from location to circle center < radius

What event will reset backgroundTimeRemaining?

In the context of an application that has been registered to run in the background with the location services, what event(s) will result in backgroundTimeRemaining being reset to its maximum value and will that reset extend the duration allowed for the completion of ongoing tasks?
Based on the experiments I ran on the simulator and hardware, and for the context I defined in the question, backgroundTimeRemaining is reset whenever an internal call from the location library is made to didUpdateLocations (or didUpdateToLocation for IOS<6).
This is what all approaches used to running continuously in background leverage in one way or another.
What are you trying to do exactly? It looks like you want to run continuously in the background.
Or maybe you just want to run a little bit of code when the location updates? Then don't "cheat the system" and run that code when your app is notified of a location change (and run it using beginBackgroundTaskWithExpirationHandler:).

How properly to handle monitored hundreds of regions?

I need to monitor ~400 regions worldwide (some places in capitals with 1-3 km radius). However, there's a limit of monitored regions per app, so I cannot register them all at start. There's no concrete max number of regions in Apple docs, but some say that the safe max number of regions is 10 regions (here).
Apple docs state "To work around these limits, you should 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". So, the questions is how and when to manage those regions?
The main callbacks are didEnterRegion and didExitRegion when using region monitoring. So at start, I though that everytime a user would enter some region, I would receive a notification where I could remove old regions, find relevant closest 10 regions and register them. But the problem will occur in cases when a user will not enter the closest region but will move more far away from them (for example fly with airplane from some place to the opposite place of the planet), and I will never get a change to update the list of monitored regions because didEnterRegion will never be called.
To work around this problem I'm thinking to add monitoring of significant changes because I should get callbacks (notifications) everytime one of the triangular cell towers change. So I could use those notifications to update a list of monitored regions quite frequently. That's it, what are your opinions on that?
The first thought that comes to mind is that if you have ten regions to work with, what you really want to do is set notifications on the 9 closest regions of interest and then one region that's not an actual region, but a meta-region around the current location. That way, you're more likely to receive a didExitRegion callback when the user moves away from the current location. At that point you deregister all 10 regions and repeat the process. (i.e. re-register 9 + meta region based on the new current location.)
As you propose, it also probably makes sense to get as many cracks at updating your ten regions as possible, so sure, adding a significant changes notification seems like a decent approach.
Another option, although probably frowned-upon, would be to tell the OS that your app is a VOIP application. This allows you to register for periodic wakeups. You could use these to update your regions. I don't know to what degree Apple audits the use of this facility, but it's something to try.

Will iPhone location accuracy go beyond the call of duty?

If I set my CLLocationManager's desired accuracy to be kCLLocationAccuracyKilometer (accurate within a kilometer) will the iPhone deliver a better position eventually, when it gets it ? Or will it stop at my desired accuracy. I can't find this in the documentation.
The idea is that I need a fast fix for the location, but then I would like to go more accurate. Will I have to code this myself, or is it done for me automatically ?
I don't know if the following is 100% correct, but I am pretty sure it works like this: the accuracy filters are primarily designed to save energy. So if you specify that kCLLocationAccuracyKilometer is enough for you and the OS is pretty certain that it can locate you accurately within 1 km using triangulation only, it won't even power up the battery-draining GPS unit. So regarding your first question, the location manager will stop as soon as it reaches your desired accuracy.
Regarding the second question: I don't think the accuracy filter has any influence on the time you receive your first location update. The OS often caches your last known location and will deliver that one almost instantly even if you have specified a very high accuracy. Subsequent location updates will get more and more precise.
You should be able to easily test for yourself if this is indeed the real behavior.
Set the best accuracy you need (but not more, because location services consume too much power). LocationManager will call didUpdateToLocation of your CLLocationManagerDelegate every time accuracy is improved. Stop updating location as soon as you can to prevent battery exhausting.
No, it will stop at the specified accuracy. If you request only kCLLocationAccuracyKilometer then the GPS receiver won't be powered on and it will get no better than WiFi or Cell tower triangulation. [The only exception would be if another app in the background (like TomTom nav) already has the GPS on for high accuracy fixes, then you might get the high (<300m) accuracy fixes too).
If you want better you have to request it and you might as well request it immediately, you'll get the fast fix (1000m accuracy) fix right away and in a minute or two you'll get the high accuracy GPS fix (well, it can take 30 seconds up to 10 min depending on several things). No special coding is required, just specify the accuracy you eventually want.

Core Location - problem initialising

I'm looking for a bit of guidance from anyone who has worked with Core Location on the iPhone. My app is almost complete, I'm just trying to finish off one last thing for my client.
My app is to assist users with their workouts. Similar functionality to MapMyRun. It has a timer screen with a Start/Stop button and a Reset button. When the start button is tapped, the timer starts counting and Core Location starts tracking the users progress, calculating speed and distance. The issue I'm having is with core location trying to find the users current location. Scenario below:
Day 1
User has gone out for a jog and uses the app to track their progress, user has jogged for an hour, workout is saved. Everything works as it should.
Day 2
User decides to go jogging again, this time in a different area than yesterdays jog. Lets say 10 miles away. So they start the timer, but core location takes some time to initialise to the users current position. This causes the distance field to jump irrationally as core location tries to determine the current location.
I've explained why this happens but my client is not very happy, they don't want to see the distance field jump, which is fair enough.
So I'm wondering if anybody has a nice solution to initialising core location to the users current location. I could perhaps break the link between core location and the distance field for a certain period of time which will give core location a chance to get an accurate reading.
Any help greatly appreciated.
Regards,
Stephen
Stabilise the readings by reporting "calibrating..." until the position readings roughly match the speed readings, which are generally more accurate than position.
Yeah, CoreLocation and the GPS-tracking really can annoy one.
some time ago someone had a quite similar problem and got posted some ideas and code:
CoreLocation
Pherhaps this helps. But still I would show an activityIndicator untill you got your exact location. And it's not like GPS-tracking is a matter of tenth of seconds... Just explain your client by referencing to navigation systems in cars. Pherhaps he will understand then....
Try to find the user current location before going in to the App. So that you can directly show the users current location with out taking much time.