Будет ли iOS просыпаться с завершенным приложением, если оно зарегистрировано в местоположении для UIBackgroundModes?

Я знаю, что если приложение использует службу значительного изменения местоположения, iOS разбудит ее, если будет обновлено местоположение, даже если приложение будет завершено.

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

ОБНОВЛЕНИЕ: В то время, когда я спрашивал об этом, у меня не было времени проверить его. Но после того, как я получил ответ здесь, я написал этот фрагмент кода в своем делетете приложения, чтобы узнать, будет ли мое завершенное приложение перезапущено, когда оно получит обновление местоположения. Я показываю UILocalNotification, когда меня уведомляют об обновлении. Однако, когда я прекратил свое приложение, а затем изменил свое местоположение в городе, приложение не было перезаписано, и я не получил никаких обновлений. Можете ли вы сказать мне, что я делаю неправильно?

ОБНОВЛЕНИЕ # 2:. Согласно окончательным выводам в этом Q & A, нет ничего плохого в этом коде, и это ожидаемое поведение для приложения, которое использует стандартные службы определения местоположения, а не перезапуска после прекращение.

Я добавил местоположение в качестве одного из UIBackgroundModes в файле Info.plist.

И это связанные с местоположением части моего делегата приложения:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;

    m_locManager = [[CLLocationManager alloc] init];
    m_locManager.delegate = self;
    [m_locManager startUpdatingLocation];
    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [m_locManager startUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog("%@", [NSString stringWithFormat:@"Background Fail %@", [error localizedDescription]]);
}

- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation
{
    UILocalNotification * theNotification = [[UILocalNotification alloc] init];
    theNotification.alertBody = [NSString stringWithFormat:@"Background location %.06f %.06f %@" , newLocation.coordinate.latitude, newLocation.coordinate.longitude, newLocation.timestamp];
    theNotification.alertAction = @"Ok";

    theNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];

    [[UIApplication sharedApplication] scheduleLocalNotification:theNotification];
}

Ответ 1

Да, он будет вести себя одинаково, за исключением того, что он будет чаще получать обновления (и, следовательно, потребляет больше батареи).

Источник: состояния приложений и многозадачность в разделе "Отслеживание местоположения пользователя".

EDIT После повторного чтения кажется, что программа будет разбужена из приостановленного состояния, но не будет завершена. Я не думаю, что вам действительно нужен этот фоновый режим. Он предназначен для приложений, которым нужна прекрасная информация о местоположении (например, пошаговая навигация). Ознакомьтесь с разделом руководства по программированию местоположения о программировании на основе региона. Пример в ваших комментариях указан как одно из применений этого приложения.

ИЗМЕНИТЬ СНОВА. Согласно обсуждению в комментариях, окончательное решение, похоже, устанавливает значительное изменение местоположения, пока пользователь не станет достаточно близко, а затем переключится на точное изменение местоположения (и надеется, что приложение не прекращается в течение этого времени ^^)

Ответ 2

Похоже, вы нашли работоспособное решение, и похоже, что использование существенной структуры изменений позволит вам сэкономить время автономной работы, если оно достаточно точно для ваших целей. Ваше решение также полезно, потому что оно позволяет вам манипулировать потенциально больше, чем ограничение на один из 20 регионов, которым можно было одновременно контролировать, только контролируя те области, в которых вы ближе всего.

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

В "Руководство по программированию местоположения" в разделе "Мониторинг форматов на основе форм":

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

А также в разделе "Обработка событий пересечения границ для региона":

Каждый раз, когда текущее местоположение пользователей пересекает граничную область, система генерирует соответствующее событие региона для вашего приложения. Если ваше приложение уже запущено, эти события передаются непосредственно делегатам любых объектов текущего менеджера местоположений. Если ваше приложение не запущено, система запускает его в фоновом режиме, чтобы он мог ответить. Приложения могут реализовывать следующие методы обработки пересечений границ:

locationManager: didEnterRegion:

locationManager: didExitRegion:

В моем случае мне просто нужно было вызвать уведомление, когда граница была пересечена, поэтому я установил приложение AppDelegate в соответствие с CLLocationManagerDelegate, создал свойство locationManager и поместил его в мой файл реализации:

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.locationManager.delegate = self;
    return YES;
}

- (CLLocationManager *)locationManager
{
    if (!_locationManager) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
    }
    return _locationManager;
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    notification.alertBody = NSLocalizedString(@"You crossed a boundary!", @"user crossed a boundary");
    [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}

Тестирование показывает, что это работает без необходимости указания ключа местоположения UIBackgroundModes. В этом случае OS обрабатывает мониторинг границ для вас, а затем отправляет событие в ваше приложение достаточно долго, чтобы обработать событие. Это не запускает приложение, оно просто запускает его в фоновом режиме на несколько секунд для обработки граничного события, в течение которого вы можете выполнять только соответствующие действия. Надеюсь, это тоже поможет кому-то другому!

Ответ 3

Как только вы убьете приложение, обновления местоположения отправляются в приложение

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

Вам нужно собрать обновления местоположения внутри этого метода делегата, ища ключ запуска, как показано ниже,

if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey])
{
//Code to handle the location update
}

Надеюсь, это то, что вы ищете. Да, вам нужно установить ключ "Необходимые фоновые режимы" со значением "Регистры приложений для обновлений местоположения" в plist.