iOS Geofence CLCircularRegion monitoring. locationManager:didExitRegion does not seem to work as expected
Asked Answered
F

9

30

I am currently trying to get my app to monitor particular regions using CoreLocation however I am finding that it does not seem to work as expected, it seems to me that it cannot work with small a small radius set for each location i.e. 10m.

I've also put together a little test app which plots the circle radius on a map so I can visually see what is happening.

The code I am using for monitoring locations is as follows:

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;

// Set-up a region
CLLocationDegrees latitude = 52.64915;
CLLocationDegrees longitude = -1.1506367;
CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(latitude, longitude);

CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:centerCoordinate
                                                                 radius:10 // Metres
                                                             identifier:@"testLocation"];

[self.locationManager startMonitoringForRegion:region];

I have not put up the code here for DidEnter region etc as I know that works when I go over 100m away from the monitored region.

Here is a screen shot of the app when I am well over 10 meters away from the purple location on the map, the did exit region events do not fire, however if I switch my location to London it fires and also when I set my location back to where the blue location is currently it also fires.

Example Region

Does anyone know if there is a limitation with the minimum region radius at all or perhaps I am doing something wrong.

Thanks Aaron

Figone answered 26/5, 2014 at 8:40 Comment(4)
I think 10 meters is just too short a distance to account for normal fluctuations in the location accuracy.Holdup
Thanks for the reply I did bump up the radius to 100m however I still can't get the exit and entered notifications unless I actually move my location over 100m away.Figone
100m might be too far away, for the suburb you live in. Try 5000 meters and it will work, unless you have a bug in your code, then make it smaller and test it as you go down.Outgoing
@AaronWardle Not the answer you want to hear, but this seems to be a bug in CLLocationManager. I can consistently reproduce the issue using a variety of different region radii. See the attached test harness in my answer below.Konopka
A
61

I don't think region monitoring will work well for such a small radius.

  • The best accuracy with the GPS chip and kCLLocationAccuracyBestForNavigation is often just 10 meters.
  • Apple says (in the Location & Maps PG) that the minimum distance for regions should be assumed to be 200m
  • I've heard that region monitoring is using WiFi to get it's position (which makes sense for power savings). WiFi accuracy is more like 20m-100m. I'm not sure how having another app using background location (i.e. using GPS) would affect this. Probably, the location manager would share information to make the accuracy better.
  • Region monitoring can take 30 seconds to fire once inside a region, and a couple of minutes to fire after leaving a region (to prevent location glitches from triggering it).
  • When region-monitoring was first introduced, they said that it would only work with 100m regions and anything smaller would be bumped up. This probably still happens.
  • There's a deprecated method startMonitoringForRegion:desiredAccuracy: which allowed you to specify the distance past the region border to start generating notifications. Presumably this feature has been rolled into startMonitoringForRegion: but is still there. A 10m region might end up with a 10m buffer.
  • If you want to do this, specify a larger region around where you want to monitor, and when the device wakes up in that region, start background location updates (GPS) and use CLCircularRegion's -containsCoordinate: to trigger when the device is within 10m manually. This method is officially sanctioned by Apple (see WWDC 2013 Session 307).

From the CLCircularRegion docs:

Remember that the location manager does not generate notifications immediately upon crossing a region boundary. Instead, it applies time and distance criteria to ensure that the crossing was intended and should genuinely trigger a notification. So choose a center point and radius that are appropriate and give you enough time to alert the user.

From the Location & Maps PG:

Region events may not happen immediately after a region boundary is crossed. To prevent spurious notifications, iOS doesn’t deliver region notifications until certain threshold conditions are met. Specifically, the user’s location must cross the region boundary, move away from the boundary by a minimum distance, and remain at that minimum distance for at least 20 seconds before the notifications are reported.
The specific threshold distances are determined by the hardware and the location technologies that are currently available. For example, if Wi-Fi is disabled, region monitoring is significantly less accurate. However, for testing purposes, you can assume that the minimum distance is approximately 200 meters.

There's further inside scoop from this post by Kevin McMahon, who asked the Core Location engineers about region monitoring at a lab at WWDC 2012. This info will have changed in the meantime, but the part about region categories is interesting. Here's an edit:

Fine Region (0 - 150m)
- With the floor of 100m this category's range is effectively 100-150m.
- For regions this size performance is heavily dependent on the location-related hardware
- The amount of time that it takes Core Location to detect and call the appropriate delegate method is roughly 2-3 minutes on average after the region boundary has been crossed.
- Some developers have figured out independently that smaller regions would see quicker callbacks and would cluster smaller regions to cover one large area to improve region crossing notifications.

