Estou procurando uma maneira de obter uma atualização de localização em segundo plano a cada n minutos no meu aplicativo iOS. Estou usando o iOS 4.3 e a solução deve funcionar em iPhones sem jailbreak.
Tentei / considerei as seguintes opções:
CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges
: Isso funciona em segundo plano conforme o esperado, com base nas propriedades configuradas, mas não parece possível forçá-lo a atualizar o local a cada n minutosNSTimer
: Funciona quando o aplicativo está sendo executado em primeiro plano, mas não parece ter sido projetado para tarefas em segundo plano- Notificações locais: as notificações locais podem ser agendadas a cada n minutos, mas não é possível executar algum código para obter a localização atual (sem que o usuário precise iniciar o aplicativo por meio da notificação). Essa abordagem também não parece ser uma abordagem limpa, pois não é para isso que as notificações devem ser usadas.
UIApplication:beginBackgroundTaskWithExpirationHandler
: Pelo que entendi, isso deve ser usado para concluir algum trabalho em segundo plano (também com tempo limitado) quando um aplicativo é movido para o segundo plano, em vez de implementar processos em segundo plano "de longa execução".
Como posso implementar essas atualizações regulares de localização em segundo plano?
Respostas:
Encontrei uma solução para implementar isso com a ajuda dos Fóruns de desenvolvedores da Apple:
location background mode
NSTimer
plano de fundo comUIApplication:beginBackgroundTaskWithExpirationHandler:
n
é menor doUIApplication:backgroundTimeRemaining
que funcionará bem. Quandon
for maior ,location manager
deve ser ativado (e desativado) novamente antes que não haja tempo restante para evitar que a tarefa em segundo plano seja eliminada.Isso funciona porque o local é um dos três tipos permitidos de execução em segundo plano .
Nota: perdi algum tempo testando isso no simulador, onde não funciona. No entanto, funciona bem no meu telefone.
fonte
No iOS 8/9/10 para atualizar o local em segundo plano a cada 5 minutos, faça o seguinte:
Vá para Projeto -> Recursos -> Modos de segundo plano -> selecione Atualizações de local
Vá para Projeto -> Informações -> adicione uma chave NSLocationAlwaysUsageDescription com valor vazio (ou opcionalmente qualquer texto)
Para que o local funcione quando o aplicativo estiver em segundo plano e envie coordenadas para o serviço da Web ou faça qualquer coisa com eles a cada 5 minutos, implemente-o como no código abaixo.
Não estou usando nenhuma tarefa ou temporizador em segundo plano. Testei esse código com meu dispositivo com iOS 8.1, que estava em minha mesa por algumas horas com meu aplicativo em execução em segundo plano. O dispositivo estava bloqueado e o código estava funcionando corretamente o tempo todo.
fonte
if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { [self.locationManager setAllowsBackgroundLocationUpdates:YES]; }
Eu fiz isso em um aplicativo que estou desenvolvendo. Os cronômetros não funcionam quando o aplicativo está em segundo plano, mas o aplicativo recebe constantemente as atualizações de local. Li em algum lugar da documentação (não consigo encontrá-lo agora, publicarei uma atualização quando o fizer) que um método pode ser chamado apenas em um loop de execução ativo quando o aplicativo está em segundo plano. O delegado do aplicativo tem um loop de execução ativo, mesmo na BG, assim você não precisa criar o seu próprio para fazer isso funcionar. [Não tenho certeza se esta é a explicação correta, mas é assim que eu entendi pelo que li]
Primeiro, adicione o
location
objeto para a chaveUIBackgroundModes
no info.plist do seu aplicativo. Agora, o que você precisa fazer é iniciar as atualizações de local em qualquer lugar do seu aplicativo:Em seguida, escreva um método para lidar com as atualizações de local, digamos
-(void)didUpdateToLocation:(CLLocation*)location
, no delegado do aplicativo. Em seguida, implementar o métodolocationManager:didUpdateLocation:fromLocation
deCLLocationManagerDelegate
na classe em que você começou a locação (uma vez que definir o gerente delegado local para 'self'). Dentro desse método, é necessário verificar se o intervalo de tempo após o qual você precisa lidar com as atualizações de local passou. Você pode fazer isso salvando o horário atual todas as vezes. Se esse tempo tiver passado, chame o método UpdateLocation do seu representante do aplicativo:Isso chamará seu método a cada 5 minutos, mesmo quando o aplicativo estiver em segundo plano. Imp: Esta implementação gasta a bateria. Se a precisão dos dados de localização não for crítica, você deve usar
[locationManager startMonitoringSignificantLocationChanges]
Antes de adicionar isso ao seu aplicativo, leia o Guia de programação de reconhecimento de local
fonte
Agora que o iOS6 é a melhor maneira de ter serviços de localização em execução permanente ...
Apenas testei assim:
Iniciei o aplicativo, entre em segundo plano e movo-me no carro por alguns minutos. Depois vou para casa por 1 hora e começo a me mover novamente (sem abrir novamente o aplicativo). Os locais começaram novamente. Então parou por duas horas e começou de novo. Tudo ok de novo ...
NÃO ESQUEÇA DE USAR os novos serviços de localização no iOS6
fonte
Para alguém que está tendo pesadelo, descubra este. Eu tenho uma solução simples.
Adicionar timer usando:
Só não se esqueça de adicionar "Registros de aplicativos para atualizações de local" em info.plist.
fonte
Aqui está o que eu uso:
Começo o rastreamento no AppDelegate assim:
fonte
Infelizmente, todas as suas suposições parecem corretas e não acho que haja uma maneira de fazer isso. Para economizar a bateria, os serviços de localização do iPhone são baseados no movimento. Se o telefone estiver em um local, é invisível para os serviços de localização.
A
CLLocationManager
chamada será feita apenaslocationManager:didUpdateToLocation:fromLocation:
quando o telefone receber uma atualização de localização, o que só acontece se um dos três serviços de localização (torre de celular, gps, wifi) perceber uma alteração.Algumas outras coisas que podem ajudar a informar outras soluções:
Iniciar e interromper os serviços faz com que o
didUpdateToLocation
método delegado seja chamado, masnewLocation
pode ter um carimbo de data / hora antigo.O monitoramento de região pode ajudar
Ao executar em segundo plano, lembre-se de que pode ser difícil obter o suporte completo ao LocationServices aprovado pela Apple. Pelo que vi, eles foram projetados especificamente
startMonitoringSignificantLocationChanges
como uma alternativa de baixo consumo de energia para aplicativos que precisam de suporte de localização em segundo plano e incentivam fortemente os desenvolvedores a usá-lo, a menos que o aplicativo precise absolutamente.Boa sorte!
ATUALIZAÇÃO: Esses pensamentos podem estar desatualizados até agora. Parece que as pessoas estão tendo sucesso com a resposta @wjans, acima.
fonte
startMonitoringSignificantLocationChanges
não daria nenhuma atualização nesse caso.Escrevi um aplicativo usando os serviços de localização. O aplicativo deve enviar o local a cada 10s. E funcionou muito bem.
Basta usar o método " allowDeferredLocationUpdatesUntilTraveled: timeout ", seguindo o documento da Apple.
O que eu fiz são:
Necessário: registre o modo de segundo plano para atualizar o local.
1. Crie
LocationManger
estartUpdatingLocation
, comaccuracy
efilteredDistance
como quiser:2. Para manter o aplicativo em execução para sempre usando o
allowDeferredLocationUpdatesUntilTraveled:timeout
método em segundo plano, você deve reiniciarupdatingLocation
com um novo parâmetro quando o aplicativo for para o segundo plano, desta forma:3. O aplicativo é atualizado como local normalmente com
locationManager:didUpdateLocations:
retorno de chamada:4. Mas você deve manipular os dados e
locationManager:didFinishDeferredUpdatesWithError:
retornar a chamada para sua finalidade5. OBSERVAÇÃO: acho que devemos redefinir os parâmetros de
LocationManager
cada vez que o aplicativo alterna entre o modo background / forground.fonte
pausesLocationUpdatesAutomatically = true
instrui o gerente de local a interromper as atualizações se aparentemente não houver alteração de local ( documento da Apple ). De qualquer forma, ainda não testei explicitamente o casolocation manager pauses updates
: D.pausesLocationUpdatesAutomatically = true
faz com que meu aplicativo pare de atualizar o local.Isso é necessário para o rastreamento de localização em segundo plano desde o iOS 9.
fonte
Eu usei o método do xs2bush de obter um intervalo (usando
timeIntervalSinceDate
) e expandi-o um pouco. Eu queria ter certeza de que estava obtendo a precisão necessária e também que não estava ficando sem bateria, mantendo o rádio GPS ligado mais do que o necessário.Eu mantenho o local em execução continuamente com as seguintes configurações:
este é um consumo relativamente baixo da bateria. Quando estiver pronto para ler minha próxima localização periódica, primeiro verifico se o local está dentro da precisão desejada; se estiver, então uso o local. Caso contrário, aumentei a precisão com isso:
obtenha minha localização e, depois que tiver a localização, diminuo a precisão novamente para minimizar o consumo da bateria. Escrevi um exemplo completo disso e também escrevi a fonte do código do servidor para coletar os dados de localização, armazená-los em um banco de dados e permitir que os usuários visualizem dados de GPS em tempo real ou recuperem e visualizem rotas armazenadas anteriormente. Tenho clientes para iOS, android, windows phone e java me. Todos os clientes são escritos de forma nativa e todos funcionam corretamente em segundo plano. O projeto é licenciado pelo MIT.
O projeto do iOS está direcionado para o iOS 6 usando um SDK base do iOS 7. Você pode obter o código aqui .
Por favor, registre um problema no github se houver algum problema. Obrigado.
fonte
Parece que stopUpdatingLocation é o que aciona o timer do watchdog em segundo plano, então substituí-o em didUpdateLocation por:
que parece efetivamente desligar o GPS. O seletor para o NSTimer em segundo plano se torna:
Tudo o que estou fazendo é alternar periodicamente a precisão para obter uma coordenada de alta precisão a cada poucos minutos e, como o locationManager não foi parado, backgroundTimeRemaining permanece em seu valor máximo. Isso reduziu o consumo da bateria de ~ 10% por hora (com constante kCLLocationAccuracyBest em segundo plano) para ~ 2% por hora no meu dispositivo
fonte
Existe um cocoapod APScheduledLocationManager que permite obter atualizações de localização em segundo plano a cada n segundos com a precisão da localização desejada.
O repositório também contém um aplicativo de exemplo escrito em Swift 3.
fonte
No iOS 9 e no watchOS 2.0, há um novo método no CLLocationManager que permite solicitar o local atual: CLLocationManager: requestLocation (). Isso é concluído imediatamente e, em seguida, retorna o local ao delegado CLLocationManager.
Você pode usar um NSTimer para solicitar um local a cada minuto com esse método agora e não precisa trabalhar com os métodos startUpdatingLocation e stopUpdatingLocation.
No entanto, se você deseja capturar locais com base em uma alteração de X metros a partir do último local, basta definir a propriedade distanceFilter de CLLocationManger e chamar X startUpdatingLocation ().
fonte
Em anexo é uma solução Swift baseada em:
Definir
App registers for location updates
no info.plistMantenha o locationManager em execução o tempo todo
Alterne
kCLLocationAccuracy
entreBestForNavigation
(por 5 segundos para obter o local) eThreeKilometers
pelo resto do período de espera para evitar a drenagem da bateriaEste exemplo atualiza o local a cada 1 minuto em primeiro plano e a cada 15 minutos em segundo plano.
O exemplo funciona bem com o Xcode 6 Beta 6, executando em um dispositivo iOS 7.
No App Delegate (mapView é um apontador opcional para o mapView Controller)
No mapView (locationManager aponta para o objeto no AppDelegate)
fonte