iOS Geofence CLCircularRegion监控。 locationManager:didExitRegion似乎没有按预期工作

我目前正试图让我的应用程序使用CoreLocation来监视特定的区域,但是我发现它似乎并不像预期的那样工作,在我看来,它不能为每个位置(即10米)设置一个小的半径集。

我也放了一个小testing应用程序,在地图上绘制圆半径 ,以便我可以直观地看到发生了什么。

我用于监视位置的代码如下所示:

 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]; 

我还没有把这里的代码放在DidEnter地区等,因为我知道,当我离开监控区域超过100米的时候,这个代码是有效的。

这里是一个应用程序的屏幕截图,当我远离地图上的紫色位置超过10米时,出口区域事件不会触发,但是如果我将位置切换到伦敦,它会触发,而且当我设置我的位置时回到当前蓝色位置的地方也会发生火灾。

示例区域

有谁知道是否有最小区域半径的限制,或者我可能做错了什么。

谢谢Aaron

我不认为区域监测在这么小的范围内运作良好。

  • GPS芯片和kCLLocationAccuracyBestForNavigation的最佳精度通常只有10米。
  • 苹果公司(位于地理位置PG )说,地区的最小距离应该假定为200米
  • 我听说区域监控正在使用WiFi来获得它的位置(这是节能的意义)。 WiFi精确度更像是20m-100m。 我不知道如何让另一个应用程序使用背景位置(即使用GPS)会影响这一点。 地理位置经理可能会分享信息,以提高准确度。
  • 区域监控可能需要30秒才能在一个区域内发射一次,在离开一个区域后需要几分钟时间才能发射(以防止位置故障触发)。
  • 当地区监测首次引入时,他们表示只能在1亿个地区开展工作,而任何规模较小的地区都会受到影响。 这可能还是会发生的。
  • 有一个不赞成使用的方法startMonitoringForRegion:desiredAccuracy:它允许您指定区域边界之后的距离,开始生成通知。 据推测,这个function已经被引入startMonitoringForRegion:但仍然存在。 一个10米的地区最终可能会有10米的缓冲区。
  • 如果要这样做,请在要监视的地方指定一个较大的区域,当设备在该区域醒来时,启动背景位置更新(GPS)并使用CLCircularRegion -containsCoordinate:在设备处于10米手动。 这种方法是由苹果正式批准的(参见WWDC 2013会议307)。

CLCircularRegion文档:

请记住,位置pipe理器在穿越区域边界时不会立即生成通知。 相反,它采用时间和距离标准来确保过境是有意的,并且应该真正触发通知。 所以select合适的中心点和半径,给你足够的时间提醒用户。

从位置和地图PG :

区域事件可能不会在区域边界越过后立即发生。 为了防止虚假的通知,iOS在达到某些阈值条件之前不会传递区域通知。 具体来说,用户的位置必须跨过区域边界,从边界移开最小距离,并且在通知被报告之前保持在该最小距离处至less20秒。
特定的阈值距离由当前可用的硬件和定位技术确定。 例如,如果Wi-Fi已禁用,则区域监视的准确性将大大降低。 但是,出于testing目的,您可以假设最小距离大约为200米。

Kevin McMahon在这篇文章中还有更多的内幕,他向核心位置工程师询问了WWDC2012的一个实验室的区域监测情况。在此期间这个信息将发生变化,但关于区域类别的部分是有趣的。 这是一个编辑:

精美的地区(0 – 150米)
– 100米的地板范围有效100-150米。
– 对于区域来说,这个尺寸的性能很大程度上依赖于位置相关的硬件
– 核心位置检测并调用相应的委托方法所花费的时间大约是在跨越区域边界后的2-3分钟。
– 一些开发者已经独立地认识到,较小的区域将会看到更快的callback,并将较小的区域集中到一个大的区域以改善区域交叉通知。

这似乎是CLLocationManager一个错误。 我已经使用各种区域半径configuration和locationManager:didExitRegion进行了广泛的testinglocationManager:didExitRegion不会以预期的方式触发。 这似乎是一个相当讨厌的错误或区域监测根本没有发生像文件build议。 我有testing用具可供任何人需要它:

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

在模拟器中运行它,并通过在iOS模拟器菜单中selectDebug – > Location – > Freeway Drive来启动testing。 你看到的数字是从监控区域的中心的距离。 设备位于监控区域内时背景颜色为绿色,区域外为红色。 距离下面的文字是事件日志。

在这里输入图像说明

运行该应用程序后,您应该会看到locationManager:didExitRegion监控区域5319米处的locationManager:didExitRegion火灾。 路线将每37分钟循环一次,您将看到设备退出该区域始终在5319米处。

我已经向苹果提交了一个雷达(17064346) 。 一旦我收到他们的回信,我会更新这个答案。 至less我们会从规范的来源获得一些信息。

以下是发送给苹果的详细文本:

在iOS模拟器以及iPhone 5S上使用testing应用程序,CLLocationManager似乎没有以预期的方式触发didExitRegioncallback。 无论被监测的圆形区域的半径如何,在达到大约5000米的阈值之前都不会发生callback。