Anglonorman answered 29/5, 2014 at 10:46 Comment(9)
This post should be protected.Cerelly
This was awesome! 1. so technically if I disable my wifi would it then fall back to using GPS data and become more accurate? or it would fallback to cell towers? 2. What is the range of cell towers? 2km? 5km? 50km? 3. I'm guessing normally in a city you'd get 3-4 towers so you can triangulate the best right? What happens if you're in the middle of nowhere...have cellular data, but there is like e.g. just 1 tower in the entire area? Would it still be able to triangulate your data or it would again fall to using GPS and become more accurate?Provocative
@Honey, I have selected 50 meters radius and 'upon exit' notification should come. But I am getting a notification on/around 250 meters and some time more than this. Please help me outKampala
@nevan king, is it normal behavior of Geo fence did exit region? As I have tested the Raywendelich tutorial project and it is also working same as per my app (i.e I have selected 50 meters radius and 'upon exit' notification should come. But I am getting a notification on/around 250 meters and some time more than this.). In ray's app, I have set radius 10 but I got notification around 250 metersKampala
@Kampala yes it's expected. Did you see my answer here? Apple docs says it could up to 200 meters. ( And the longer you wait outside the 200meters the more likely you'll get a notification. It's not necessarily 250 meters...it could be 200meters + 30 seconds and since you get to 250 meters after 30 seconds you conclude differently) Radius 10 is also nonsense. I believe anything lesser than 100 meter gets just rounded up to 100. Geofence is not very accurate because it needs to be battery efficient. Still an effective for the right scenarioProvocative
@Honey, thanks for your quick reply. I also observe it is not a better approach, is there any other thing that we can use to achieve accurate functionality? Yes, I have checked your answer, I have searched a lot, but similar things came up. Need to convey client regarding this, but he is expecting an accurate result, this not possible with Geofence.Kampala
@Kampala communication with client is key. Tell them the alternative is to use more battery ie use normal location tracking and then you can just calculate the distance yourself for all your regions...but let them be the one who makes that decision. That being said many companies use geofence to find stores etc.Provocative
@Kampala I forgot to mention this explicitly. After all your discussion, and explaining the limitations of each let your client make the decision to choose which one.Provocative
Shall we still consider those 200m in 2022 or can we go down to 50/100 does anyone know?Jojo
K
25

This seems to be a bug in CLLocationManager. I've done extensive testing using various region radius configurations and locationManager:didExitRegion does not fire in an expected way. This seems to be either a rather nasty bug or region monitoring does not happen at all like the documentation suggests. I have the test harness available to anyone who wants it:

http://www.mediafire.com/download/x863zkttltyalk6/LocationTest.zip

Run it in the simulator and start the test by by selecting Debug -> Location -> Freeway Drive in the iOS simulator menu. The number you see is the distance from the center of the monitored region. The background color will be green while the device is within the monitored region and red when outside the region. The text below the distance are event logs.

enter image description here

After running the app, you should see locationManager:didExitRegion fire at 5319 meters from the monitored region. The route will loop every 37 minutes and you'll see the device exiting the region always at 5319 meters.

I've submitted a radar with Apple (17064346). I'll update this answer once I hear back from them. At least then we'll have some input from the canonical source.

Here's the detailed text sent to Apple:

Using a test app on the iOS simulator as well as on an iPhone 5S the CLLocationManager doesn't seem to fire didExitRegion callbacks in an expected way. Regardless of the radius of the circular region being monitored, the callback won't happen until a threshold of around 5000 meters is hit.

Steps to Reproduce:
1. Run the attached app
2. Start region tracking by selecting Debug -> Location -> Freeway Drive in the iOS simulator
3. Monitor the app. The large # indicates the distance from the center of the watched region.
4. After about 190 seconds and 5300 meters didExitRegion will finally fire.

Ths issue does not seem to be related at all to the size of the region. According to the Apple docs, even small regions are supported:

In iOS 6, regions with a radius between 1 and 400 meters work better on iPhone 4S or later devices. (In iOS 5, regions with a radius between 1 and 150 meters work better on iPhone 4S and later devices.) On these devices, an app can expect to receive the appropriate region entered or region exited notification within 3 to 5 minutes on average, if not sooner.

