2012-04-19 12 views
26

Estoy tratando de implementar las sugerencias dadas en this post.Obtener la ubicación del usuario cada n minutos después de que la aplicación vaya al fondo

Lamentablemente, los pasos no están claros para mí. Intenté implementar esas sugerencias, pero el backgroundTimeRemaining continúa disminuyendo incluso después de iniciar y detener LocationServices. Esta es la forma en que he desarrollado:

- (void)applicationDidEnterBackground:(UIApplication *)application { 

    UIApplication* app = [UIApplication sharedApplication]; 

    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
     [app endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    }]; 

    // Start the long-running task and return immediately. 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     // Do the work associated with the task. 
     self.timer = nil; 
     [self initTimer]; 

    }); 
} 

initTimer:

- (void)initTimer { 

    // Create the location manager if this object does not 
    // already have one. 
    if (nil == self.locationManager) 
     self.locationManager = [[CLLocationManager alloc] init]; 

    self.locationManager.delegate = self; 
    [self.locationManager startMonitoringSignificantLocationChanges]; 

    if (self.timer == nil) { 
     self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3 
               target:self 
              selector:@selector(checkUpdates:) 
              userInfo:nil 
              repeats:YES]; 
    } 
} 

checkupdates:

- (void)checkUpdates:(NSTimer *)timer{ 
    UIApplication* app = [UIApplication sharedApplication]; 
    double remaining = app.backgroundTimeRemaining; 
    if(remaining < 580.0) { 
     [self.locationManager startUpdatingLocation]; 
     [self.locationManager stopUpdatingLocation]; 
     [self.locationManager startMonitoringSignificantLocationChanges]; 
    } 
    DbgLog(@"Reminaing %f", app.backgroundTimeRemaining); 
} 

¿alguien tiene una sugerencia sobre lo que podría estar mal en mi código? Se están llamando tanto a initTimer como a CheckUpdates, pero solo durante el tiempo de ejecución de fondo (+ - 10 Mins). Quiero que la aplicación actualice la ubicación cada n minutos "para siempre".

UIBackgroundModes de mi aplicación está configurado.

ACTUALIZACIÓN:

ahora estoy Restablecimiento del temporizador de didUpdateToLocation y didFailWithError. Pero aún así el backgroundTimeRemaining sigue disminuyendo:

- (void)locationManager:(CLLocationManager *)manager 
didUpdateToLocation:(CLLocation *)newLocation 
     fromLocation:(CLLocation *)oldLocation { 

NSLog(@"Did Update Location = %f/%f", [newLocation coordinate].latitude, [newLocation coordinate].longitude); 

UIApplication* app = [UIApplication sharedApplication]; 

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    [app endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid; 
}]; 

// Start the long-running task and return immediately. 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

    // Do the work associated with the task. 

    [self initTimer]; 

}); 
} 

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { 

[self.locationManager stopUpdatingLocation]; 
UIApplication* app = [UIApplication sharedApplication]; 

bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
    [app endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid; 
}]; 

// Start the long-running task and return immediately. 
[self initTimer]; 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

    // Do the work associated with the task. 

}); 

} 

También estoy invalidando el temporizador:

- (void)checkUpdates:(NSTimer *)timer{ 
UIApplication* app = [UIApplication sharedApplication]; 
double remaining = app.backgroundTimeRemaining; 
if(remaining < 580.0 && remaining > 570.0) { 
    [self.timer invalidate]; 
    self.timer = nil; 
    [self.locationManager startUpdatingLocation]; 
    [self.locationManager stopUpdatingLocation]; 
} 
DbgLog(@"*************************Checking for updates!!!!!!!!!!! Reminaing %f", app.backgroundTimeRemaining); 
} 
+3

¿Su aplicación está aceptada en App Store? Estoy considerando seguir el mismo enfoque, pero necesito asegurarme de que mi aplicación no sea rechazada. Gracias por cierto! – aslisabanci

+1

¿conseguiste que esto funcionara? –

Respuesta

8

Después de algunos días probando todas las soluciones posibles finalmente pude hacerlo funcionar. Esto es lo que estaba mal en mi solución:

  • Necesito fijar UIBackgroundTaskIdentifiers, uno para el temporizador, y otro para el locationManager

En mi solución, basta con añadir:

UIApplication *app = [UIApplication sharedApplication]; 

bgTask2 = [app beginBackgroundTaskWithExpirationHandler:^{ 
[app endBackgroundTask:bgTask2]; 
bgTask2 = UIBackgroundTaskInvalid; }]; 

self.locationManager.delegate = self; 
[self.locationManager startUpdatingLocation]; 
+27

¿A qué método está agregando estas líneas? – Michal

+0

@scurioni ¿Puede publicar el código de trabajo completo? – Sharme

+0

¿podría compartir el código de trabajo del delegado de la aplicación? estamos experimentando el mismo problema –

4

Una vez que estés en el fondo sólo puede tener 10 minutos de tiempo adicional. No hay forma de extender eso. En su lugar, debe usar los servicios en segundo plano de ubicación.

+1

