【问题标题】:Beacon Ranging in Background on iOSiOS 上的后台信标测距
【发布时间】:2014-12-09 16:41:03
【问题描述】:

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

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

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

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

我没有在此处包含代码 sn-ps,因为问题不在于代码,它只是一个概念问题。如果需要任何说明或代码,我也可以添加。

谢谢

【问题讨论】:

  • 有什么答案可以解决您的问题吗?或者你能解决它吗?

标签: ios core-location ibeacon


【解决方案1】:

答案的最大部分是我的同事@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

【讨论】:

  • 如果用户在多任务器中手动终止了应用程序,这是否有效?
  • 在 multiasker 中终止应用程序将立即停止测距。但是在 iOS 7.1+ 上,如果检测到受监控的信标,它将在后台启动应用程序并重新启动该过程。在 iOS 7.0 上,在多任务器中终止应用程序将永远停止它,直到用户再次手动启动它。
  • 有道理。那么如果用户在信标范围内终止应用程序,它会立即重新启动吗?还是需要退出重新进入才能收到区域进入回调?
  • 您是否有任何应用程序实施“长时间运行任务”以便在后台继续测距超过 180 秒的经验?它们甚至可行吗? developer.apple.com/library/ios/documentation/iPhone/Conceptual/… 似乎表明它们是(从外部附件接收定期更新的应用程序),但我不知道这是否适用于信标的测距。
  • 适用于测距的是位置背景模式。您可以提出要求,然后根据需要进行范围,但您需要说服应用商店评论者这是合法的 - 例如。你有一个后台导航应用程序。 “外部配件”条款是指与 Apple Watch 等蓝牙设备连接——我认为它不适用于 CoreLocation。
【解决方案2】:

您需要做的是确保所有信标都具有相同的 UUID。然后,注册一个 CLBeaconRegion 进行监控,只指定该 UUID。不要包含主要或次要值。这将导致在输入任何与该 UUID 匹配的信标时调用didEnterRegion:(主要和次要值是通配符)。但是,此处返回的 CLBeaconRegion 将只有 UUID,没有主要/次要,就像您注册它的方式一样,因此您不知道确切触发了哪个信标。要准确确定您的设备看到的是哪个信标,当调用didEnterRegion: 时,请告诉位置管理器startRangingBeaconsInRegion: 输入区域。然后位置管理器将通过didRangeBeacons: 传递一个CLBeacons 数组回电给您。这些 CLBeacon 将知道它们的主要和次要值,从中您可以准确地确定用户在商店的哪个部分(因为您知道具有该主要/次要的信标部署在哪里)。这一切都可以在应用处于后台时完成。

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

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

【讨论】:

  • 这正是我现在所做的。但这不允许您在进入该区域后继续对信标进行测距。因此,如果用户进入该区域,我可以立即进行测距以查看正在发射的信标,但如果他们在该区域内四处移动,我无法继续测距以查看他们正在移动到哪个信标。
  • 一旦您进入该区域并在该区域上调用 startRangingBeaconsInRegion,位置管理器将继续测距它看到的具有该 UUID 的任何信标,直到调用 didExitRegion,此时您应该调用 stopRangingBeaconsInRegion。这不是你正在经历的吗?
  • 奇怪。不,这不是我正在经历的。对我来说,一旦我收到didEnterRegion,我就会打电话给startRangingBeaconsInRegion,这将给我定期回拨(每秒一个)长达大约 10 秒。之后就什么都没有了。
  • 您是否启用了任何特定的后台模式?或者您是否专门配置了任何东西以允许在后台继续测距?
  • 此功能需要位置更新后台模式(至少在 iOS 8 上)
【解决方案3】:

我可能会通过将商店分成多个区域来建模。它们的建模方式将取决于您在触发通知时所拥有的用例。

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

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

例如:

  • UUID:754A5D70-C59E-4E39-AA56-ED646903EF5B Major:1 → 入口
  • UUID:754A5D70-C59E-4E39-AA56-ED646903EF5B Major:2 → 收银机
  • UUID:754A5D70-C59E-4E39-AA56-ED646903EF5B Major:3 → 服装
  • UUID:754A5D70-C59E-4E39-AA56-ED646903EF5B Major:4 → 家居用品
  • ...

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

这样你可以:

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

【讨论】:

  • 我想过。问题在于将信标分成多个区域可能不够精细。在某些情况下,我可能需要显示与特定单个信标相关的报价或信息。据我了解,iOS 对所有应用程序的全球限制为 20 个区域,因此不实用。
  • 我认为您可以解决这个问题,请参阅我的编辑 - 试图解决这个问题。
  • 感谢您的澄清。另一个问题是,一旦我收到区域进入回调,我只能在 10 秒左右范围内定位信标,之后,应用程序会回到后台。因此,如果我们有一个较大的服装区,我们只能在该区域的边缘进行范围,但不能在该区域内进行范围,以防我需要显示有关特定信标的通知。除非用户打开应用。
  • @csexton 关于这项技术是绝对正确的。有关延长测距时间的信息,请参阅我提供的答案。
猜你喜欢
  • 2014-11-09
  • 1970-01-01
  • 1970-01-01
  • 2017-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多