Ранжирование маяков iOS в фоновом режиме

Я знаю, что основные цели

-(void)locationManager:(CLLocationManager*)manager
       didRangeBeacons:(NSArray*)beacons
              inRegion:(CLBeaconRegion*)region

должен работать, пока приложение находится на переднем плане.

Находясь в фоновом режиме,

- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region

используется для обнаружения маяков, но не с таким количеством информации, как хотелось бы (второстепенные и основные идентификаторы из CLBeacons для предоставления контекстной информации).

Я знаю, что методы делегата из CLLocationManager позволяют ненадолго запустить код в фоновом режиме.

Можно ли сделать что-то вроде этого: - начать кратко ранжировать маяки в фоновом режиме при входе в регион - вызвать веб-службу в фоновом режиме в соответствии с младшими/основными идентификаторами - отправить UILocalNotification, настроенный с возвращаемым результатом веб-службы

- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region
{

    if (![region isKindOfClass:[CLBeaconRegion class]]) return;


    [locationManager startRangingBeaconsInRegion:(CLBeaconRegion*)region];

}

а потом :

-(void)locationManager:(CLLocationManager*)manager
       didRangeBeacons:(NSArray*)beacons
              inRegion:(CLBeaconRegion*)region
{

    if (beacons.count == 0) return;

    CLBeacon *foundBeacon = [sortedBeacons firstObject];

    // DO STUFF IN BACKGROUND
    if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive){
        //Call for a webservice according to minor /major

        //Dispatch contextual notification
        // ^success(...)
        UILocalNotification * theNotification = [[UILocalNotification alloc] init];
        theNotification.alertBody = [NSString stringWithFormat:@""];

        theNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];

        [[UIApplication sharedApplication] scheduleLocalNotification:theNotification];


    }
    else{   //DO STUFF IN FOREGROUND
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"proximity"
                                                                       ascending:YES];
        NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"accuracy"
                                                                        ascending:YES];

        NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor,sortDescriptor2];
        NSArray *sortedBeacons = [beacons sortedArrayUsingDescriptors:sortDescriptors];
        //determine which beacon will be used to trigger foreground event
    }



}

person Romain Dorange    schedule 17.01.2014    source источник
comment
У меня есть аналогичное требование в приложении. Не могли бы вы придумать способ сделать это?   -  person Chengappa C D    schedule 20.08.2015


Ответы (5)


Я испытал точно такой же сценарий. Я использовал шаблон ниже:

// start background task
- (void)beginBackgroundTask {
    if (self.backgroundTask != UIBackgroundTaskInvalid) {
        [self endBackgroundTask];
    }

    self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [self endBackgroundTask];
    }];
}

// end background task
- (void)endBackgroundTask {
    if (self.backgroundTask != UIBackgroundTaskInvalid) {
        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
    }
    self.backgroundTask = UIBackgroundTaskInvalid;
}

Это обычные методы, которые я использовал для пометки/снятия пометки фоновых задач, таких как вызов веб-службы.

Вот некоторые из них:

[self beginBackgroundTask];

[[MySessionManager sharedInstance] POST:MoteList parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
    // process the response

    [self endBackgroundTask];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
    // error handling
}];

Кстати, этот период времени фоновой задачи ограничен 3 минутами.

Существует также другой вариант выполнения фоновой задачи в течение неограниченного периода времени: это использование многозадачного API, поддерживаемого NSURLSession, начиная с iOS 7. Но его можно использовать только для задач загрузки/выгрузки. Если вам нужно выполнить запрос POST, ответ сервера должен быть загружаемыми данными json/xml. Приложение должно загрузить это в файл и выполнить программный анализ.

Я надеюсь, что это поможет вам.

person Zheng Huiying    schedule 10.02.2014

Отвечая на ваш первоначальный вопрос: можно ли работать в фоновом режиме? Ответ - да, но вы должны остановить это как можно скорее. iOS в любом случае остановит вас, но сохранение включенного диапазона будет разряжать батарею, и это не будет иметь смысла.

У меня такая же проблема.

  1. Определить основной/второстепенный один раз в регионе.
  2. Позвоните в веб-службу для получения обновленной информации.
  3. При мониторинге UUID вы не можете обнаружить серьезные/незначительные изменения для перекрывающихся маяков с одним и тем же UUID.

