Поведение для существенного изменения местоположения API, когда прекращено / приостановлено?
Это раздел документации CLLocationManager, описывающий поведение приложения с помощью startMonitoringSignificantLocationChanges:
Если вы запускаете эту службу и ваше приложение впоследствии закрывается, система автоматически перезапускает приложение в фоновом режиме, если поступает новое событие. В таком случае словарь опций, передаваемый приложению: didFinishLaunchingWithOptions: метод вашего делегата приложения содержит ключ UIApplicationLaunchOptionsLocationKey, чтобы указать, что ваше приложение было запущено из-за события местоположения. После перезапуска вы все равно должны сконфигурировать объект диспетчера местоположений и вызвать этот метод, чтобы продолжить получать события местоположения. Когда вы перезапускаете службы определения местоположения, текущее событие немедленно доставляется вашему делегату. Кроме того, свойство location вашего объекта менеджера местоположений заполняется самым последним объектом location даже до запуска служб определения местоположения.
Поэтому я понимаю, что если ваше приложение завершает работу (и я предполагаю, что если вы не вызываете stopMonitoringSignificantLocationChanges из applicationWillTerminate), вы будете разбужены параметром UIApplicationLaunchOptionsLocationKey для приложения: didFinishLaunchingWithOptions. В этот момент вы создаете свой CLLocationManager, вызываете startMonitoringSignificantLocationChanges и выполняете фоновую обработку местоположения в течение ограниченного времени. Так что я в порядке с этим битом.
Предыдущий абзац говорит только о том, что происходит, когда приложение закрывается, но не предлагает того, что вы делаете, когда приложение приостановлено. Документация для didFinishLaunchingWithOptions гласит:
Приложение отслеживает обновления местоположения в фоновом режиме, было очищено и теперь перезапущено. В этом случае словарь содержит ключ, указывающий, что приложение было перезапущено из-за нового события местоположения.
Предполагается, что вы получите этот вызов только при запуске приложения (из-за изменения местоположения) после того, как вы были прекращены.
Однако параграф о Службе значительных изменений в Руководстве по программированию осведомленности о местоположении содержит следующее:
Если вы оставляете эту службу включенной, а ваше приложение впоследствии приостанавливается или прекращает работу, служба автоматически активирует ваше приложение, когда поступают новые данные о местоположении. Во время пробуждения ваше приложение переводится в фоновый режим, и ему предоставляется небольшое количество времени для обработки данных о местоположении. Поскольку ваше приложение работает в фоновом режиме, оно должно выполнять минимальную работу и избегать любых задач (таких как запросы к сети), которые могут помешать его возврату до истечения выделенного времени. Если это не так, ваша заявка может быть прекращена.
Это говорит о том, что вы проснулись с данными о местоположении, если ваше приложение было приостановлено, но не упоминает, как вы проснулись:
- Получает ли UIApplicationDelegate обратный вызов, сообщающий мне, что я возвращаюсь из приостановленного состояния в фоновое состояние?
- Менеджер местоположений (который был заморожен, когда приложение было приостановлено) начинает получать locationManager: didUpdateToLocation: fromLocation обратные вызовы?
- Нужно ли просто реализовать код в моем сообщении didUpdateToLocation, которое проверяет состояние приложения и выполняет минимальную обработку в фоновом режиме?
В процессе написания этого, я думаю, что я, возможно, только что ответил на свой собственный вопрос, но было бы здорово, чтобы мое понимание этого подтвердилось кем-то более знающим.
4 ответа
Поскольку я задал этот вопрос, я провел немало тестов (в основном на поезде между домом и работой) и подтвердил, что поведение приостановленных приложений такое же, как я подозревал в конце вопроса.
То есть ваше приостановленное приложение проснулось, вы не получите никаких обратных вызовов для вашего делегата приложения, вместо этого вы получите обновления вашего местоположения через существующий CLLocationManagerDelegate. Вы можете определить, что вы работаете в фоновом режиме, проверив applicationState, и выполнить ограниченную работу для случая, когда вы проснулись из приостановленного состояния, чтобы выполнить обработку местоположения.
[UIApplication sharedApplication].applicationState == UIApplicationStateBackground
Я пришел к такому выводу с помощью проводов для проверки местоположения, которые вы можете загрузить и попробовать. Это довольно простое приложение, которое позволяет вам включать значительные изменения и API изменения GPS через пользовательский интерфейс и регистрировать все полученные ответы.
NB. Пункт шесть в предыдущем ответе неверен. Замороженные приостановленные приложения получают обратные вызовы CLLocationManagerDelegate, когда они просыпаются из приостановленного состояния.
Мое понимание таково (я нахожусь в процессе написания приложения, которое использует этот API, но еще не завершило этот компонент, чтобы начать тестирование):
- Ваше приложение запускается в первый раз, вы регистрируетесь в startMonitoringSignificantLocationChanges и предоставляете функцию обратного вызова. Пока ваше приложение работает, оно будет вызывать этот обратный вызов всякий раз, когда оно получает существенное изменение.
- Если ваше приложение переведено в фоновый режим, UIApplication получит applicationWillResignActive, за которым следует applicationDidEnterBackground.
- Если ваше приложение будет удалено, пока оно приостановлено в фоновом режиме, вы не будете уведомлены; однако, если ваше приложение будет убито во время его работы (насколько мне известно, передний план или фон), вы получите мгновение с applicationWillTerminate. Вы не можете запросить дополнительное фоновое время от этой функции.
Несмотря на то, что ОС была убита в фоновом режиме, ОС перезапустит ваше приложение. Если ваше приложение просто запускается ОС для изменения, вы получите вызов приложения didFinishLaunchingWithOptions:
if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey])
поможет вам определить, вернулись ли вы из фонового изменения местоположения.
- Если вместо этого вы в данный момент работаете в фоновом режиме, и ваше приложение вручную перезапускается пользователем, вы получите applicationWillEnterForeground, за которым следует applicationDidBecomeActive.
-
Независимо от того, как это произошло, когда ваше приложение перезапускается (если только оно не работало в фоновом режиме в результате фоновой задачи и указанная задача не начала отслеживать изменения), вам необходимо явно указать ему startMonitoringSignificantLocationChanges снова, потому что обратный вызов не дольше прикрепляется после "сублимационной сушки".И да, вам просто нужно реализовать код в didUpdateToLocation, как только вы повторно подключите какой-либо обработчик местоположения, когда возвращаетесь из приостановленного состояния.
Это то, чем я сейчас занимаюсь при разработке кода. Как я упоминал ранее, я не совсем готов протестировать это на устройстве, поэтому не могу сказать, правильно ли я все интерпретировал, поэтому, комментаторы, не стесняйтесь поправлять меня (хотя я много читал о тема).
О, и если по какой-то причине вам не повезет, вы выпустите приложение, которое делает то, что я хочу, чтобы я сделал, я бы заплакал
Удачи!
Если приложение вызвано из приостановленного состояния в результате изменения местоположения, приложение запустится в фоновом состоянии.
Все объекты будут активными, и вы получите обновление местоположения в существующем делегате.
Итак, у меня есть важное примечание, касающееся того, когда приложение было прекращено:
Для некоторых API, которые могут запускать приложение в фоновом режиме, а затем должны получать обратный вызов, обрабатывающий этот запуск, вероятно, потребуется
Поэтому, если вы получаете запуск приложения (т.е. из завершенного состояния, а не из приостановленного состояния) из-за отслеживания местоположения, ваши обратные вызовы делегата locationManager не будут вызываться, если вы не установите делегат в
- Итак, если вы выполняете следующие действия в своем контроллере просмотра ABC после запуска вашего приложения
let manager = CLLocationManager()
manager.delegate = self
- Затем приложение было прекращено
- Затем приложение было расположено из-за изменения местоположения в фоновом режиме.
- ВЫ НЕ ПОЛУЧИТЕ обратный вызов, пока не переведете приложение на передний план и не откроете контроллер просмотра ABC.
Неверно думать, что приложение волшебным образом знает, что такое объект делегата. Эта информация не сохраняется .
Решение:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let myLocationManager = CLLocationManager()
myLocationManager.delegate = self
}
Я понял это для совершенно не связанного API:
optional func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void)
То есть, если вы не установите свой делегат перед AppLaunch, вы пропустите взаимодействие пользователя с уведомлениями, которые происходят сразу после закрытия приложения. Чтобы быть более точным, вы пропускаете любые обратные вызовы, пока не установите делегат userNotification.