Although region events don't happen instantaneously, they should happen fairly quickly. From the Apple docs:

Region events may not happen immediately after a region boundary is crossed. To prevent spurious notifications, iOS doesn’t deliver region notifications until certain threshold conditions are met. Specifically, the user’s location must cross the region boundary, move away from the boundary by a minimum distance, and remain at that minimum distance for at least 20 seconds before the notifications are reported.

This is not at all what I am seeing in the test harness. On the simulator the device will always be 5000+ meters away from the region before a locationManager:didExitRegion event occurs.

Konopka answered 29/5, 2014 at 14:32 Comment(5)
I'm seeing the same behaviour. Hopefully Apple has a workaround. I can't access the bug report from the link you provided. Is it available to anyone or to yourself only?Sapajou
@Ruckstar Unfortunately Apple bug reports are private. If you are seeing the same thing though, you should submit your own report and reference my radar. Hopefully, Apple will provide some feedback on the report sometime in the near future. I'll update the answer when they do.Konopka
Any idea if iOS 7.1.2 has any effect on this behaviour?Sapajou
@MichaelG.Emmons this test harness is awesome. I moved the region center to 7.7km along the freeway drive and tried it with a bunch of different radii. Here is what I came up with: docs.google.com/spreadsheets/d/…. It seems like your speed can drastically change the characteristics of how the region is treated. I tried to verify this with the slower bike ride simulation but I was unable to leave the region in that case...Ceciliacecilio
In any case it seems like there are a variety of factors that can affect when regions are delivered and it's best to test this in field with real devices.Ceciliacecilio
E
17

I like the answers by both Michael and Nevan. I would like to add more information from my personal experience/opinion in developing Location Based iOS Application with Region Monitoring and also highlight some important points:-

Be realistic on Region Monitoring

Region Monitoring is using Global Positioning System (GPS), Wifi and other technologies to determine if the device is inside or outside the monitored region. Don't forget that our earth is 510 square kilometers and about 30% are land (149 million km2). It is a huge area. Remember the recent MH370 missing case? Our current most advance technology could not even pinpoint an estimated region of that missing plane.

If you want to monitor for a small region with only 10 meter radius. It could possibly work inside a highly dense city with a lot of cell towers and wifi connected areas. But at the same time, the signal might be blocked by high rise towers which might cause the signal loss for a few seconds/minutes which caused the delay in delivering the notification.

So, you really have to consider the above information before deciding how big is the region that you want to monitor. Personally I think 10 meter radius is too small.

Be Realistic on the Number of Monitored Regions

The current Core Location technology can only monitors up to maximum 20 regions on a single app. Make sure that the monitored regions are not too close to each other as well.

I personally have tested 3 regions that are about 100 meters in radius which are about 200 meters aways from each others. Sometimes I can get notifications from all these 3 regions when I am driving through them, but sometimes, I can only get the notification from the First region only. What could be the reason? I could not know. The regions might be too close to each other. Or the cell towers decide that my device does not actually inside the monitored region.

There was one person on StackOverFlow who wants to monitor 1800 points on our Earth. Don't be like him as he is quite unrealistic and probably does not understand the limitation of current Core Location technology. Link: Check if the user location is near of some points

Fine Tune The LocationManager

If your app needs to monitor a small area or needs the location update frequently. Here are the potential properties of your location Manager.

self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;

kCLLocationAccuracyBestForNavigation will consume more battery compare with kCLLocationAccuracyBest. But, it will be more accurate.

I found a glitch in region monitoring in iOS 7 when there are multiple notifications triggered at the same time in different monitored regions. I have found a solution to filter out this glitch. For more info, please visit: Region Monitoring Glitch on iOS 7 - Multiple Notifications at the same time

Don't Be Over Ambitious

You might have used some apps which can monitor a small region and are very accurate and able to notify your the same second you step into the region. And you have the inspiration to develop the exact same app to compete with them. But do you understand what happens behind scene? What additional technologies that they are using? And what partners that they are collaborating with?

I have done some research on that and found out that some of the technologies that they use are not available publicly. Some of those companies are heavily funded and could pay a premium to the telecommunication companies in order to get the best location accuracy for the best user experience. I do not understand the details on how it works. I believe most of the location determination is actually on the server end (back end), not the mobile (front end).

So, the apps that are developed by those companies not only can pinpoint the best accurate location but also does not consume a lot of battery.

