Enviar actualizaciones de location cada 30 minutos en Swift

Tengo el modo de background activado para los services de location y tengo el objective de enviar la location (latitud y longitud) al server cada 30 minutos. Por ahora estoy imprimiendo lo mismo en la console. Parece que funciona por un time, pero me pregunto cómo trabajo con NSTimer en este caso. ¿Y de dónde debería llamarlo?

import UIKit import CoreLocation @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate { var window: UIWindow? var locationManager = CLLocationManager() func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. return true } func applicationWillResignActive(application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } func applicationDidEnterBackground(application: UIApplication) { // Use this method to release shanetworking resources, save user data, invalidate timers, and store enough application state information to restre your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. self.locationManager.delegate = self self.locationManager.startUpdatingLocation() // I know i should be using signification location option here. this is just for testing now. } func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) { self.sendBackgroundLocationToServer(newLocation); } func sendBackgroundLocationToServer(location: CLLocation) { var bgTask = UIBackgroundTaskIdentifier() bgTask = UIApplication.shanetworkingApplication().beginBackgroundTaskWithExpirationHandler { () -> Void in UIApplication.shanetworkingApplication().endBackgroundTask(bgTask) } println(location.coordinate.latitude) if (bgTask != UIBackgroundTaskInvalid) { UIApplication.shanetworkingApplication().endBackgroundTask(bgTask); bgTask = UIBackgroundTaskInvalid; } } func applicationWillEnterForeground(application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. application.beginBackgroundTaskWithExpirationHandler{} } func applicationDidBecomeActive(application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. application.beginBackgroundTaskWithExpirationHandler{} } func applicationWillTerminate(application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. application.beginBackgroundTaskWithExpirationHandler{} } } 

Tal vez llamar a application.beginBackgroundTaskWithExpirationHandler{} es una mala idea? ¿Con qué opciones voy aquí?

La idea de beginBackgroundTask... es comenzar una tarea de longitud finita para que, si el usuario abandona la aplicación, se mantendrá ejecutando en la tarea de background durante un corto período de time (creo que de 3 minutos). Y antes de que se agote el time, debe llamar a endBackgroundTask o de lo contrario la aplicación será terminada de forma sumria.

Por lo tanto, lamentablemente, el mecanismo de tarea de background no es realmente adecuado para su intención deseada. Sin embargo, hay un set estrecho de modos de background especiales diseñados para la operación continua en segundo plano fuera de un set estrecho de funciones (VOIP, audio, etc.). Para get más información, consulte la sección Implementar tareas de ejecución prolongada de la Guía de progtwigción de aplicaciones para iOS: Ejecución en segundo plano .

Ahora, uno de esos modos de background es para un service de "location". Por lo tanto, si esa es una característica central de su aplicación, esencial para una function adecuada, puede registrarse en el modo de background de location y su aplicación continuará ejecutándose en segundo plano. Desde allí, puede supervisar las actualizaciones de location y, si ha transcurrido un time suficiente, desencadenar algún process. Pero si este modo de location de background no es una característica esencial de su aplicación, es probable que Apple rechace su aplicación para solicitar un modo de background que no necesita.


Por cierto, debe tener en count que comenzar los services de location estándar puede agotar la batería del dispositivo. Puede considerar utilizar el service de location de "cambio significativo" eficiente de la batería. Esto también tiene la virtud de despertar automáticamente su aplicación cada vez que el usuario mueve una distancia significativa (por ejemplo, medida en km; creo que se activa al moverse a una torre celular diferente).

Un par de notas, ya que hemos estado peleando los problemas de location y luchando con aplicaciones de background que no parecen despertarnos.

  1. NSTimer solo es bueno siempre que su aplicación no esté suspendida. Claro, está en segundo plano, pero solo porque es capaz de recibir notifications del iOS (APN, location, …). Eventualmente, su cronómetro DEJARÁ de disparar mientras se ejecuta en el BG. Entonces, confías en uno de los modos BG para patearte.

  2. Si está utilizando CLLocationManager.startUpdatingLocation, notará que dejó de getlos después de un time. Especialmente cuando el teléfono se relaja e intenta dormir. Esto se debe a una característica mal documentada llamada CLLocationManager.pausesLocationUpdatesAutomatically … que decide dejar de enviarlos cuando se establece en "true" (la configuration DEFAULT). Puede establecer esto en "falso", y continuará recibiendo las actualizaciones de su position. Lo que más seguro es que tu aplicación haga lo que quieres.

  3. Como se indicó anteriormente, debe asegurarse de que, cuando reciba su callback de locationManager.didUpdateLocations, inicie un process de background para mantener su aplicación funcionando mientras procesa esa información y envía los datos de su networking. Pero pareces entender eso.

  4. Solo despertarse el time suficiente para "grabar" una actualización de location no es tan malo. Solo asegúrese de no generar su código de networking a less que claramente haya alcanzado su expectativa de 30 minutos.

testing esto:

  • Haga una singleton para el service de location. Registrado con una NSNotification
  • En AppDelegate 's willEnterBackGround , envía una notificación a través de NSNotificationCenter

entonces, su singleton comenzará a updatingLocation location y lo enviará al server cuando se reciban los datos de la location.