在后台进行iBeacon监测和范围定位

4
我花了几个月的时间开发了一个基于 iBeacons 的应用程序,但我非常沮丧。
总体思路是在检测到信标时,向用户提供与该 iBeacon 相关的信息。
该应用程序的设计如下:所有 iBeacons 具有相同的 UUID,Major 确定建筑物(博物馆、商店等),Minor 确定特定产品(图片、鞋子等)。因此,此应用程序可以为多个客户提供服务。
当应用程序启动时,我开始对具有我们的 UUID 的区域进行监控和范围测量。当应用程序处于前台时,一切都很完美。但在后台或挂起状态下,问题就开始了。在后台或挂起状态下不允许进行范围测量。
我知道当您进入或退出信标的区域时,应用程序将在后台运行约 5 秒钟。您可以在这五秒钟的时间内在后台进行范围测量,之后 iOS 将再次挂起您的应用程序。
我成功地使用此处学到的技术将范围测量延长到了 3 分钟。我还通过 notifyEntryStateOnDisplay = YES 获得了额外的回调;
但这还不够,如果客户在应用程序处于后台或挂起状态下进入区域,他将收到通知。在额外的 3 分钟内,如果范围测量检测到另一个 iBeacon,他将收到通知,但是当 3 分钟的后台任务过期时,如果没有触发区域退出,他将不会再次收到任何通知。
在这种情况下,难道没有真正的解决方案吗?我认为这是一个非常常见的场景,我很惊讶居然没有办法处理它。
编辑:我尝试通过监视两个区域来找到解决问题的方法,正如 David Young 在他的回答中建议的那样。以获取更多进入/退出区域的事件。
我添加了我实现的代码来尝试监视两个区域。
但是,我做错了什么,didRangeBeacons:InRegion: 回调每 10 毫秒触发一次,而预期的是每秒触发一次。
在 AppDelegate.m 中,我在 didFinishLaunchingWithOptions 中执行以下操作:
[self.locationManager startMonitoringForRegion:self.beaconRegion];
        [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
        [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
        [self.locationManager startMonitoringForRegion:self.beaconRegion2];
        [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion2];
        [self.locationManager startRangingBeaconsInRegion:self.beaconRegion2];

然后,在didRangeBeacons:InRegion:方法中,
- (void) locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{

     if(beacons.count > 0){
          [self.locationManager stopRangingBeaconsInRegion:region];
          for (CLBeacon *beacon in beacons){
             NSLog(@"beacon detected major: %@ minor: %@", beacon.major,beacon.minor);
          }
           [self.locationManager startRangingBeaconsInRegion:region];   
     }

}

当我在模拟器上运行应用并且每个网络都有信标在范围内时,消息会大约每10毫秒显示在控制台上。我怀疑停止和重新启动测距正在破坏预期的回调流程,但当只有一个区域在范围内时,回调按预期每秒发生一次。
2个回答

7
您所描述的问题很常见。最简单的方法是使用后台位置模式,将后台范围时间无限延长。(这类似于OP已经做过的事情,但可以无限期地延长)。
另外两个选择:
1. 获取硬件信标,使您可以调整发射功率 (我们公司的RadBeacon产品可以实现) ,以便传输不重叠。这样,您就可以在从一个信标到另一个信标移动时得到退出事件和新的进入事件。
2. 重新设计您的标识符方案,使主字段专用于识别多达20个不同区域(基于UUID和主1-20)。然后,您监视所有这些区域。您的各个信标仍然可以按您想要的方式使用次要字段,并具体作为触发消息的键。在放置信标时,确保没有重叠的传输共享相同的主字段。这将确保您在从一个到另一个移动时获得新的后台进入事件。

你能给我更多关于第一个选项的信息吗?第二个选项比较复杂,因为Major标识了客户端,这将会改变整个后端和Android应用程序。 - Kepa Santos
一个疯狂的想法,如果我定义一个虚构的网络,具有相同的UUID但具有特定的Major和Minor。然后我开始监视和测距到两个区域,一个只有UUID,第二个则包括UUID和特定的Major和Minor。如果我分发虚构的网络信标并将它们放置在可能存在重叠的战略位置,那么我会得到额外的区域进入和退出吗? - Kepa Santos
对于第一个选项,您只需使信标传输的距离更短,比如10米。只要您的信标至少相距20米,当您在它们之间移动时,就会获得出入事件。您在上面的评论中提出的第二个建议是我的答案中第二个选项的可行变体。您只需要部署额外的信标即可实现该变体。 - davidgyoung
我正在尝试监视两个区域,但我注意到了一些奇怪的事情。当我只监视一个区域时,“didRangeBeacons”回调每秒触发一次。但现在,有了2个区域,当它们都在范围内时,它大约每10毫秒触发一次。这是预期的行为吗? - Kepa Santos
每个收到信号的区域都应该以1Hz的频率调用“didRangeBeacons:InRegion:”方法。即使有10个接收到信号的区域,您只会在100毫秒内获得一次回调。您确定在该回调方法中没有循环内部看到这个时间吗?如果是这样,那么同时处理100个可见信标可能会给您更少的回调,但每个信标的处理速度为每10毫秒处理一个。 - davidgyoung
我添加了代码,使回调每10毫秒发生一次,而不是每秒钟发生一次。我不明白为什么会这样,请你看一下?谢谢你的帮助! - Kepa Santos

2

在iOS 8中,背景下的信标测距完全可行,只要您跳过所有障碍。

首先,您需要正确的授权。将键NSLocationAlwaysUsageDescription添加到您的Info.plist中,并调用

[self.locationManager requestAlwaysAuthorization];

您的应用程序必须具有“位置更新”的“后台模式”。在 Info.plist 或通过功能(与 Build Settings 并列)中指定。

然后在 applicationDidBecomeActive 中检查授权。

switch([CLLocationManager authorizationStatus])
{
    ...

授权后,您需要执行以下操作:

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// If you don't do this, location updates will pause after 15 minutes in the same place
// Usually this is what you want, so I've left this line commented out
// self.locationManager.pausesLocationUpdatesAutomatically = NO;

// Create a NSUUID with the same UUID as the broadcasting beacon
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:kProximityUUID];

_beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
                                                  identifier:@"uk.co.airsource.testregion"];

// Necessary to get continued background ranging.
// See https://community.estimote.com/hc/en-us/articles/203914068-Is-it-possible-to-use-beacon-ranging-in-the-background-
_locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
[_locationManager startUpdatingLocation];
[_locationManager startMonitoringForRegion:self.beaconRegion];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接