后台 iBeacon 监控和测距
iBeacon monitoring and ranging in background
我花了几个月的时间开发基于 iBeacons 的应用程序,我真的很沮丧。
总体思路是,当检测到信标时,会通知用户特定于该 iBeacon 的信息。
应用程序设计如下,所有iBeacons都有相同的UUID,Major确定建筑物(博物馆,商店...),Minor确定具体产品(图片,鞋子...)。所以这个应用程序可能服务于多个客户端。
当应用程序启动时,我开始使用我们的 UUID 对区域进行监控和测距。当应用程序处于前台时,一切正常。但是在后台或暂停状态下问题开始了。背景或暂停状态不允许测距。
我知道当您进入或离开信标区域时,该应用程序将在后台启动约 5 秒钟。您可以在这五秒钟内在后台进行测距,之后 iOS 将再次暂停您的应用程序。
我使用这里学到的技术设法在后台将范围延长了 3 分钟。我还通过 notifyEntryStateOnDisplay = YES;
获得额外回调
但这还不够,如果客户端进入应用处于后台或挂起状态的区域,他将收到通知。并且在额外的3分钟内,如果测距检测到另一个iBeacon,他会收到通知,但是当3分钟后台任务到期时,如果没有触发区域退出,他将不会再次收到任何通知。
这样的场景没有真正的解决方案吗?我认为这是一种非常常见的情况,我很惊讶没有办法处理它。
已编辑:我试图通过监控两个区域来找到解决问题的方法,正如 David Young 在他的回复中所推荐的那样。为了获得更多entry/exit地区的活动。
我添加了我实现的代码以尝试监视两个区域。
但是我做错了什么 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 毫秒显示在控制台上。
我怀疑停止和重新启动测距打破了预期的回调流程,但是当只有一个区域在范围内时,回调按预期每秒发生一次。
您描述的问题很常见。除了延长背景测距时间(您已经完成)外,iOS 没有灵丹妙药。
另外两种技术可能会有所帮助。这两种技术都涉及在您从一个信标传递到下一个时获得新进入事件 :
获取允许您调低发射机功率(我公司的 RadBeacon 产品允许这样做)的硬件信标,这样传输就不会重叠。这样,当您从一个信标移动到另一个信标时,您将获得一个退出事件,然后是一个新的进入事件。
重新设计您的标识符场景,使 major 字段专门用于识别多达 20 个不同的区域(基于 UUID 和 major 1-20)。然后监控所有这些区域。您的个人信标仍然可以根据需要使用未成年人,特别是作为触发消息传递的关键。放置信标时,请确保具有重叠传输的 none 共享相同的专业。当您从一个移动到另一个时,这将确保一个新的后台进入事件。
背景中的信标范围在 iOS 8 上工作得很好,前提是你能克服所有障碍。
首先,您需要正确的授权。将密钥 NSLocationAlwaysUsageDescription
添加到您的 Info.plist,然后调用
[self.locationManager requestAlwaysAuthorization];
您的应用必须具有 Background Mode
的 Location Updates
。在 Info.plist 中指定或通过功能(与构建设置平行)指定。
然后使用
在 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];
我花了几个月的时间开发基于 iBeacons 的应用程序,我真的很沮丧。
总体思路是,当检测到信标时,会通知用户特定于该 iBeacon 的信息。
应用程序设计如下,所有iBeacons都有相同的UUID,Major确定建筑物(博物馆,商店...),Minor确定具体产品(图片,鞋子...)。所以这个应用程序可能服务于多个客户端。
当应用程序启动时,我开始使用我们的 UUID 对区域进行监控和测距。当应用程序处于前台时,一切正常。但是在后台或暂停状态下问题开始了。背景或暂停状态不允许测距。
我知道当您进入或离开信标区域时,该应用程序将在后台启动约 5 秒钟。您可以在这五秒钟内在后台进行测距,之后 iOS 将再次暂停您的应用程序。
我使用这里学到的技术设法在后台将范围延长了 3 分钟。我还通过 notifyEntryStateOnDisplay = YES;
获得额外回调但这还不够,如果客户端进入应用处于后台或挂起状态的区域,他将收到通知。并且在额外的3分钟内,如果测距检测到另一个iBeacon,他会收到通知,但是当3分钟后台任务到期时,如果没有触发区域退出,他将不会再次收到任何通知。
这样的场景没有真正的解决方案吗?我认为这是一种非常常见的情况,我很惊讶没有办法处理它。
已编辑:我试图通过监控两个区域来找到解决问题的方法,正如 David Young 在他的回复中所推荐的那样。为了获得更多entry/exit地区的活动。
我添加了我实现的代码以尝试监视两个区域。
但是我做错了什么 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 毫秒显示在控制台上。
我怀疑停止和重新启动测距打破了预期的回调流程,但是当只有一个区域在范围内时,回调按预期每秒发生一次。
您描述的问题很常见。除了延长背景测距时间(您已经完成)外,iOS 没有灵丹妙药。
另外两种技术可能会有所帮助。这两种技术都涉及在您从一个信标传递到下一个时获得新进入事件 :
获取允许您调低发射机功率(我公司的 RadBeacon 产品允许这样做)的硬件信标,这样传输就不会重叠。这样,当您从一个信标移动到另一个信标时,您将获得一个退出事件,然后是一个新的进入事件。
重新设计您的标识符场景,使 major 字段专门用于识别多达 20 个不同的区域(基于 UUID 和 major 1-20)。然后监控所有这些区域。您的个人信标仍然可以根据需要使用未成年人,特别是作为触发消息传递的关键。放置信标时,请确保具有重叠传输的 none 共享相同的专业。当您从一个移动到另一个时,这将确保一个新的后台进入事件。
背景中的信标范围在 iOS 8 上工作得很好,前提是你能克服所有障碍。
首先,您需要正确的授权。将密钥 NSLocationAlwaysUsageDescription
添加到您的 Info.plist,然后调用
[self.locationManager requestAlwaysAuthorization];
您的应用必须具有 Background Mode
的 Location Updates
。在 Info.plist 中指定或通过功能(与构建设置平行)指定。
然后使用
在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];