在后台运行iPhone作为iBeacon

时间:2013-09-22 13:26:26

标签: ios bluetooth bluetooth-lowenergy ibeacon

是否可以将iOS 7设备作为蓝牙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;
    }
}
}

5 个答案:

答案 0 :(得分:47)

标准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)使用CBCentralManager使用您指定的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(核心蓝牙编程指南)。

更新full code sample is up on Github。我作为work related project的一部分来处理这个问题。

更新#2: Apple release major improvements to iBeacon background behavior for iOS7.1

答案 1 :(得分:4)

Can you smell the iBeacon?文章讨论了Estimotes的使用以及Mac和iOS设备的广告。您需要在项目目标中检查“充当蓝牙LE附件”的功能。

答案 2 :(得分:2)

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

当然,如果你真的希望广告继续,请禁用空闲计时器并进行引导访问,以便iOs设备不会进入休眠状态,并且没有人可以切换到另一个应用程序。

答案 3 :(得分:1)

我也希望能够设置我的(测试)应用程序来从后台宣传iBeacon。 UIBackgroundModes info.plist键上的文档表明蓝牙外设密钥可能有效,但似乎没有。 (我刚刚在几分钟前测试过它。)

我现在正在做的是将空闲计时器设置为禁用,如RawMean所示,然后将屏幕亮度设置为0.最后,当我的测试应用程序充当iBeacon时,我添加了一个抖动事件处理程序,再次点亮屏幕30秒。将屏幕调暗尽可能低有助于减少电池消耗。

答案 4 :(得分:0)

这可以做到。我不想惹恼苹果工程师,所以我不会公开该算法。

总而言之,对服务UUID进行编码的溢出区域只是一堆字节,这些字节是无线传输的。您可以自己嗅一下。特别地,这是短哈希,其随后由一个热编码来表示。通过设置多个位来通信多个UUID。您将以这种方式发生碰撞。例如,UUID 1001的编码与3333相同。您可以自己检查一下:在iPhone的背景上广播UUID 1001,然后对3333进行另一次扫描。它将认为它确实接收了3333。