Comportamento para alteração significativa da API de localização quando encerrada / suspensa?

108

Esta é a seção da documentação CLLocationManager que descreve o comportamento do aplicativo com startMonitoringSignificantLocationChanges :

Se você iniciar este serviço e seu aplicativo for encerrado posteriormente, o sistema reiniciará automaticamente o aplicativo em segundo plano se um novo evento chegar. Nesse caso, o dicionário de opções passado para o aplicativo: didFinishLaunchingWithOptions: método do delegado do seu aplicativo contém a chave UIApplicationLaunchOptionsLocationKey para indicar que seu aplicativo foi iniciado devido a um evento de localização. Após a reinicialização, você ainda deve configurar um objeto gerenciador de localização e chamar esse método para continuar recebendo eventos de localização. Quando você reinicia os serviços de localização, o evento atual é entregue ao seu delegado imediatamente. Além disso, a propriedade de localização de seu objeto de gerenciador de localização é preenchida com o objeto de localização mais recente, mesmo antes de iniciar os serviços de localização.

Portanto, meu entendimento é que se seu aplicativo for encerrado (e eu presumo que se você não chamar stopMonitoringSignificantLocationChanges de applicationWillTerminate ), você será ativado com um parâmetro UIApplicationLaunchOptionsLocationKey para o aplicativo: didFinishLaunchingWithOptions . Nesse ponto, você cria seu CLLocationManager , chama startMonitoringSignificantLocationChanges e faz o processamento de localização em segundo plano por um tempo limitado . Então estou bem com essa parte.

O parágrafo anterior fala apenas sobre o que acontece quando o aplicativo é encerrado, não sugere o que você faz quando o aplicativo é suspenso. A documentação para didFinishLaunchingWithOptions diz:

O aplicativo rastreia as atualizações de localização em segundo plano, foi eliminado e agora foi reiniciado. Nesse caso, o dicionário contém uma chave indicando que o aplicativo foi reiniciado devido a um novo evento de localização.

Sugerindo que você só receberá esta chamada quando seu aplicativo for iniciado (devido a uma mudança de local) após ter sido encerrado.

No entanto, o parágrafo sobre o Serviço de Mudança Significativa no Guia de Programação de Conscientização de Localização tem o seguinte a dizer:

Se você deixar este serviço em execução e seu aplicativo for suspenso ou encerrado, o serviço ativará automaticamente seu aplicativo quando novos dados de localização chegarem. Na hora de despertar, seu aplicativo é colocado em segundo plano e recebe um pequeno período de tempo para processar os dados de localização. Como seu aplicativo está em segundo plano, ele deve fazer o mínimo de trabalho e evitar quaisquer tarefas (como consultar a rede) que possam impedir que ele retorne antes que o tempo alocado expire. Caso contrário, seu aplicativo pode ser encerrado.

Isso sugere que você acordou com dados de localização se seu aplicativo foi suspenso, mas não menciona como você acordou:

  • O UIApplicationDelegate recebe um retorno de chamada informando que estou retomando de um estado suspenso para um estado de segundo plano?
  • O gerenciador de localização (que foi congelado quando o aplicativo foi suspenso) começa a receber callbacks de locationManager: didUpdateToLocation: fromLocation ?
  • Preciso apenas implementar o código em minha mensagem didUpdateToLocation que verifica o estado do aplicativo e faz o processamento mínimo se estiver no modo de segundo plano?

No processo de escrever isso, acho que posso ter respondido minha própria pergunta, mas seria ótimo ter meu entendimento sobre isso confirmado por alguém mais experiente.

RedBlueThing
fonte

Respostas:

80

Desde que fiz esta pergunta, fiz alguns testes (principalmente no trem entre casa e trabalho) e confirmei que o comportamento dos aplicativos suspensos é o que eu suspeitava no final da pergunta.

Ou seja, seu aplicativo suspenso é ativado, você não recebe nenhum retorno de chamada em seu delegado de aplicativo, em vez disso, recebe suas atualizações de localização por meio de seu CLLocationManagerDelegate existente . Você pode detectar que está executando em segundo plano verificando o applicationState e fazer um trabalho limitado para o caso em que foi acordado de um estado suspenso para fazer o processamento de localização.

[UIApplication sharedApplication].applicationState == UIApplicationStateBackground

Cheguei a essa conclusão com um equipamento de teste de localização que você pode baixar e testar. É um aplicativo muito simples que permite ativar mudanças significativas e APIs de mudança de GPS por meio da IU e registrar todas as respostas que você receber.

NB O ponto seis da resposta anterior não está correto. Aplicativos suspensos liofilizados recebem retornos de chamada CLLocationManagerDelegate quando são acordados de um estado suspenso.

RedBlueThing
fonte
1
Risou # 6 na minha resposta para não confundir as pessoas.
Aaron
Ironicamente, também senti a mesma confusão ao desenvolver a mudança significativa. Ainda tenho algumas dúvidas sobre o que acontecerá se o aplicativo for fechado. o retorno de chamada UIApplicationDelegate não acontecerá? é a maneira certa de iniciar o aplicativo. se o gerenciador de localização ainda não foi inicializado, como ele pode obter as notificações em segundo plano? (hora para mais P&D)
darshansonde
Muito obrigado pelo aplicativo de amostra, foi muito útil para mim. Eu tenho uma pergunta: e se eu estivesse usando o serviço de localização padrão em segundo plano, não o mais significativo, o aplicativo também será reiniciado após o encerramento nesse caso? Eu fiz esta pergunta aqui em detalhes, eu ficaria feliz se você pudesse me iluminar:] stackoverflow.com/questions/12239967/…
aslisabanci
2
Não funcionou em ios7 stackoverflow.com/questions/18946881/…
Igor
Você sabe quanto tempo levou para o seu aplicativo ser encerrado? E obter um retorno de chamada appDelegate? (São 30 minutos? 2 horas? 5 horas?) Estou perguntando isso porque configurei uma região para monitorar. Tentei muitas vezes ver meu aplicativo sendo iniciado, mas apenas uma vez consegui reiniciá-lo. Outras vezes, o didExitRegionretorno de chamada, mas não consegui startLocationUpdatesde lá, porque não foi através do lançamento do aplicativo ...
Querida
25

