在后台将iPhone作为iBeacon运行


71

是否可以将iOS 7设备作为Bluetooth LE外围设备(iBeacon)运行,并在后台做广告?我已经能够使用下面的代码在前台进行广告发布,并且可以从其他iOS设备上看到它,但是一旦我回到主屏幕,它便停止了广告发布。我确实在plist中添加了蓝牙外围设备背景模式,但这似乎无济于事,尽管我确实得到提示,说该设备希望在背景中使用蓝牙。我是在做错什么,还是在iOS 7中是不可能的?

peripManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
  if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
      return;
  }

  NSString *identifier = @"MyBeacon";
  //Construct the region
  CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:identifier];

  //Passing nil will use the device default power
  NSDictionary *payload = [beaconRegion peripheralDataWithMeasuredPower:nil];

  //Start advertising
  [peripManager startAdvertising:payload];
}

这是接收/收听端的代码:

- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons
           inRegion:(CLBeaconRegion *)region
{
//Check if we have moved closer or farther away from the iBeacon…
if (beacons.count > 0) {
    CLBeacon *beacon = [beacons objectAtIndex:0];

    switch (beacon.proximity) {
        case CLProximityImmediate:
            [self log:[NSString stringWithFormat:@"You're Sitting on it! %li", (long)beacon.rssi]];
            break;
        case CLProximityNear:
            [self log:[NSString stringWithFormat:@"Getting Warmer! %li", (long)beacon.rssi]];
            break;
        default:
            [self log:[NSString stringWithFormat:@"It's around here somewhere! %li", (long)beacon.rssi]];
            break;
    }
}
}

您是说当另一台设备进入信标范围时,该区域不会触发吗?还是在触发区域后您无法从信标中获取其他详细信息?
2013年

7
根据苹果开发者论坛的说法,iBeacons仅在前台广播到该应用程序。它可能与Core Bluetooth的节能特性有关。苹果需要修改蓝牙广告的所有方面以广播信标,根据文档,当应用程序在后台运行时,这是不可用的。developer.apple.com/library/ios/documentation/...
PaulWoodIII

1
@Wain苹果开发人员说,论坛不支持空白点,但这就是使用API​​,我仍然希望我们找到一种反向工程使其在后台用作自定义外围设备的方法。我仍然怀疑是否可以这样做,因为后台应用程序外围广告中的广告包溢出区域较小
PaulWoodIII,2013年

1
@jpcoder如果您正在寻找溢出区域,那么您就对了,应该可以找到它,但这是令我担心的“ CBAdvertisementDataLocalNameKey广告密钥被忽略,而外围设备的本地名称未被广告”。以及稍后有关CBAdvertisementDataOverflowServiceUUIDsKey的信息:“由于此区域中存储的数据的性质,此处列出的UUID是“尽力而为”的方法,可能并不总是准确的。有关广告数据溢出区域的详细信息,请参见startAdvertising:方法在CBPeripheralManager类参考中。”
PaulWoodIII 2013年

1
@Wain是的,一个基本的CBPeripheralManager将继续做广告,我在这里还有另一个问题:stackoverflow.com/questions/18906988/…(请稍等,如果您可以进行清晰的编辑,我将不胜感激),询问iBeacon是什么服务是。从理论上讲,如果我们知道他们如何在Corebluetooth框架内制作iBeacon,我们也许可以使用CBPeripheralManager在后台对其进行广告。
PaulWoodIII

Answers:


50

标准CoreBluetooth广告可以在应用程序在后台播放时播放,但如果它们是从CLBeaconRegion字典开始的,则不能播放。解决方法是完全放弃CoreLocation框架,仅使用CoreBlueTooth创建自己的邻近度“框架”。

您仍然需要在Info.plist文件中使用适当的背景说明符(例如bluetooth-peripheralbluetooth-central)。

代码看起来像这样:

1)使用创建标准外围广告 CBPeripheralManager

NSDictionary *advertisingData = @{CBAdvertisementDataLocalNameKey:@"my-peripheral",
                                  CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:identifier]]};

// Start advertising over BLE
[peripheralManager startAdvertising:advertisingData];

2)使用useCBCentralManager通过您指定的UUID扫描该服务。

NSDictionary *scanOptions = @{CBCentralManagerScanOptionAllowDuplicatesKey:@(YES)};
NSArray *services = @[[CBUUID UUIDWithString:identifier]];

