在iOS背景中的灯塔测距

时间:2014-10-14 19:04:29

标签: ios core-location ibeacon

我理解监视和测距之间的区别,并且我理解iOS中信标范围的限制只能在进入和退出区域时在前景或后台发生,如此处所述(http://developer.radiusnetworks.com/2013/11/13/ibeacon-monitoring-in-the-background-and-foreground.html)。但我试图弄清楚如何解决一个常见的情况。

如果我在百货公司安装了一堆信标,当一个人在这些信标的范围内移动时,我该如何检测?通过它当前的工作方式,当用户进入商店(didEnterRegion)时,应用程序将获得一个事件,因为所有信标的集合都充当一个大区域。但是没有办法知道用户在商店的不同部分之间移动,除非信标放置得足够远,以便用户退出并再次进入该区域,这可能是不切实际的。

我想在后台设置信标范围的原因是我可能需要知道用户位于商店中的特定部分/产品,以显示该部分的特定优惠/信息(通过通知)而无需用户打开应用程序。

在我看来,这对于商场和博物馆等非常常见的场景......我想知道其他开发者是如何解决这个问题的,或者是否有另一种实现我想要的方式。

我在这里没有包含代码段,因为问题不在于代码,它只是一个概念问题。如果需要任何澄清或代码,我也可以添加。

由于

3 个答案:

答案 0 :(得分:7)

答案的最大部分是我的同事@csexton在这个问题的另一个答案中记录的技术。

为了解决转换后仅获得10秒测距时间的第二个问题,您可以请求额外的时间来保持测距。 iOS允许您在后台继续播放长达180秒。这不需要后台模式,也不需要AppStore的特殊许可。

以下是你如何设置的:

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    if (_inBackground) {
        [self extendBackgroundRunningTime];
    }
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [self logString: [NSString stringWithFormat:@"applicationDidEnterBackground"]];
    [self extendBackgroundRunningTime];
    _inBackground = YES;
}


- (void)extendBackgroundRunningTime {
    if (_backgroundTask != UIBackgroundTaskInvalid) {
        // if we are in here, that means the background task is already running.
        // don't restart it.
        return;
    }
    NSLog(@"Attempting to extend background running time");

    __block Boolean self_terminate = YES;

    _backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"DummyTask" expirationHandler:^{
        NSLog(@"Background task expired by iOS");
        if (self_terminate) {
            [[UIApplication sharedApplication] endBackgroundTask:_backgroundTask];
            _backgroundTask = UIBackgroundTaskInvalid;
        }
    }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"Background task started");

        while (true) {
            NSLog(@"background time remaining: %8.2f", [UIApplication sharedApplication].backgroundTimeRemaining);
            [NSThread sleepForTimeInterval:1];
        }

    });
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [self logString: [NSString stringWithFormat:@"applicationDidBecomeActive"]];
    _inBackground = NO;
}

在背景中获得180秒的范围并不是银弹,但它解决了许多10秒钟没有的用例。

您可以在此处阅读有关其工作原理的完整说明以及测试结果:https://github.com/RadiusNetworks/ibeacon-background-demo/tree/background-task

答案 1 :(得分:3)

我可能会通过将商店分成多个区域来建模。它们的建模方式将基于触发通知时的用例。

我会通过给予他们所有相同的UUID但不同的主要值来做到这一点。然后使用次值来区分商店。这样,当他们从区域移动时,应用会注册didEnter事件。

您可以注册约20个地区,因此在将信标分组时我会小心。

例如:

  • UUID:754A5D70-C59E-4E39-AA56-ED646903EF5B少校:1→入口
  • UUID:754A5D70-C59E-4E39-AA56-ED646903EF5B主要:2→收银机
  • UUID:754A5D70-C59E-4E39-AA56-ED646903EF5B少校:3→服装
  • UUID:754A5D70-C59E-4E39-AA56-ED646903EF5B少校:4→家庭用品
  • ...

然后,当应用程序的用户在商店中移动时,您可以在跨越区域边界时触发操作。

这样你就可以:

  1. 获取进入和退出回拨
  2. 开始测距以找出次要值(可以是每个商店或每个信标的唯一值)
  3. 发送本地通知

答案 2 :(得分:2)

您需要做的是确保所有信标都具有相同的UUID。然后,注册一个CLBeaconRegion用于监视,仅指定该UUID。不包括主要或次要价值。这将导致在输入与该UUID匹配的任何信标时调用didEnterRegion:(主要和次要值是通配符)。但是,这里返回的CLBeaconRegion只有UUID,没有主要/次要,就像你注册它一样,所以你不知道确切地知道了哪个灯塔。要确切了解设备所看到的信标,请在调用didEnterRegion:时,通过输入的区域告知位置管理员startRangingBeaconsInRegion:。然后,位置管理员将通过didRangeBeacons:通过一系列CLBeacons回叫给您。这些CLBeacons将知道它们的主要和次要值,您可以从中确定用户所在的商店的确切位置(因为您知道部署了主要/次要的信标的位置)。这可以在应用程序处于后台时完成。

这样您只注册一个CLBeaconRegion,但您仍然可以与任何与您注册的UUID匹配的信标进行交互。

我已经使用这种方法在一个区域内成功部署了80多个信标,这些信标都在前台和后台成功触发。您无需用户打开应用即可完成此操作。