Meu entendimento é o seguinte (estou no processo de escrever um aplicativo que depende dessa API, mas não concluí este componente o suficiente para começar o teste):

  1. Seu aplicativo é executado pela primeira vez, você se registra em startMonitoringSignificantLocationChanges e fornece uma função de retorno de chamada. Enquanto seu aplicativo estiver em execução, ele chamará esse retorno de chamada sempre que receber uma alteração significativa.
  2. Se seu aplicativo for colocado em segundo plano, UIApplication receberá applicationWillResignActive , seguido por applicationDidEnterBackground .
  3. Se seu aplicativo for encerrado enquanto estiver suspenso em segundo plano, você não será notificado; no entanto, se seu aplicativo for encerrado enquanto estiver em execução (primeiro ou segundo plano, pelo que sei), você terá um momento com applicationWillTerminate . Você não pode solicitar tempo extra em segundo plano a partir desta função.
  4. Apesar de ser morto em segundo plano, o sistema operacional irá reiniciar seu aplicativo. Se o seu aplicativo for simplesmente iniciado pelo sistema operacional para uma mudança, você receberá uma chamada para o aplicativo didFinishLaunchingWithOptions :

    if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey])

    irá ajudá-lo a determinar se você voltou de uma mudança de localização em segundo plano.

  5. Se, em vez disso, você estava executando em segundo plano e seu aplicativo foi reiniciado manualmente pelo usuário, você receberá um applicationWillEnterForeground seguido por applicationDidBecomeActive .
  6. Independentemente de como isso aconteceu, quando seu aplicativo for reiniciado (a menos que ainda estivesse em execução em segundo plano como resultado de uma tarefa em segundo plano e a referida tarefa tivesse iniciado o monitoramento de alterações), você precisa dizer explicitamente para iniciarMonitoringSignificantLocationChanges novamente porque o retorno de chamada não mais anexado após a "liofilização". E sim, você só precisa implementar o código em didUpdateToLocation depois de reconectar um manipulador de localização de algum tipo, ao retornar do estado suspenso.

Isso é o que estou fazendo com meu desenvolvimento de código agora. Como mencionei antes, não estou totalmente pronto para testar isso em um dispositivo, então não posso dizer se interpretei tudo corretamente, portanto, comentadores, sintam-se à vontade para me corrigir (embora eu tenha feito uma leitura substancial no tópico).

Ah, e se por um golpe de azar você lançar um aplicativo que faz o que eu quero que o meu faça, posso chorar :)

Boa sorte!

Aaron
fonte
1
@Tegeril +1 Obrigado pela resposta. Eu estava começando a ouvir grilos neste. :) Estou surpreso que os aplicativos que começaram a ser suspensos precisem chamar novamente startMonitoringSignificantLocationChanges. Você tem um link para o doco onde isso é descrito? Meu entendimento é que ser carregado de um estado suspenso irá instanciar todos os seus objetos como estavam quando o aplicativo foi suspenso. Portanto, espero que a solicitação de mudança significativa entre em vigor.
RedBlueThing de
Você pode estar falando sobre isso? "Ao reiniciar, você ainda deve configurar um objeto gerenciador de localização e chamar esse método para continuar recebendo eventos de localização" Mas acho que isso se refere ao caso em que seu aplicativo foi iniciado de um estado encerrado (por um evento de localização). Esta é basicamente a raiz da minha pergunta, 'o que acontece com o caso suspenso?'.
RedBlueThing
Morgan Grainger nos fóruns de desenvolvimento sugeriu isso: "Você precisa criar um CLLocationManager, definir um delegado e chamar startMonitoringSignificantLocationChanges quando seu aplicativo for iniciado, ou então o Core Location não terá onde entregar as atualizações." no contexto de reiniciar um aplicativo independentemente de um estado encerrado ou suspenso. Em "o aplicativo foi reiniciado após startMonitoringSignificantLocationChanges e agora?"
Aaron de
Concordo que isso ainda pode ser vago, mesmo no contexto daquela postagem no fórum (o postador estava discutindo como acordar do fundo, mas Morgan usou o reinício mais geral de um aplicativo). Ainda acho que você precisa chamar para monitorar novamente quando seu aplicativo for reiniciado se quiser trabalhar com a função de mudanças significativas. Se você quiser iniciar uma tarefa em segundo plano e atualizar com o serviço de localização padrão e a funcionalidade GPS, essa é uma opção alternativa. Não acredito que você precise se registrar novamente em cada lançamento com mudanças significativas para ser lançado novamente.
Aaron de
1
Estou feliz que algo definitivo saiu disso, deve me ajudar no futuro :)
Aaron
1

Se o aplicativo for acionado do estado suspenso como resultado da mudança de local, o aplicativo será iniciado em segundo plano.

Todos os objetos estarão ativos e você receberá atualização de localização no delegado existente.

Anshu
fonte