y esos servicios todavía no tienen una versión basada en el tiempo, sino que se activan con cada actualización o cambian de ubicación significativa –

+0

Pero al leer la publicación que he vinculado, parece que las personas pudieron hacerlo. ¿Cuál crees que es la diferencia de lo que implementé y el código que hicieron? – scurioni

+1

el enfoque que están usando (de un vistazo) es usar el servicio completo de ubicación de fondo de energía (para que continuamente reciba actualizaciones, pero solo lo maneje cada X minutos). Eso funcionaría, pero su batería morirá cada noche –

9

Para que alguien más tenga una pesadilla de tiempo tratando de resolver esto, tengo una solución simple.

  1. Estudia el ejemplo de raywenderlich.com. El código de muestra funciona perfectamente, pero desafortunadamente no hay temporizador durante la ubicación de fondo. Esto se ejecutará indefinidamente.
  2. Añadir temporizador mediante el uso de este fragmento de código:

    -(void)applicationDidEnterBackground { 
        [self.locationManager stopUpdatingLocation]; 
    
        UIApplication* app = [UIApplication sharedApplication]; 
    
        bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
        [app endBackgroundTask:bgTask]; 
        bgTask = UIBackgroundTaskInvalid; 
        }]; 
    
        self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate 
                   target:self.locationManager 
                   selector:@selector(startUpdatingLocation) 
                   userInfo:nil 
                   repeats:YES]; 
    } 
    
  3. Pero no se olvide de añadir "de la aplicación se registra para las actualizaciones de ubicación" en info.plist.

+3

¿De dónde viene 'bgTask'? – KKendall

+2

propiedad (no atómica) UIBackgroundTaskIdentifier bgTask; en la clase de encabezado – HelmiB

+2

@HelmiB: no está funcionando en ** iOS 7 **, ¿puede sugerir algo más, tengo que iniciar locationmanger en segundo plano? – Optimistic

0

Código de Trabajo (Todo el código paso a paso) código modificado de scurioni

Paso 1

  • Ir al proyecto -> Capacidades -> Modos de fondo -> seleccione Ubicación actualizaciones.
  • Vaya a Proyecto -> Información -> agregue una clave NSLocationAlwaysUsageDescription con una cadena opcional.

Paso 2

Añadir este código para AppDelegate.m

@interface AppDelegate()<CLLocationManagerDelegate> 
@property (strong, nonatomic) CLLocationManager *locationManager; 
@property (strong, nonatomic) NSTimer *timer; 
@end 

Paso 3 añadir este código a applicationDidEnterBackground método en el AppDelegate.m

- (void)applicationDidEnterBackground:(UIApplication *)application { 
     UIApplication *app = [UIApplication sharedApplication]; 
     __block UIBackgroundTaskIdentifier bgTaskId = 
     [app beginBackgroundTaskWithExpirationHandler:^{ 
      [app endBackgroundTask:bgTaskId]; 
      bgTaskId = UIBackgroundTaskInvalid; 
     }]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      self.timer = nil; 
      [self initTimer]; 
      [app endBackgroundTask:bgTaskId]; 
      bgTaskId = UIBackgroundTaskInvalid; 
     }); 
    } 

- (void)initTimer { 
    if (nil == self.locationManager) 
     self.locationManager = [[CLLocationManager alloc] init]; 

    self.locationManager.delegate = self; 
    [self.locationManager requestAlwaysAuthorization]; 
    [self.locationManager startMonitoringSignificantLocationChanges]; 
    if (self.timer == nil) { 
     self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3 
                 target:self 
                selector:@selector(checkUpdates:) 
                userInfo:nil 
                repeats:YES]; 
    } 
} 

- (void)checkUpdates:(NSTimer *)timer{ 
    UIApplication *app = [UIApplication sharedApplication]; 
    double remaining = app.backgroundTimeRemaining; 
    if(remaining < 580.0) { 
     [self.locationManager startUpdatingLocation]; 
     [self.locationManager stopUpdatingLocation]; 
     [self.locationManager startMonitoringSignificantLocationChanges]; 
    } 
} 

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
      fromLocation:(CLLocation *)oldLocation { 
    NSLog(@"Did Update Location = %f/%f", [newLocation coordinate].latitude, [newLocation coordinate].longitude); 
    [self updateLocationWithLatitude:[newLocation coordinate].latitude andLongitude:[newLocation coordinate].longitude]; 
    UIApplication* app = [UIApplication sharedApplication]; 
    __block UIBackgroundTaskIdentifier bgTask = 
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
     [app endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    }]; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     [self initTimer]; 
    }); 
} 

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { 
    [self.locationManager stopUpdatingLocation]; 
    UIApplication *app = [UIApplication sharedApplication]; 
    __block UIBackgroundTaskIdentifier bgTask = 
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
     [app endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    }]; 
    [self initTimer]; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     // Do the work associated with the task 
    }); 
} 

-(void)updateLocationWithLatitude:(CLLocationDegrees)latitude 
        andLongitude:(CLLocationDegrees)longitude{ 
//Here you can update your web service or back end with new latitude and longitude 
} 
Cuestiones relacionadas