iOS 应用程序使用地理围栏来通知用户预定义的附近位置。允许应用程序错过某些位置(用户不会收到有关附近位置的通知),但最好保持较低的错过率。
实现此目的的一种方法是使用
startMonitoringSignificantLocationChanges
开始监视重大变化位置,并且每次触发“位置变化”事件时,查找报告位置 500m 半径内的位置。
让我担心的是,每次发生重大位置变化时都需要执行附近区域的查询,这对电池有影响。
另一种方法是使用
startMonitoringForRegion
注册位置,但 Apple 对同时跟踪区域的数量设置了(合理的)限制,即 20 个,而我们的位置明显超过 20 个。因此需要对跟踪区域进行某种动态更新,但我仍然不确定最好的方法是什么。
有什么想法可以让电池消耗保持在较低水平,同时位置丢失率也较低?
由于这个问题没有太多活动,我将描述我们目前如何解决这个问题。
我们尝试重新加载新区域以应对重大位置更改(SLC)事件。当 SLC 发生时,我们会检查 20 个应“地理围栏”的邻近区域。为了找到最近的 20 个区域,我们只需根据以下公式近似 1 英寸的纬度和经度:
纬度:1 度 = 110.54 公里
经度:1 度 = 111.320 * cos(纬度) km
然后只需检查设备当前位置的边界框以获取监控区域的中心(请参阅:使用纬度/经度和公里距离进行简单计算?)
例如,如果 (10N,10E) 是设备的当前位置,我们从顶点位于 (10-1',10-1'), (X-10',10+1') 的边界正方形开始), (10+1',10+1'), (10+1',10-1')(在纬度 (10N,10E),一纬度/经度分钟约为 1.85 公里)。
如果有 20 个(或几乎 20 个) - 我们将它们注册到地理围栏并等待下一个 SCL。如果少/多,只需增加/减少边界矩形的大小并重复搜索。
您可以调整此搜索算法以获得更好的性能,但此处描述的算法已经可以完成这项工作。
您可以为包含所有当前监控位置的“元地理围栏”保留一个位置。当用户离开此地理围栏时,应用程序将收到通知。然后应用程序可以自我更新并停止跟踪最远的区域并开始跟踪附近的新区域。
我想我应该添加另一个选项,以便在您的应用程序中使用 20 多个地理围栏。这种方式在我们的应用程序中已经运行良好很长时间了,并且使用内置的
CLLocation
方法。
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (locations.count > 0) {
CLLocation *location = locations[0];
NSMutableArray *sortedFences = [[NSMutableArray alloc] init];
// add distance to each fence to be sorted
for (GeofenceObject *geofence in enabledFences) {
// create a CLLocation object from my custom object
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(geofence.latitude, geofence.longitude);
CLLocation *fenceLocation = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
// calculate distance from current location
CLLocationDistance distance = [location distanceFromLocation:fenceLocation];
// save distance so we can filter array later
geofence.distance = distance;
[sortedFences addObject:geofence];
}
// sort our array of geofences by distance and add we can add the first 20
NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:@"distance" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortByName];
NSArray *sortedArray = [sortedFences sortedArrayUsingDescriptors:sortDescriptors];
// should only use array of 20, but I was using hardcoded count to exit
for (GeofenceObject *geofence in sortedArray) {
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(geofence.latitude, geofence.longitude);
CLLocationDistance radius = geofence.radius;
NSString *ident = geofence.geofenceId;
CLCircularRegion *fenceRegion = [[CLCircularRegion alloc] initWithCenter:coordinate radius:radius identifier:ident];
fenceRegion.notifyOnEntry = geofence.entry;
fenceRegion.notifyOnExit = geofence.exit;
[locationController.locationManager startMonitoringForRegion:fenceRegion];
}
}
}
希望这能帮助某人或引导他们走上正确的道路。
我知道这篇文章已经过时了,但是对于那些想要做类似事情的人来说,Skyhook提供了对无限数量的场地进行地理围栏的能力。
来自他们的营销: Skyhook 的上下文加速器使应用程序开发人员和广告商能够通过简单的 Web 界面立即将无限地理围栏部署到任何品牌链(例如 CVS)或场所类别(例如便利店)。 Context Accelerator SDK 使用 Skyhook 第一方定位网络的相同专利技术来管理设备上的活动地理围栏,而不受允许无限地理围栏的操作系统限制。