重现步骤:
1.运行附加的应用程序
2.通过在iOS模拟器中selectDebug – > Location – > Freeway Drive来启动区域跟踪
3.监视应用程序。 大#表示距离观看区域中心的距离。
4.大约190秒和5300米之后,didExitRegion终于开火了。

这个问题似乎与该地区的规模无关。 根据苹果公司的文件 ,即使是小地区也是如此:

在iOS 6中,半径在1到400米之间的区域在iPhone 4S或更高版本的设备上效果更好。 (在iOS 5中,半径在1到150米之间的区域在iPhone 4S和更高版本的设备上效果更好)。在这些设备上,应用程序可以预期在3到5分钟内收到input的适当区域或区域退出通知,如果不是早点的话。

虽然地区事件不是瞬间发生的,但它们应该相当快地发生。 从苹果文档 :

区域事件可能不会在区域边界越过后立即发生。 为了防止虚假的通知,iOS在达到某些阈值条件之前不会传递区域通知。 具体来说,用户的位置必须跨过区域边界,从边界移开最小距离,并且在通知被报告之前保持在该最小距离处至less20秒。

这完全不是我在testing中看到的。 在模拟器上, locationManager:didExitRegion事件发生之前,设备将始终距离该地区5000+米。

我喜欢Michael和Nevan的答案。 我想从我的个人经验/意见中添加更多的信息来开发基于地理位置的iOS应用程序区域监控 ,并突出一些重点:

在区域监测上切实可行

区域监控使用全球定位系统(GPS),Wifi和其他技术来确定设备是在监控区域之内还是之外。 不要忘记,我们的地球是510平方公里,大约30%是土地(1.49亿平方公里)。 这是一个巨大的领域。 还记得最近MH370遗漏的情况吗? 我们目前最先进的技术甚至无法确定这架失踪飞机的估计区域。

如果你想监视一个只有10米半径的小地区。 它可能工作在一个高密度的城市有很多细胞塔和无线连接区域。 但与此同时,信号可能被高层信号塔阻挡,可能导致信号丢失几秒/分钟,从而导致通知延迟。

所以,在决定你要监测的区域有多大之前,你必须考虑上述信息。 我个人认为10米半径太小。

对监测区域数量的现实性

目前的核心定位技术只能在一个应用程序上监视最多20个区域 。 确保监测的地区也不太接近彼此。

我亲自testing了3个半径约100米的地区,彼此相距约200米。 有时我可以在驾驶时通过这三个地区的通知,但是有时我只能得到第一地区的通知。 可能是什么原因? 我不知道。 这些地区可能彼此靠得太近。 或者手机塔决定我的设备实际上并不在监控区域内。

有一个人在StackOverFlow上想要监视我们地球上的1800点。 不要像他那样,因为他很不现实,可能不了解当前Core Location技术的局限性。 链接 : 检查用户位置是否接近某些点

微调LocationManager

如果您的应用程序需要监视一个小区域或需要经常更新位置。 以下是您的位置pipe理器的潜在属性。

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

kCLLocationAccuracyBest相比, kCLLocationAccuracyBest将消耗更多电量。 但是,它会更准确。

当在不同的受监控区域同时触发多个通知时,我在iOS 7中发现了一个区域监控的小故障。 我find了一个解决scheme来滤除这个故障。 欲了解更多信息,请访问: 区域监控故障在iOS 7 – 多个通知在同一时间

不要过于雄心勃勃

您可能已经使用了一些可以监控一个小区域的应用程序,而且这些应用程序非常准确,并且可以在进入该区域的同一时间通知您。 你有灵感来开发完全相同的应用程序来与他们竞争。 但是你知道幕后发生了什么吗? 他们正在使用哪些其他技术? 他们正在与哪些合作伙伴合作?

我已经做了一些研究,发现他们使用的一些技术并不公开。 其中一些公司资金充足,可以为电信公司支付额外的费用,以获得最佳的用户体验的最佳位置精度。 我不明白它是如何工作的细节。 我相信大部分的位置确定实际上是在服务器端(后端),而不是移动端(前端)。

因此,这些公司开发的应用程序不仅可以精确定位最准确的位置,而且不会消耗大量的电池。

:我只是想分享我的2美分。 以上信息包括我的经验和个人意见。 它可能不是100%准确的,因为我仍在学习核心位置区域监视

我同意Michael G. Emmons ,也想分享我的经验:

我testing了三个区域的代码,如下图所示:

在这里输入图像说明

解释行为:

  • 我目前的位置是区域1,我开始监视上述三个区域,并调用requestStateForRegion,以确定,如果有任何区域内,我现在站在哪里。
  • 然后我得到“input”通知,前两个区域(区域1和区域2),但它应该只检测区域1。
  • 现在当我进入region-2时,我得到了区域-3的Enter通知。 但我应该在这里得到区域2的通知。
  • 现在,当我再次进入region-1时,我得到了为区域-3启动的Exit事件,并且继续。
  • 但前两个区域我没有进入/退出事件,直到我移动到距离前两个区域至less7公里-10公里以上。

预期行为: – 只有当我穿过地区的边界或地区内部时,才会触发进入/退出事件,而不是在距离该地区500米之前。

