Запустите 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's around here somewhere! %li", (long)beacon.rssi]];
            break;
    }
}
}

person jpcoder    schedule 22.09.2013    source источник
comment
Вы имеете в виду, что регион не срабатывает, когда другое устройство попадает в зону действия маяка? Или что вы не можете получить дополнительную информацию от маяка после срабатывания региона?   -  person Wain    schedule 22.09.2013
comment
@Wain Смотрите код ниже. Это то, что я использую на принимающей/слушающей стороне. Этот обратный вызов запускается, когда приведенный выше рекламный код выполняется на переднем плане, но не когда приложение находится в рекламном приложении в фоновом режиме.   -  person jpcoder    schedule 23.09.2013
comment
@Wain Я добавил код получения в исходный пост выше.   -  person jpcoder    schedule 23.09.2013
comment
Согласно форумам разработчиков Apple, iBeacons будет транслироваться только в приложение на переднем плане. Вероятно, это связано с энергосберегающими характеристиками Core Bluetooth. Apple необходимо изменить все аспекты рекламы Bluetooth для трансляции маяков, и это недоступно, когда приложение находится в фоновом режиме, согласно документам. developer.apple.com/library/ios/ документация/   -  person PaulWoodIII    schedule 23.09.2013
comment
@ChinaPaul, этот документ говорит, что все должно работать с правильными фоновыми клавишами, просто медленнее и с некоторыми ограничениями. Из режима фонового выполнения Bluetooth-периферии. Это не дает представления о том, что медленнее. Тем не менее, форум разработчиков определенно указывает на проблемы...   -  person Wain    schedule 23.09.2013
comment
@Wain Разработчики Apple прямо говорят, что это не поддерживается на форумах, но это с использованием API, я все еще надеюсь, что мы найдем способ перепроектировать его для использования в фоновом режиме в качестве пользовательского периферийного устройства. Я все еще сомневаюсь, что это можно сделать из-за того, что область переполнения рекламных пакетов меньше на фоновых приложениях, периферийных рекламных объявлениях.   -  person PaulWoodIII    schedule 23.09.2013
comment
@ChinaPaul Весь этот разговор об области переполнения в документах подразумевает, что что-то должно работать в фоновом режиме. Тогда вопрос в том, что работает.   -  person jpcoder    schedule 23.09.2013
comment
@ChinaPaul, спасибо за информацию. У вас есть ссылка на ветку, где это было сделано явно. Я хотел бы создать отчет об ошибке и сослаться на него. Спасибо   -  person Wain    schedule 23.09.2013
comment
@jpcoder вы правы насчет области переполнения, если вы ее ищете, вы должны ее найти, но вот что меня беспокоит. Ключ объявления CBAdvertisementDataLocalNameKey игнорируется, а локальное имя периферийного устройства не рекламируется. и позже о CBAdvertisementDataOverflowServiceUUIDsKey: из-за характера данных, хранящихся в этой области, UUID, перечисленные здесь, являются «максимальными усилиями» и могут не всегда быть точными. Дополнительные сведения об области переполнения рекламных данных см. в описании метода startAdvertising: в справочнике по классам CBPeripheralManager.   -  person PaulWoodIII    schedule 23.09.2013
comment
@Wain Надеюсь, это поможет: devforums.apple.com/message/832089#832089   -  person PaulWoodIII    schedule 23.09.2013
comment
@ChinaPaul, спасибо. Последний вопрос, это конкретно iBeacon? Итак, базовый CBPeripheralManager продолжает рекламировать в фоновом режиме?   -  person Wain    schedule 23.09.2013
comment
@Wain Да, базовый CBPeripheralManager будет продолжать рекламировать, у меня есть еще один вопрос: stackoverflow.com/questions/18906988/ (приостановлено, поэтому, если вы можете отредактировать его с некоторой ясностью, я был бы признателен), которые спрашивают, что такое служба iBeacon. Теоретически, если бы мы знали, как они создали iBeacon внутри фреймворка Corebluetooth, мы могли бы использовать CBPeripheralManager для его рекламы в фоновом режиме.   -  person PaulWoodIII    schedule 24.09.2013
comment
Итак, вы можете заставить CBPeripheralManager рекламировать что-то кроме CLBeaconRegion в фоновом режиме с помощью BLE? Вы не знаете, есть ли где-нибудь такой пример?   -  person jpcoder    schedule 24.09.2013
comment
@ChinaPaul: вы можете легко использовать фреймворк CoreBluetooth для рекламы в качестве iBeacon, однако он по-прежнему выглядит так, как будто он не уважает фоновый режим правильно, когда вы это делаете. Если вы сможете найти решение, пожалуйста, сообщите нам.   -  person Senseful    schedule 05.01.2014
comment
@jpcoder Я разработал библиотеку, которая может быть полезна в вашем случае (реклама в фоновом режиме): github.com/omergul123/Discovery   -  person Ömer Faruk Gül    schedule 13.02.2015


Ответы (4)


Стандартные объявления 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) используйте 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, чтобы получить что-то работоспособное. Это ничем не отличается от работы с любыми данными датчиков (например, данными акселерометра).

У меня есть эта концепция, полностью работающая, надеюсь когда-нибудь опубликовать ее где-нибудь.

Кроме того, используйте документы (Основное руководство по программированию Bluetooth), если вы застряли.

Обновление: полный образец кода размещен на Github. Я работал над этим в рамках проекта, связанного с работой.

