71

是否可以将 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;
    }
}
}
4

4 回答 4

52

标准的 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) 使用 use 使用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 值才能获得任何可行的结果。这与您使用任何传感器数据(例如加速度计数据)时没有什么不同。

我有这个概念完全可行,希望在某个时候在某个地方发布它。

此外,如果您遇到困难,请使用文档(核心蓝牙编程指南)。

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

更新 #2: Apple 发布 iOS7.1 的 iBeacon 背景行为的重大改进

于 2013-11-12T22:39:58.777 回答
4

你能闻到 iBeacon 的味道吗?文章讨论了 Estimotes 的使用以及来自 Mac 和 iOS 设备的广告。您需要检查项目目标中的“充当蓝牙 LE 附件”功能。

于 2013-11-23T19:20:25.100 回答
2

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

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

于 2013-10-18T02:29:01.160 回答
1

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

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

于 2013-10-29T13:58:42.490 回答