我一直在iOS上开发区域监控约2个月。最近我们发现了一个小故障,同时在一定半径范围内(约4.7KM或4700米)触发了所有区域。设备的当前位置甚至不靠近任何区域。我不确定是什么原因引发了这一事件。我通过StackOverFlow,Apple开发者论坛等搜索过,我找不到与我面临的任何类似问题。
在我正在开发的应用程序中,我们正在监控城市内的8个地区(吉隆坡)。有一次,我的同事发现他的手机同时触发了4个地区通知。下面是显示其位置,所有受监控区域,触发4区域通知的潜在半径的地图。
已触发通知的屏幕截图:
以下是我的位置管理器代码: -
CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
locationManager.distanceFilter = kCLDistanceFilterNone;
这是我的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];
}
}
注意:此问题不会每次都发生,只会偶尔发生一次。 4700米是我在分析了4个触发区域的位置后得出的半径。我不确定这是否是我的代码上的故障,在iOS上或我国家的本地电信公司有问题。在最新版本的应用程序中,我将distanceFiter调整为10,我们正在测试它是否能解决问题。
//locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.distanceFilter = 10;
方法 didEnterRegion 永远不会返回用户的位置,我无法过滤掉具有大半径的潜在坏位置,就像上面显示的示例一样。我能做些什么来解决这个小故障?
任何面临类似问题的开发人员,请挺身而出,分享您的经验和解决方案以解决此问题(如果有的话)。感谢。
答案 0 :(得分:6)
我找到了解决这个奇怪错误的方法。我们测试了超过1周,到目前为止我们还没有再看到相同的bug。这是解决方案: -
-(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];
}
}
}
我使用CLLocation * lastLocation = [manager location];
从设备获取最新位置,并使用此坐标查看它是否在 containsCoordinate:方法的触发区域内。如果它在里面,那么只会触发本地通知。
有关此错误及其解决方法的详细说明,您可以访问:iOS Region Monitoring and Location Manager
答案 1 :(得分:3)
HERE是针对iOS地理围栏故障的全面校对工作解决方案/修复工具!
这将解决在网络交换机上接收错误的多个事件(如wifi到移动数据,反之亦然)的问题。此外,它通过此逻辑/修复为您提供准确的结果/通知
基本上,LocationManager
应该被视为单身,而distanceFilter应该是kCLDistanceFilterNone
,而且期望精度应该是kCLLocationAccuracyBestForNavigation
(我们已经采用了这个以获得最佳准确度,因为我们需要对位置进行真正的背景监控非常准确的实时地理围栏入口通知发送给用户)
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
CLLocation * lastLocation = [manager location];
BOOL doesItContainMyPoint;
if(lastLocation==nil)
doesItContainMyPoint = NO;
else{
CLLocationCoordinate2D theLocationCoordinate = lastLocation.coordinate;
CLCircularRegion * theRegion = (CLCircularRegion*)region;
//we need to take new instance of given region for which the iOS triggers entry event..Adding 50.0 meters is needed just to make sure that containsCoordinate method of CLCircularRegion works well.Because there is lag/difference measured in our real time field testing that brought us to this conclusion and it works like a charm.If we do not add this 50.0 meters in the fence for which we are getting this event then there is a chance that containsCoordinate might miss the recent point/coordinate to consider in given region...
CLCircularRegion * theCircularRegion = [[CLCircularRegion alloc]initWithCenter:theRegion.center radius:theRegion.radius+50.0 identifier:theRegion.identifier];
doesItContainMyPoint = [theCircularRegion containsCoordinate:theLocationCoordinate];
}
if(doesItContainMyPoint){
NSLog(@"ItContainMyPoint");
//trigger local notification...
}else{
NSLog(@"ItDoesNotContainMyPoint");
//do not trigger local notification...because it is triggered due to switching network(wifi to mobile data and vice versa) Currently user is not at all in the region for which we are getting event of entry
return;
}
}
答案 2 :(得分:1)
这是一个老问题,但是让我分享我对区域监控的经验,该问题涉及不准确的didExit-didEnterRegion调用:
需要注意的一点是,如果您在设备上关闭了Wifi,iOS设备上的地理围栏的可靠性会大大降低。
对于提问者,您不应只检查要调试的最后一个位置的.coordinate
,还要检查CLLocation的.horizontalAccuracy
。如果关闭wifi和GPS,这可能会显示出非常低的准确度(很大的可能区域)。在您还运行GPS位置跟踪的情况下,接受的答案实际上是一个很好的答案。如果没有,.horizontalAccuracy可能是一个非常大的数字。区域监控似乎(根据我的经验)听GPS更新,因此无法以这种方式增强其可靠性。但启用WiFi可以。在一个城市地区。
如果没有Wifi和GPS技巧,如接受的答案使用,所有设备都有手机信号塔的位置。我发现如果所有设备必须获得它的位置,didExitRegion和didEnterRegion可能是不可靠的,是单元塔。这是因为蜂窝塔位置的准确性当然远低于wifi。在这种情况下,低精度(大可能区域)可能意味着它位于提问者的四个区域中的任何一个区域。对于单个区域甚至可能多次调用它,因为它可能突然想到(基于单元塔)它距离一公里,然后意识到它不是,这可能导致多次调用didEnterRegion。
didExitRegion也是如此。如果准确度非常低,系统无法确定您在几公里之外离开该区域(这是评论者的问题之一)
因此,如果您不确定您的用户是否使用了始终打开wifi的应用程序(您无法在iOS上检查或保证),请确保您不要使区域太小或使用接受的答案GPS([locationManager startUpdatingLocation]
)确保您真正在该地区。在这种情况下,还要检查位置是否准确且足够年轻。类似的东西:
CLLocation * lastLocation = [manager location];
NSTimeInterval locationAge = -[lastLocation.timestamp timeIntervalSinceNow];
if (lastLocation != nil && locationAge < MAX_AGE && self.currentLocation.horizontalAccuracy <= MAX_ACCURACY) {
CLLocationCoordinate2D theLocationCoordinate = lastLocation.coordinate;
CLCircularRegion * theRegion = (CLCircularRegion*)region;
doesItContainMyPoint = [theRegion containsCoordinate:theLocationCoordinate];
}
但是,如果有任何方法可以说服用户在使用应用程序时始终启用Wifi,请执行!!它使它更加可靠。