NOTE: I just want to share my 2 cents. The above information consists of my experience and personal opinion. It might not be 100% accurate as I am still learning Core Location and Region Monitoring.

Electra answered 3/6, 2014 at 3:51 Comment(0)
S
6

I do agree with Michael G. Emmons, and want to share my experience too:

I tested my code with three regions as shown in the image below:

enter image description here

Explaining the behaviour:

  • My current location is Region-1, and i start monitoring for the above three regions, and call to requestStateForRegion, to determine, if there is any region inside, where i am currenly standing.
  • Then i get "Enter" notifications, for first two region (region-1, and region 2), but it should only detect the region-1.
  • Now when i enter in region-2, i get the Enter notification for region-3. but i should get the notification for region-2 here.
  • Now when i enter in region-1 again, i get the Exit event fired for the region-3, and this continues.
  • but i don't get any Enter/Exit events for first two regions, until i move at-least more than 7Km-10Km far from first two regions.

Expected Behaviour: - Enter/Exit event should be triggered only when i am crossing the boundary of regions, or inside the regions, not before 500 meter from the region.

My Assumption:

  • What i have noticed after all the experiment, that when i call "requestStateForRegion" for all three regions,
  • it detects all regions inside region of radius 5000m, thats why it detects first two regions at the same time (region-1 create a circle of 5000m radius, and region-2 comes in its range, thats why region -2 is also getting detected).
  • and when user moves far more than 10Km, their Exit events will be called and when user comes back in these regions, their Enter event will be fired. Its the same case as explained by Aaron Wardle above.
  • Region-3 is getting detected, because,when user enters in region-1, ie. 8-9km far from the region-3, so Exit event is fired for this, and when user is on the route for region-2, here even when region-3 is 5000 meters far, still it detects the region-3 and fire, Enter event for region-3.

So i think that all the regions inside 5000 meters are being detected, and as user moves away 10 km from detected region, its Exit event will be fired. otherwise if user is inside the 5Km range, it will never call it Enter/Exit events again.

Please update me on, if anyone has fixed this issue, or Apple documents anywhere about this issue.

Straightforward answered 16/9, 2014 at 8:23 Comment(0)
P
2

Based on @Nevan's answer, which indicated some sort of coverage in WWDC 2013 307 (which didn't directly address this), I came up with a reasonable solution to getting < 10m accuracy for the arrival to a location, though I have a feeling that implementing -(void)locationManager:didVisit: might make this more battery-conservative, but would provide less frequent updates.

First, have some regions with 0..150m radius, and start monitoring. Doesn't really matter, as the system seems to trigger these at around 150~200m:

_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;

CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(location.lat, location.lng) radius:50 identifier:location.name];
[_locationManager startMonitoringForRegion:region];

Then, implement

-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    for (CLCircularRegion *enteredRegion in _locationManager.monitoredRegions.allObjects) {
        if ([enteredRegion.identifier isEqualToString:region.identifier]) {

            self.locationManager.activityType = CLActivityTypeFitness;
            self.locationManager.distanceFilter = 5;
            [self.locationManager startUpdatingLocation];

            break;
        }
    }
}

The system will start monitoring and reporting to your delegate a stream of locations, even if your app is suspended (need UIBackgroundModes to include location array element).

To check if one of those locations is within the centre of one of your regions, Implement:

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    CLLocation *firstLocation = [locations firstObject];
    CGFloat const DESIRED_RADIUS = 10.0;

    CLCircularRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:firstLocation.coordinate radius:DESIRED_RADIUS identifier:@"radiusCheck"];

    for (CLCircularRegion *enteredRegion in _locationManager.monitoredRegions.allObjects) {
        if ([circularRegion containsCoordinate:enteredRegion.center]) {
            [_locationManager stopUpdatingLocation];
            NSLog(@"You are within %@ of %@, @(DESIRED_RADIUS), enteredRegion.identifier);            
            break;
        } else if ([enteredRegion containsCoordinate:circularRegion.center]) {
            NSLog(@"You are within the region, but not yet %@m from %@", @(DESIRED_RADIUS), enteredRegion.identifier);
        }
    }
}

You'll also want to implement:

