Region Monitoring Glitch on iOS 7 - Multiple Notifications at the Same Time

Region Monitoring Glitch on iOS 7 - Multiple Notifications at the same time

I have found a fix for this strange bug. We have tested for over 1 week and so far we haven't see the same bug again. Here is the solution:-

-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{

NSLog(@"didEnterRegion");
CLLocation * lastLocation = [manager location];

BOOL doesItContainMyPoint;

if(lastLocation==nil)
doesItContainMyPoint = NO;
else{
CLLocationCoordinate2D theLocationCoordinate = lastLocation.coordinate;
CLCircularRegion * theRegion = (CLCircularRegion*)region;
doesItContainMyPoint = [theRegion containsCoordinate:theLocationCoordinate];
}

if(doesItContainMyPoint){
NSString* message = [NSString stringWithFormat:@"You are now in this region:%@",region.identifier];
UIApplicationState state = [[UIApplication sharedApplication] applicationState];

if (state == UIApplicationStateBackground || state == UIApplicationStateInactive)
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [NSDate date];
NSTimeZone* timezone = [NSTimeZone defaultTimeZone];
notification.timeZone = timezone;
notification.alertBody = message;
notification.alertAction = @"Show";
notification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
}
}

I use CLLocation * lastLocation = [manager location]; to get the latest location from the device and use this coordinate to see if it is inside the triggered region with containsCoordinate: method. If it is inside, then only the local notification will trigger.

For the details explanation on this bug and the way to fix it, you may visit: iOS Region Monitoring and Location Manager

(iOS) Multiple notifications via locationManager:didExitRegion: when exiting a region

tl;dr: It's really quite simple - you're getting as much information as Apple can give you about the fact that you're crossing cell tower boundaries - meaning, not really good data at all.

Now the real story:

Generally, there are only a couple of ways that CoreLocation can determine one's position:

  • By GPS. This is highly accurate (tens of meters), but takes lots of power to use.
  • By WiFi. This is generally accurate, though wifi base stations can and do change, which makes it fuzzy. This method cross-references the wifi stations in the area vs some known accurate locations - so it knows when it sees "FooWifiStation" that it's associated with a particular area, measured by precise instruments, or perhaps even other phones with GPS turned on (which is controversial, we may never know if Apple uses this method)
  • By cell tower locations. These don't move, so it knows you're within a big fuzzy dot of coverage when you're associated with a tower. This is the least accurate, but least power-consuming, because your phone is already doing the work to stay in contact.

You can even see this if you go into the maps application "cold": you start out immediately with a big fuzzy blue dot, (at least 1km where I am), then it shrinks as it gets a wifi location fix, then it more or less disappears when GPS gets its fix. It's doing [cell tower] => [wifi] => [gps] accuracies in real time.

From my experience, the "significant location change" clause means "We'll let you know whenever you move in a big way, as long as we don't have to do any more work or expend any more power to get you that data. This means de facto that the very best you can rely on is using transitions between cell towers. Apple deliberately left this vague, because if another app uses something that has better resolution - say, you open Maps.app, and it gets a GPS fix - it is possible that you will suddenly get a great fix on location, but you can't depend on that always being the case. You've asked for a "weak reference" to location.

Now think about what happens when you are wandering about in your car: your cell phone has to manage that transition. It gets handed off, talks to multiple towers at once, that sort of thing, to manage a seamless transition which must be viable while you are having a conversation. Just that is a pretty neat feat for any little box to do. Necessarily, this will cause you to see a bit of bounce in location updates, because, to the phone, you're vibrating between cell towers at this time as it negotiates the transition.

So what the radius really means is that you're interested in data of roughly that accuracy - but the API will not guarantee that you get updates within that radius. You can think of it as Apple saying, "We're going to bucket your accuracy into one of 3 groups - but we didn't give you an enumeration, because we want to reserve the right to develop better methods of fixing your location without you having to change your code". Of course, in reality, any real app will change if they change their method of getting location, because they are annoyingly vague about this location stuff.

In other words, you will get a location fix at the cell tower with some totally made up guess as to how good that accuracy is; when you move to the next tower, you will instantly jump to its location, with a similarly fuzzy fix - does that make sense? CoreLocation is telling you you're at the cell tower with accuracy of however far the cell tower's signal reaches; as you move to another tower, you will probably get the bounciness of the handoff.

So when it comes to it, to really do a good job, you have to assume that the data is one of "great", "ok", or "bad" and use other methods - like Kalmann filters - if you really need to have a better guess at where the user is. As a zeroth-order approximation, I would just debounce the callbacks based on the time of the update, which is given, and assume that the user isn't really leaping kilometers back and forth within a few seconds, but rather, travelling in the direction of the first new update.

Region monitoring current location doesn't notify on exit

I think the way you implement the region monitoring might cause some problems.

Here are the reasons:-

  1. Inside the startLocationTracking method, your locationManager is a local object that does not extend over the life cycle of that method. It also means that every time you call startLocationTracking, there will be a new locationManagerobject that is allocated with a new block of memory.

    To solve this problem: You should use a singleton locationManager that is a shared locationManager for the entire life cycle of the Application.

  2. I believe you should not startMonitoringForRegion inside the delegate method -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:. The reason is, if you call startLocationTracking more once, there will be more than one locationManager. Multiple locationManagers could monitor the same region which may cause multiple notifications.

  3. After you call [manager startMonitoringForRegion:region];, the region will not be monitored immediately. If you do not believe believe me, try the follow code:-

    [locationManager startMonitoringForRegion:region];
    NSLog(@"%@",locationManager.monitoredRegions);

You will find out that the region that you just monitored will not be inside the locationManager.monitoredRegions. Since this is handled on the iOS level, so, I think it might need a few minutes for the region to be ready to be monitored.

You should also understand other limitations for Region Monitoring in iOS:-

https://developer.apple.com/library/mac/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html

An app can register up to 20 regions at a time. In order to report
region changes in a timely manner, the region monitoring service
requires network connectivity.

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.

Note: Apps can expect a notification as soon as the device moves 500
meters or more from its previous notification. It should not expect
notifications more frequently than once every five minutes. If the
device is able to retrieve data from the network, the location manager
is much more likely to deliver notifications in a timely manner.

I don't know what your app is about, I believe you should redesign the flow of your app. You should try to monitor the region outside of the delegate methods.

For more information about the Singleton LocationManager, you may check out this answer: Background Location Services not working in iOS 7. There is a complete project on GitHub that contains a Singleton LocationManager class that I named as LocationTracker.

You might also want to check out a glitch for Region Monitoring in iOS 7 that I found out a month ago (with a workaround to solve the glitch): Region Monitoring Glitch on iOS 7 - Multiple Notifications at the same time

iOS Region Monitoring not working

I ended up using the CLRegion.containsCoordinate(location.coordinate) method instead. It works pretty much the same way.

Once the object has entered my set region, it returns true and from here I can know when it's entered and exited the region.

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

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.

IOS 7 Region monitoring - choosing your regions

If you have a list of regions in your app then you can use distanceFromLocation: to determine which ones are the closest and register those. You can also implement signification location change notification to review your region distances and select different regions to monitor when the device moves.



Related Topics



Leave a reply



Submit