Мое решение выглядит следующим образом:

  1. Монитор UUID
  2. Оказавшись в регионе, прекратите мониторинг и начните определять ближайший маяк.
  3. После определения ближайшего маяка (иногда после до 3 вызовов метода делегата ранжирования) остановите ранжирование.
  4. В его момент также определяем, бежим ли мы в фоновом режиме (как видите, я ранжировал и остановил ранжирование, не спрашивая режим бега).
  5. Если мы находимся в режиме переднего плана: я показываю верхний баннер с информацией о маяке. И запланируйте еще одно ранжирование через 3 секунды, чтобы обнаружить новый маяк.
  6. Если мы в фоновом режиме: я отправляю локальное уведомление.
  7. В обоих режимах я откладываю вызов веб-службы до тех пор, пока пользователь не отреагирует на уведомление. Тем временем я показываю общее сообщение для маяка, выбранного из местного словаря: «Нажмите, чтобы увидеть сегодняшние специальные акции».

Я знаю, это звучит запутанно, и это так. Потребовалось в полевых испытаниях настроить его. Он удовлетворяет минимальным требованиям, не завися от быстрого подключения к Интернету.

Я попробую фоновые задачи, предложенные @ZhenHuiying, это звучит жизнеспособно, если маяки находятся на улице. В моем случае сигнал сотовой связи в помещении недостаточно надежен, чтобы отображать обновленные данные в фоновом режиме.

person Juan Valera    schedule 13.07.2015

Вы должны иметь возможность отправить запрос веб-службе, но не сможете надежно получить ответ. Ваше приложение бодрствует только около 5 секунд после уведомления маяка.

МОЖЕТ быть возможно запросить фоновое время для завершения вашей сетевой транзакции - я не эксперт по обработке в фоновом режиме.

Вам нужно, чтобы пользователь разблокировал телефон, чтобы в любом случае делать что-либо с пользовательским интерфейсом. Почему бы вашему серверу не отправить push-уведомление в ответ на ваше сообщение? Это достигает всех ваших целей.

person Duncan C    schedule 17.01.2014
comment
Да, но использование push-уведомлений требует от нас добавления еще одного уровня абстракции и технического уровня (сертификаты и т. д.). Поскольку мы хотели бы предоставить межотраслевую структуру, которую можно было бы использовать в существующих приложениях, уже использующих push-уведомления, мне интересно обойтись без нее. Я уже работал над приложением для недвижимости: вы идете в город, и ваше местоположение определяется с помощью startMonitoringSignificantLocationChanges, мы ищем в локальной базе данных идентификатор почтового индекса, полученный в методе делегата, вызываем с ним веб-сервис и отображаем UILocalNotification с количеством свойств. - person Romain Dorange; 17.01.2014

Если вам действительно нужен ответ на вызов веб-службы для отображения уведомления, то @duncan-c прав, говоря, что он может не ответить в течение 5 секунд или около того, прежде чем ваше приложение снова перейдет в спящий режим.

Другой вариант — отправить push-уведомление на ваше устройство iOS из вашего веб-сервиса. Преимущество этого подхода в том, что оно будет доставлено на ваш телефон, даже если ваше приложение снова заснет. Недостатком этого подхода является то, что доставка push-уведомлений происходит не сразу — иногда они приходят через несколько минут. Вы должны решить, подходит ли это для вашего варианта использования.

person davidgyoung    schedule 17.01.2014

я пытаюсь что-то сделать с маяком в BackGrounds, это работает для меня, и я надеюсь, что это сработает для вас

первый шаг: добавьте этот код в приложение didFinishLaunchingWithOptions

 _locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[_locationManager setDistanceFilter:kCLDistanceFilterNone];
[_locationManager requestAlwaysAuthorization];


    _locationRegion=[[CLBeaconRegion alloc]
                     initWithProximityUUID:BLUE_SCENE
                     identifier:@"EstimoteSampleRegion"];

[_locationRegion setNotifyOnEntry:YES];
[_locationRegion setNotifyOnExit:YES];
[_locationRegion setNotifyEntryStateOnDisplay:YES];


[_locationManager startMonitoringForRegion:_locationRegion];

второй шаг: также добавьте этот код снова в эту функцию

-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region

и в этой функции

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{

что я обнаружил, что ваше приложение проснется в фоновом режиме всего на несколько секунд и войдет в эту функцию, состояние didDetermine, поэтому в эту секунду вы вызываете ранжирование для функции маяка и реализуете ее делегат в AppDelegate.

если вам нужна помощь, просто скажите мне

person khaled    schedule 05.02.2015