-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    [_locationManager stopUpdatingLocation];
}
Piranha answered 9/6, 2016 at 17:26 Comment(2)
Unfortunately calling startUpdatingLocation in background is not really a good idea, when the app is woken up by the system it has only 10 seconds to perform any actions it has, so calling startUpdatingLocation will only work for about 10 seconds and thats it. Basically the system detects this and is stopping the location updates. I even got to create/spend a Code Level ticket with something similar and the answer from Apple was pretty clear, you should not call startUpdatingLocation while being in background, thou its OK to call the significant location changes.Weeny
Not that the app has been approved by Apple yet, startUpdatingLocation in background works just fine, with the UIBackgroundModes Info.plist entry also containing locations. This gives me about 10 minutes for me to reach my destination; after that, my expirationHandler suspends locationUpdates.Piranha
P
2

This is more like an important comment. From Region Monitoring and iBeacon

Testing an iOS App’s Region Monitoring Support

When testing your region monitoring code in iOS Simulator or on a device, realize that region events may not happen immediately after a region boundary is crossed. To prevent spurious notifications, iOS doesn’t deliver region notifications until certain threshold conditions are met. Specifically, the user’s location must cross the region boundary, move away from the boundary by a minimum distance, and remain at that minimum distance for at least 20 seconds before the notifications are reported.

The specific threshold distances are determined by the hardware and the location technologies that are currently available. For example, if Wi-Fi is disabled, region monitoring is significantly less accurate. However, for testing purposes, you can assume that the minimum distance is approximately 200 meters.

Provocative answered 3/11, 2017 at 15:22 Comment(0)
H
1

Sounds like even 1 meter should work (and work better on iPhone 4S+ devices):

startMonitoringForRegion:

(...)

In iOS 6, regions with a radius between 1 and 400 meters work better on iPhone 4S or later devices. (In iOS 5, regions with a radius between 1 and 150 meters work better on iPhone 4S and later devices.) On these devices, an app can expect to receive the appropriate region entered or region exited notification within 3 to 5 minutes on average, if not sooner.

Hake answered 29/5, 2014 at 0:43 Comment(0)
G
0

In the past few days iv'e been testing a geofencing feature on my iOS 8.1 device (iPhone 5S) for an app iv'e developed.
The app is registering few regions to the iOS gefence service. The app's logic needs that each geofence radius is between 40 to 80 meters.
I'm seeing so far that in areas with larger number of cell towers and Wifi hot-spots, the geofence detection is good enough on entering regions. That is, in down town areas, business areas etc' the geofence detection is working fine.

Unfortunately, the opposite occurs in areas with few cell towers & wifi networks. My neighborhood, for example, is about 1000 meters width and 500 height (1KM x 0.5KM), and there are no cell towers in it. There are few cell towers thought, on the perimeter that surrounds the neighborhood. Unfortunately In the perimeter of the neighborhood the geofence service detects nothing.

Needless to say that i'm testing with Wifi enabled on the device.

When i test my app on Android: the geofencing service on android 4.3, 4.4 & 5.1 works much better than on iOS. The Android's geofencing service does not detect 100% of region transitions, however it detects 50%-90% of the region transitions.

I conclude the following: If there would have been more cell towers & Wifi hot-spots & if Apple would have improved the geofence service then the detection on iOS devices would have been as good as in Android's.

Gurevich answered 26/5, 2014 at 8:40 Comment(0)
O
-2

Geofencing works by detecting a user moving from one cell network tower to another cell network tower.

Therefore smallest area you can define is dictated by how close together the cell towers are.

Inside a shopping mall or sports stadium, it might be able to do 10 metres — cell towers are often extremely close together. In a regional area anything smaller than 100km can fail.

If you need smaller areas, you need to use bluetooth instead of cell towers (iBeacons). If there is a bluetooth low energy device in the target area you can set the range to very short (centimetres) or reasonably large (up to 30 metres or so). Note this all depends on the quality of the iBeacon hardware, some are better than others.

Unfortunately bluetooth (version 4.0 or newer) and cell network towers are the only way to monitor locations without significantly draining battery. Keeping the GPS active to check for a 10 metre boundary would drain the battery from full to completely flat in about 2 hours even with the screen switched off.

Outgoing answered 28/5, 2014 at 8:57 Comment(2)
Region monitoring does not use cell towers or bluetooth exclusively. Just like the rest of the location manager, it uses several different methods to determine location with differing degrees of accuracy: Cell towers, WiFi, GPS, and bluetooth for beacon monitoring.Prohibitionist
@Prohibitionist only if WiFi or GPS are turned on by some other app on the system. They will never be activated by geofencing. And bluetooth is never used for geofencing, it's only used for beacons.Outgoing

© 2022 - 2024 — McMap. All rights reserved.