我的假设:

  • 我注意到所有的实验后,当我为所有三个区域调用“requestStateForRegion”时,
  • 它检测半径5000m范围内的所有区域,这就是为什么它同时检测到前两个区域(区域1创build一个5000m半径的圆,区域-2进入其范围,这就是为什么区域-2也被检测到)。
  • 当用户移动远远超过10Km时,他们的退出事件将被调用,并且当用户返回到这些区域时,他们的Enter事件将被触发。 这与上面的Aaron Wardle所解释的情况是一样的。
  • 区域-3正被检测到,因为当用户进入区域-1时,即, 8-9km,因此退出事件被触发,当用户在区域2的路线上时,这里即使区域3远在5000米,仍然检测到区域3和火灾input区域3的事件。

因此,我认为5000米范围内的所有地区都被检测到,并且当用户离开被检测地区10公里的地方时,其退出事件将被触发。 否则,如果用户在5Km范围内,则不会再次调用Enter / Exit事件。

请更新我,如果有人已经解决了这个问题,或苹果文件的任何地方关于这个问题。

听起来像1米,应该工作(并在iPhone 4S +设备上更好地工作):

startMonitoringForRegion:

(……)

在iOS 6中,半径在1到400米之间的区域在iPhone 4S或更高版本的设备上效果更好。 (在iOS 5中,半径在1到150米之间的区域在iPhone 4S和更高版本的设备上效果更好)。在这些设备上,应用程序可以预期在3到5分钟内收到input的适当区域或区域退出通知,如果不早的话。

根据@ Nevan的回答,这个答案在2013年的WWDC上表示了一些报道,但是我想出了一个合理的解决scheme来获得<10m的准确性,尽pipe我有一种感觉实施-(void)locationManager:didVisit:可能会使这个电池更保守,但会提供更less的频率更新。

首先有一些半径为0..150m的区域,并开始监测。 真的不重要,因为系统似乎在150〜200米左右触发这些系统:

 _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]; 

然后执行

 -(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; } } } 

即使您的应用程序被暂停(需要包含location数组元素的UIBackgroundModes ,系统也会开始监控并向您的UIBackgroundModes报告一组位置。

要检查其中一个位置是否位于您所在地区的中心,请执行以下操作:

 -(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); } } } 

你也想实现:

 -(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region { [_locationManager stopUpdatingLocation]; } 

这更像是一个重要的评论。 来自地区监测和iBeacon

testingiOS应用程序的区域监视支持

在iOS模拟器或设备上testing您的区域监视代码时,请注意区域边界越过后,区域事件可能不会立即发生。 为了防止虚假的通知,iOS在达到某些阈值条件之前不会传递区域通知。 具体来说,用户的位置必须跨过区域边界,从边界移开最小距离,并且在通知被报告之前保持在该最小距离处至less20秒

具体的阈值距离由当前可用的硬件和定位技术决定。 例如,如果Wi-Fi已禁用,则区域监视的准确性将大大降低 。 但是,出于testing目的,您可以假设最小距离大约为200米

在过去的几天里,iv'e一直在我的iOS 8.1设备(iPhone 5S)上testinggeofencingfunction,以开发应用程序。
该应用正在向iOS Gefence服务注册less量地区。 该应用的逻辑需要每个地理围栏半径在40到80米之间。
目前为止,在手机信号塔和Wifi热点数量较多的地区,进入地区的地理围栏检测已经足够好了。 也就是说,在城镇地区,商业区等地理围栏检测工作正常。

不幸的是,相反的情况发生在细胞塔和无线networking很less的地区。 例如,我的邻里约有1000米宽,500米高(1KM×0.5KM),里面没有手机信号塔 。 在附近的周边有很less的细胞塔。 不幸的是,在附近的周边地理围栏服务没有发现任何东西

不用说,我正在与设备上启用Wifitesting。

当我在Android上testing我的应用时:android 4.3,4.4和5.1上的geofencing服务比iOS上的更好。 Android的geofencing服务没有检测到100%的区域转换,但它检测到50%-90%的区域转换。

我得出以下结论:如果将有更多的手机信号塔和Wifi热点,如果苹果公司将改进地理围栏服务,那么在iOS设备上的检测将会和Android一样好。

Geofencing通过检测用户从一个小区networking塔移动到另一个小区networking塔来工作。

因此,您可以定义的最小面积取决于细胞塔之间的距离。

在购物中心或运动场内,它可能能够做到10米 – 细胞塔往往非常接近。 在一个小于100公里的区域范围内可能会失败。

如果您需要更小的区域,则需要使用蓝牙而不是手机信号塔(iBeacons)。 如果在目标区域内有蓝牙低功耗设备,可以将范围设置为非常短(厘米)或相当大(高达30米左右)。 注意这一切都取决于iBeacon硬件的质量,有些比其他更好。

不幸的是,蓝牙(4.0或更新版本)和蜂窝networking塔是监测位置的唯一方式,而不会显着耗尽电池。 即使屏幕closures,保持GPS激活以检查10米的边界将在大约2小时内将电池从完全耗尽到完全平坦。

Interesting Posts