在iOS的背景中的烽火台

我理解监视和测距之间的差异,并且我明白iOS的局限性在于,在进入和退出区域时,只能在前台或后台进行信标定位( http://developer.radiusnetworks.com/2013 /11/13/ibeacon-monitoring-in-the-background-and-foreground.html )。 但我试图找出如何解决一个共同的情况。

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

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

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

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

谢谢

答案的最大部分是我的同事@csexton在另一个回答这个问题时所logging的技术。

为了解决转换后仅有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秒没有。

你可以阅读关于如何工作的完整的文章,以及testing结果: https : //github.com/RadiusNetworks/ibeacon-background-demo/tree/background-task

我可能通过将商店分成多个区域来build模。 如何build模将基于触发通知时的用例。

我会给他们所有相同的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. 获取进入和退出callback
  2. 开始测距,找出次要值(可能是每个商店或每个信标唯一)
  3. 发送本地通知

你需要做的是确保你所有的信标都有相同的UUID。 然后,注册一个用于监视的CLBeaconRegion,仅指定该UUID。 不要包含主要或次要的价值。 这将导致didEnterRegion:didEnterRegion:标匹配的UUID进入(主要和次要值通配符)时被调用。 但是,这里返回的CLBeaconRegion只有UUID,没有主要/次要,就像你如何注册它一样,所以你不知道究竟是哪一个信标。 为了弄清楚你的设备看到的是什么信标,当didEnterRegion:被调用时,告诉位置pipe理器startRangingBeaconsInRegion:用input的区域。 位置pipe理器会用didRangeBeacons:callback给你didRangeBeacons:传递一个CLBeacons数组。 这些CLBeacons将知道它们的主要和次要值,从中可以确定用户所在商店的哪个部分(因为您知道部署该主要/次要信标的位置)。 这可以在应用程序处于后台时完成。

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

我已经使用这种方法在一个区域成功部署了80多个信标,这些信标都成功地在前景和背景中发射。 您不需要用户打开应用程序来完成此操作。