Запуск iPhone в качестве iBeacon в фоновом режиме

Возможно ли запустить iOS 7-устройство в качестве периферийного устройства Bluetooth LE (iBeacon) и рекламировать его в фоновом режиме? Я смог получить его для рекламы на переднем плане с приведенным ниже кодом и увидеть его с другого устройства iOS, но как только я вернусь на главный экран, он прекратит рекламу. Я добавил bluetooth-периферийный режим фона в plist, но это, похоже, не помогло, хотя я получаю подсказку, говорящее, что устройство хочет использовать bluetooth в фоновом режиме. Я что-то делаю неправильно или это невозможно в 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 around here somewhere! %li", (long)beacon.rssi]];
            break;
    }
}
}

Ответ 1

Стандартные объявления CoreBluetooth могут транслироваться, когда приложение находится в фоновом режиме, но не в том случае, если они были запущены с помощью словаря CLBeaconRegion. Обходной путь состоит в том, чтобы полностью расколоть структуру CoreLocation и создать собственную "инфраструктуру" близости, используя только CoreBlueTooth.

Вам по-прежнему необходимо использовать соответствующие спецификаторы фона в файле Info.plist(например, bluetooth-peripheral и bluetooth-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 (Core Bluetooth Programming Guide).

Обновление: A полный пример кода включен в Github. Я работал над этим как часть проекта связанного с работой.

Обновление # 2: Apple выпустит основные улучшения в отношении поведения iBeacon для iOS7.1

Ответ 3

Нет, устройства iOS рекламируют только iBeacon, когда приложение, которое делает рекламу, запускается на переднем плане. поэтому, если вы переключаетесь на другое приложение или устройство переходит в режим сна, реклама останавливается.

Конечно, если вы действительно хотите, чтобы реклама продолжалась, отключите таймер простоя и сделайте Guided Access, чтобы устройство iOS не переходило в режим сна, и никто не может переключиться на другое приложение.

Ответ 4

Я также надеюсь, что смогу настроить мое (тестовое) приложение для рекламы iBeacon с фона. Документы в ключе UIBackgroundModes info.plist предполагают, что bluetooth-периферийный ключ может работать, но, похоже, он этого не делает. (Я только что проверил это несколько минут назад.)

То, что я делаю сейчас, - отключить таймер простоя, как предлагает RawMean, а затем установить яркость экрана на 0. Наконец, когда мое тестовое приложение действует как iBeacon, я добавляю обработчик события shake, который снова загорается экран в течение 30 секунд. Уменьшение яркости экрана при низком уровне помогает немного уменьшить расход батареи.