[centralManager scanForPeripheralsWithServices:services options:scanOptions];

3)在CBCentralManagerDelegate方法中didDiscoverPeripheral,读取RSSI广告的值。

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{

    NSLog(@"RSSI: %d", [RSSI intValue]);
}

4)将RSSI值转换为距离。

- (INDetectorRange)convertRSSItoINProximity:(NSInteger)proximity
{
    if (proximity < -70)
        return INDetectorRangeFar;
    if (proximity < -55)
        return INDetectorRangeNear;
    if (proximity < 0)
        return INDetectorRangeImmediate;

    return INDetectorRangeUnknown;
}

我发现我需要“轻松”或“平均” RSSI值以使任何可行的方法。这与处理任何传感器数据(例如,加速度计数据)没有什么不同。

我有这个概念,希望能在某个时候将其发布在某个地方。

另外,如果遇到问题,请使用docs(《核心蓝牙编程指南》)。

更新:Github上完整的代码示例。作为工作相关项目的一部分,我从事此工作

更新#2: 苹果发布了iOS7.1的iBeacon后台行为的重大改进


这是解决问题的另一种实现方式,还是iBeacon?从我看到的结果来看,另一部电话不会将其注册为iBeacon,并且您将不会从后台获得相同的唤醒,并输入使用CoreLocation iBeacon将获得的退出区域回调。
PaulWoodIII

1
@bentford我看到它在后台运行(当您说到主屏幕或切换应用程序时),但是如果该应用程序被iOS终止以节省内存,该应用程序是否仍在播发广告/唤醒?我在文档中看到,我们可以“调用CBCentralManager类的connectPeripheral:options:方法,并且由于连接请求不会超时,因此找到外围设备后,iOS设备将重新连接”。我仍然不清楚外围设备是否继续以这种方式做广告。谢谢!
PotatoFro 2014年

2
不幸的是,当应用程序移至后台时,数据有效载荷(即iBeacon信息)被剥离。在iOS 7.0.5上测试。
valvoline 2014年

2
这实际上并不能使应用程序完全像iBeacon那样工作,对吗?就像这样,它不支持Major / Minor值,并且传统的CoreLocation API是否无法检测到它?
Yazid 2014年

2
@Yazid对。它不使用或不与传统的CoreLocation API一起使用。但是它确实允许您在支持后台广播和检测的同时在应用中复制iBeacon行为。
bentford

4

你能闻到iBeacon显示?本文讨论了Estimotes的使用以及Mac和iOS设备上的广告。您需要在项目目标中检查功能“充当Bluetooth LE附件”。


有趣的是,iOS不允许在后台进行iBeacon广告。但是它将允许您CoreBluetooth用作外围设备或中央设备。iBeacons,没有骰子(至少暂时没有,但这是希望)。
Yazid 2014年

2

不,iOS设备仅在进行广告发布的应用程序在前台运行时才发布iBeacon。因此,如果您切换到另一个应用程序或设备进入睡眠状态,则广告将停止。

当然,如果您真的希望继续播发广告,请禁用空闲计时器并执行“引导访问”,以使iOs设备不会进入睡眠状态,并且任何人都无法切换到另一应用程序。


1
这是一个疯狂的解决方案,在iOS7.1上如何?您所说的“空闲计时器”是什么意思?
bluefloyd14年

是的,我不建议使用iOS设备作为iBeacon广告商。显然,正确的解决方案是获得实际的专用iBeacon设备(您可以购买其中的一些,但就目前而言,它们太贵了)。您甚至可以使用Raspberry Pi和BTLE USB软件狗将其配置为iBeacon广告商。我所说的“空闲时间”是指睡眠计时器,该计时器在到期时会导致设备进入睡眠状态。
RawMean 2014年

1

我也希望能够设置我的(测试)应用程序,以便从后台宣传iBeacon。UIBackgroundModes info.plist键上的文档建议蓝牙外设键可能有效,但似乎无效。(我刚刚在几分钟前进行了测试。)

我现在要做的是按照RawMean的建议将空闲计时器设置为禁用,然后将屏幕亮度设置为0。最后,当我的测试应用程序充当iBeacon时,我添加了一个震动事件处理程序来点亮屏幕再次上升30秒。将屏幕调到尽可能低的程度有助于一定程度地减少电池消耗。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.