Обновление №2: Apple выпускает значительные улучшения к фоновому поведению iBeacon для iOS7.1

person bentford    schedule 12.11.2013
comment
это еще одна реализация для решения проблемы или это iBeacon? Из того, что я вижу, другой телефон не зарегистрирует это как iBeacon, и вы все равно не проснетесь из фона и не введете обратные вызовы области выхода, которые вы получили бы с iBeacon CoreLocation. - person PaulWoodIII; 09.12.2013
comment
Правильно. Это вообще не будет использовать инфраструктуру CoreLocation iBeacon. Он использует CoreBluetooth, чтобы делать то же самое, что и iBeacons, но он работает в фоновом режиме и будит ваше приложение для выполнения обновлений. - person bentford; 17.12.2013
comment
@bentford Я вижу, что это работает в фоновом режиме (когда вы говорите, перейдите на главный экран или переключите приложения), но приложение по-прежнему рекламирует / просыпается в случае, если iOS завершает его работу для экономии памяти? Я видел в документе, что мы можем вызвать метод connectPeripheral:options: класса CBCentralManager, и, поскольку время ожидания запросов на подключение не истекает, устройство iOS повторно подключится, когда периферийное устройство будет найдено. Мне все еще неясно, продолжает ли периферийное устройство рекламировать таким образом. Спасибо! - person PotatoFro; 10.01.2014
comment
@PotatoFro Насколько мне известно, периферийное устройство прекращает вещание, если ваши приложения уничтожаются пользователем или iOS. - person bentford; 11.01.2014
comment
@bentford Интересно! Интересно, можно ли повторно запустить периферийное вещание, когда приложение пробуждается в фоновом режиме для выполнения другой задачи? (возможно, периодическое обновление сервера или при использовании значительного изменения местоположения) - person PotatoFro; 13.01.2014
comment
К сожалению, полезные данные (например, информация iBeacon) удаляются, когда приложение переходит в фоновый режим. Протестировано на iOS 7.0.5. - person valvoline; 06.02.2014
comment
@valvoline, можете ли вы объяснить, как потеря информации iBeacon вызывает проблему? - person bluefloyd8; 31.03.2014
comment
Это на самом деле не заставляет приложение работать точно так же, как iBeacon, верно? Например, он не поддерживает значения Major/Minor и не обнаруживается традиционными API CoreLocation? - person Yazid; 04.04.2014
comment
@Язид Верно. Он не использует и не работает с традиционными API-интерфейсами CoreLocation. Но это позволяет вам воспроизвести поведение iBeacon в вашем приложении, поддерживая фоновую трансляцию и обнаружение. - person bentford; 04.04.2014
comment
Можете ли вы рассказать о том, как вы видите это масштабирование для большего количества маяков? -- Является ли подход, который вы описываете в «историческом» разделе вашего github, вашим рекомендуемым подходом? -- Каково максимальное количество различных UUID, которые вы можете отслеживать параллельно? - person Daij-Djan; 20.07.2014
comment
Хотя это и не идеально, это решение было идеальным для меня и в любом случае имитировало маяк. Он должен быть отмечен как правильный ответ. - person Jacob King; 17.12.2015
comment
Это решение изменяет имя устройства, которое видно по bluetooth других устройств. Не приведет ли это к отключению других устройств, например. наушники, Apple Watch и т. д.? Есть ли какое-либо другое поле, в котором мы можем отправить около 4 байтов данных, которые не повлияют на другую связь Bluetooth на устройстве iOS? - person Abdurrahman Mubeen Ali; 16.10.2017
comment
@bentford Можете ли вы проверить мой вопрос? У меня проблема с вашим решением. stackoverflow.com/questions/61676910/ - person uyarc; 09.05.2020

В статье Вы чувствуете запах iBeacon? обсуждается и то, и другое. использование Estimotes и рекламы с устройств Mac и iOS. Вам необходимо проверить возможность «Действует как аксессуар Bluetooth LE» в цели проекта.

person Cameron Lowell Palmer    schedule 23.11.2013
comment
Интересно, что iOS не разрешает рекламу iBeacon в фоновом режиме. Однако это позволит вам использовать CoreBluetooth в качестве периферийного или центрального устройства. iBeacons, никаких кубиков (по крайней мере пока, но будем надеяться). - person Yazid; 19.04.2014

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

Конечно, если вы действительно хотите, чтобы реклама продолжалась, отключите таймер простоя и сделайте Гид-доступ, чтобы устройство iOs не ушло в спящий режим и никто не смог переключиться на другое приложение.

person RawMean    schedule 18.10.2013
comment
Это сумасшедшее решение, как насчет iOS7.1? Что вы имеете в виду под таймером простоя? - person bluefloyd8; 31.03.2014
comment
Да, использование устройства iOS в качестве рекламодателя iBeacon — не то решение, которое я бы рекомендовал. Очевидно, что правильное решение — приобрести настоящее выделенное устройство iBeacon (есть несколько таких, которые вы можете купить, но они слишком дороги для того, что они стоят на данный момент). Вы даже можете использовать Raspberry Pi и USB-ключ BTLE, чтобы настроить его в качестве рекламодателя iBeacon. Под временем простоя я имею в виду таймер сна, который по истечении времени заставляет устройство переходить в спящий режим. - person RawMean; 31.03.2014

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

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

person Duncan C    schedule 29.10.2013