Estoy buscando una manera de obtener una actualización de ubicación en segundo plano cada n minutos en mi aplicación iOS. Estoy usando iOS 4.3 y la solución debería funcionar para iPhone sin jailbreak.
Intenté / consideré las siguientes opciones:
CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges
: Esto funciona en segundo plano como se esperaba, en función de las propiedades configuradas, pero parece que no es posible forzarlo a actualizar la ubicación cada n minutosNSTimer
: Funciona cuando la aplicación se ejecuta en primer plano, pero no parece estar diseñada para tareas en segundo plano- Notificaciones locales: las notificaciones locales se pueden programar cada n minutos, pero no es posible ejecutar algún código para obtener la ubicación actual (sin que el usuario tenga que iniciar la aplicación a través de la notificación). Este enfoque tampoco parece ser un enfoque limpio, ya que esto no es para lo que deberían usarse las notificaciones.
UIApplication:beginBackgroundTaskWithExpirationHandler
: Según tengo entendido, esto debería usarse para terminar un trabajo en segundo plano (también limitado en el tiempo) cuando una aplicación se mueve a segundo plano en lugar de implementar procesos en segundo plano de "ejecución prolongada".
¿Cómo puedo implementar estas actualizaciones periódicas de ubicación en segundo plano?
Respuestas:
Encontré una solución para implementar esto con la ayuda de los foros de desarrolladores de Apple:
location background mode
NSTimer
fondo en el fondo conUIApplication:beginBackgroundTaskWithExpirationHandler:
n
es más pequeño queUIApplication:backgroundTimeRemaining
funcionará bien. Cuandon
es más grande , selocation manager
debe habilitar (y deshabilitar) nuevamente antes de que no quede tiempo para evitar que se elimine la tarea en segundo plano.Esto funciona porque la ubicación es uno de los tres tipos permitidos de ejecución en segundo plano .
Nota: Perdí algo de tiempo probando esto en el simulador donde no funciona. Sin embargo, funciona bien en mi teléfono.
fuente
En iOS 8/9/10 para hacer una actualización de la ubicación en segundo plano cada 5 minutos, haga lo siguiente:
Vaya a Proyecto -> Capacidades -> Modos de fondo -> seleccione Actualizaciones de ubicación
Vaya a Proyecto -> Información -> agregue una clave NSLocationAlwaysUsageDescription con un valor vacío (u opcionalmente cualquier texto)
Para que la ubicación funcione cuando su aplicación esté en segundo plano y envíe coordenadas al servicio web o haga algo con ellos cada 5 minutos, impleméntela como en el código a continuación.
No estoy usando ninguna tarea de fondo o temporizadores. Probé este código con mi dispositivo con iOS 8.1, que estuvo en mi escritorio durante unas horas con mi aplicación ejecutándose en segundo plano. El dispositivo estaba bloqueado y el código se ejecutaba correctamente todo el tiempo.
fuente
if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { [self.locationManager setAllowsBackgroundLocationUpdates:YES]; }
Hice esto en una aplicación que estoy desarrollando. Los temporizadores no funcionan cuando la aplicación está en segundo plano, pero la aplicación recibe constantemente las actualizaciones de ubicación. Leí en alguna parte de la documentación (parece que no puedo encontrarla ahora, publicaré una actualización cuando lo haga) que un método solo se puede llamar en un ciclo de ejecución activo cuando la aplicación está en segundo plano. El delegado de la aplicación tiene un ciclo de ejecución activo incluso en el BG, por lo que no necesita crear el suyo propio para que esto funcione. [No estoy seguro si esta es la explicación correcta, pero así es como entendí por lo que leí]
En primer lugar, agregue el
location
objeto para la claveUIBackgroundModes
en la lista de información de su aplicación. Ahora, lo que debe hacer es iniciar las actualizaciones de ubicación en cualquier lugar de su aplicación:A continuación, escriba un método para manejar las actualizaciones de ubicación, por ejemplo
-(void)didUpdateToLocation:(CLLocation*)location
, en el delegado de la aplicación. Luego implemente el métodolocationManager:didUpdateLocation:fromLocation
deCLLocationManagerDelegate
en la clase en la que inició el administrador de ubicación (ya que configuramos el delegado del administrador de ubicación en 'self'). Dentro de este método, debe verificar si ha transcurrido el intervalo de tiempo después del cual debe manejar las actualizaciones de ubicación. Puede hacer esto guardando la hora actual cada vez. Si ha transcurrido ese tiempo, llame al método UpdateLocation desde el delegado de su aplicación:Esto llamará a su método cada 5 minutos, incluso cuando su aplicación esté en segundo plano. Imp: esta implementación agota la batería, si la precisión de los datos de su ubicación no es crítica, debe usar
[locationManager startMonitoringSignificantLocationChanges]
Antes de agregar esto a su aplicación, lea la Guía de programación de concientización de ubicación
fuente
Ahora que iOS6 está fuera, la mejor manera de tener servicios de ubicación que se ejecutan para siempre es ...
Solo lo probé así:
Inicié la aplicación, pasé a segundo plano y me moví en el auto unos minutos. Luego me voy a casa por 1 hora y empiezo a moverme nuevamente (sin abrir nuevamente la aplicación). Las ubicaciones comenzaron de nuevo. Luego se detuvo durante dos horas y comenzó de nuevo. Todo bien otra vez ...
NO OLVIDES USAR los nuevos servicios de ubicación en iOS6
fuente
Para alguien más que tenga pesadilla, descubra este. Tengo una solución simple
Agregar temporizador usando:
Simplemente no olvide agregar "Registros de aplicaciones para actualizaciones de ubicación" en info.plist.
fuente
Esto es lo que uso:
Comienzo el seguimiento en AppDelegate así:
fuente
Desafortunadamente, todas sus suposiciones parecen correctas, y no creo que haya una manera de hacerlo. Para ahorrar batería, los servicios de ubicación del iPhone se basan en el movimiento. Si el teléfono se encuentra en un lugar, es invisible para los servicios de ubicación.
La
CLLocationManager
única llamarálocationManager:didUpdateToLocation:fromLocation:
cuando el teléfono recibe una actualización de posición, que sólo ocurre si uno de los tres servicios de localización (antena de telefonía móvil, GPS, WiFi) percibe un cambio.Algunas otras cosas que podrían ayudar a informar soluciones adicionales:
Al iniciar y detener los servicios,
didUpdateToLocation
se llama al método delegado, pero esnewLocation
posible que tenga una marca de tiempo antigua.El monitoreo regional podría ayudar
Cuando se ejecute en segundo plano, tenga en cuenta que puede ser difícil obtener el soporte "completo" de LocationServices aprobado por Apple. Por lo que he visto, se han diseñado específicamente
startMonitoringSignificantLocationChanges
como una alternativa de bajo consumo de energía para aplicaciones que necesitan soporte de ubicación en segundo plano, y recomiendan encarecidamente a los desarrolladores que lo usen a menos que la aplicación lo necesite absolutamente.¡Buena suerte!
ACTUALIZACIÓN: Estos pensamientos pueden estar desactualizados por ahora. Parece que las personas están teniendo éxito con la respuesta de @wjans, arriba.
fuente
startMonitoringSignificantLocationChanges
no daría ninguna actualización en ese caso.Escribí una aplicación usando los servicios de ubicación, la aplicación debe enviar la ubicación cada 10 segundos. Y funcionó muy bien.
Simplemente use el método " allowDeferredLocationUpdatesUntilTraveled: timeout ", siguiendo el documento de Apple.
Lo que hice son:
Obligatorio: registre el modo de fondo para actualizar la ubicación.
1. Crea
LocationManger
ystartUpdatingLocation
, conaccuracy
yfilteredDistance
como quieras,2. Para que la aplicación se ejecute para siempre utilizando el
allowDeferredLocationUpdatesUntilTraveled:timeout
método en segundo plano, debe reiniciarupdatingLocation
con un nuevo parámetro cuando la aplicación se mueva a segundo plano, de esta manera:3. La aplicación se actualizaLocalizaciones de forma normal con
locationManager:didUpdateLocations:
devolución de llamada:4. Pero debe manejar los datos en la
locationManager:didFinishDeferredUpdatesWithError:
devolución de llamada para su propósito5. NOTA: Creo que deberíamos restablecer los parámetros de
LocationManager
cada vez que la aplicación cambia entre modo de fondo / fondo.fuente
pausesLocationUpdatesAutomatically = true
le dice al gerente de ubicación que pause las actualizaciones si aparentemente no hay cambio de ubicación ( documento de Apple ). De todos modos,location manager pauses updates
todavía no probé explícitamente el caso de : D.pausesLocationUpdatesAutomatically = true
hace que mi aplicación deje de actualizar la ubicación.Esto es necesario para el seguimiento de la ubicación en segundo plano desde iOS 9.
fuente
Usé el método de xs2bush para obtener un intervalo (usando
timeIntervalSinceDate
) y lo expandí un poco. Quería asegurarme de que estaba obteniendo la precisión requerida que necesitaba y también que no estaba agotando la batería manteniendo la radio gps encendida más de lo necesario.Mantengo la ubicación ejecutándose continuamente con la siguiente configuración:
Esta es una descarga relativamente baja en la batería. Cuando estoy listo para obtener mi próxima lectura periódica de ubicación, primero verifico si la ubicación está dentro de mi precisión deseada, si es así, entonces uso la ubicación. Si no es así, entonces aumento la precisión con esto:
obtener mi ubicación y luego, una vez que tengo la ubicación, vuelvo a bajar la precisión para minimizar el agotamiento de la batería. He escrito una muestra de trabajo completa de esto y también he escrito la fuente del código del lado del servidor para recopilar los datos de ubicación, almacenarlos en una base de datos y permitir a los usuarios ver datos gps en tiempo real o recuperar y ver rutas almacenadas anteriormente. Tengo clientes para iOS, Android, Windows Phone y Java. Todos los clientes están escritos de forma nativa y todos funcionan correctamente en segundo plano. El proyecto tiene licencia del MIT.
El proyecto iOS está dirigido a iOS 6 utilizando un SDK base de iOS 7. Puede obtener el código aquí .
Presente un problema en github si ve algún problema con él. Gracias.
fuente
Parece que stopUpdatingLocation es lo que activa el temporizador de vigilancia de fondo, por lo que lo reemplacé en didUpdateLocation con:
que parece apagar efectivamente el GPS. El selector para el fondo NSTimer se convierte en:
Todo lo que estoy haciendo es alternar periódicamente la precisión para obtener una coordenada de alta precisión cada pocos minutos y debido a que locationManager no se ha detenido, backgroundTimeRemaining se mantiene en su valor máximo. Esto redujo el consumo de batería de ~ 10% por hora (con kCLLocationAccuracyBest constante en segundo plano) a ~ 2% por hora en mi dispositivo
fuente
Hay un APScheduledLocationManager de cocoapod que permite obtener actualizaciones de ubicación en segundo plano cada n segundos con la precisión de ubicación deseada.
El repositorio también contiene una aplicación de ejemplo escrita en Swift 3.
fuente
En iOS 9 y watchOS 2.0 hay un nuevo método en CLLocationManager que le permite solicitar la ubicación actual: CLLocationManager: requestLocation (). Esto se completa inmediatamente y luego devuelve la ubicación al delegado CLLocationManager.
Puede usar un NSTimer para solicitar una ubicación cada minuto con este método ahora y no tiene que trabajar con los métodos startUpdatingLocation y stopUpdatingLocation.
Sin embargo, si desea capturar ubicaciones en función de un cambio de X metros desde la última ubicación, simplemente configure la propiedad distanceFilter de CLLocationManger y para que X llame a startUpdatingLocation ().
fuente
Attached es una solución Swift basada en:
Definir
App registers for location updates
en la info.plistMantenga el administrador de ubicaciones funcionando todo el tiempo
Cambie
kCLLocationAccuracy
entreBestForNavigation
(durante 5 segundos para obtener la ubicación) yThreeKilometers
durante el resto del período de espera para evitar el drenaje de la bateríaEste ejemplo actualiza la ubicación cada 1 minuto en primer plano y cada 15 minutos en segundo plano.
El ejemplo funciona bien con Xcode 6 Beta 6, ejecutándose en un dispositivo iOS 7.
En el delegado de la aplicación (mapView es una opción que apunta al controlador mapView)
En mapView (locationManager apunta al objeto en AppDelegate)
fuente