Ricky Ricky - 6 months ago 34
iOS Question

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

I have been developing region monitoring on iOS for about 2 months. Recently we have found a glitch where all the regions within a certain radius (about 4.7KM or 4700 meters) triggered at the same time. The current location of the device is not even close to any of the regions. I am not sure what could have triggered that event. I have searched through StackOverFlow, Apple Developer forums and etc, I haven't find any similar issue with what I am facing.

In the app that I am developing, we are monitoring 8 regions within the City (Kuala Lumpur). On one instance, my colleague found out that there were 4 regions notification triggered on his phone at the same time. Below is the map showing his location, all the monitored regions, the potential radius that triggered the 4 region notifications.

iOS region Monitoring


  • The green marker is the location of the device when receiving the notification.

  • The blue circle is the potential radius of the device (about 4700 meters) which is covering 4 regions that send the notification to the device.

  • The red circle is the radius for each of the region.

  • There are 2 other regions on the map which never send notifications (never cover under blue circle)



Screen shot of the triggered notifications:

iOS region monitoring glitch

Here is my code for location Manager:-

CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
locationManager.distanceFilter = kCLDistanceFilterNone;


Here is my code for didEnterRegion:-

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

NSString* message = [NSString stringWithFormat:@"Message"];
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];
}

}


Note: This issue does not happen every time, it only happens once in a while. The 4700 meters is the radius that I came out with after analysing the location of the 4 triggered regions. I am not sure if this is a glitch on my code, on the iOS or there is a problem on the local telco in my country. In the latest version of the app, I am adjusting the distanceFiter to 10 and we are testing it right now to see if this will solve the issue.

//locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.distanceFilter = 10;


The method didEnterRegion never return the location of the user, I am not able to filter out the potential bad location with a big radius like the example I show above. What I can do to solve this glitch?

Any developer who is facing the similar issue, please come forward and share your experience and solution to solve this issue (if there is any). Thanks.

Answer

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