2012-09-17 13 views
12

La mia app deve tracciare la posizione degli utenti in background ma non riesce a inviare una richiesta 'get'. La richiesta http viene inviata immediatamente quando l'app arriva in primo piano. Sto usando RestKit per tutte le mie richieste di rete e ho seguito this tutorial per configurare il servizio di localizzazione in background. Nel mio applicationDidEnterBackgroundSfondo iOS Posizione che non invia richiesta http

-(void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    self.bgLocationManager = [[CLLocationManager alloc] init]; 
    self.bgLocationManager.delegate = self; 
    [self.bgLocationManager startMonitoringSignificantLocationChanges]; 
    NSLog(@"Entered Background"); 
} 

e ho stopMonitoringSignificantLocationChange nel mio delegato applicationDidBecomeActive

Questo è il mio delegato locationManager in cui accetto la nuova posizione aggiornata e inviare al mio server

-(void) locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
      fromLocation:(CLLocation *)oldLocation 
{ 
    NSLog(@"I am in the background"); 
    bgTask = [[UIApplication sharedApplication] 
       beginBackgroundTaskWithExpirationHandler: 
       ^{ 
         [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
       }]; 
       // ANY CODE WE PUT HERE IS OUR BACKGROUND TASK 

    NSString *currentLatitude = [[NSString alloc] 
            initWithFormat:@"%g", 
            newLocation.coordinate.latitude]; 
    NSString *currentLongitude = [[NSString alloc] 
            initWithFormat:@"%g", 
            newLocation.coordinate.longitude]; 
    NSString *webToken = [[NSUserDefaults standardUserDefaults] stringForKey:@"userWebToken"]; 
    NSLog(@"I am in the bgTask, my lat %@", currentLatitude); 

    NSDictionary *queryParams; 
    queryParams = [NSDictionary dictionaryWithObjectsAndKeys:webToken, @"auth_token", currentLongitude, @"lng", currentLatitude, @"lat", nil]; 
    RKRequest* request = [[RKClient sharedClient] post:@"/api/locations/background_update" params:queryParams delegate:self]; 
    //default is RKRequestBackgroundPolicyNone 
    request.backgroundPolicy = RKRequestBackgroundPolicyContinue; 

    // AFTER ALL THE UPDATES, close the task 

    if (bgTask != UIBackgroundTaskInvalid) 
    { 
     [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    } 
} 

La rete richiede opere come previsto ma non verrà chiamato in background. Sono necessari ulteriori passaggi? Nel mio info.plist ho la chiave di modalità Background richiesta e servizi di localizzazione come valore.

EDIT

anche io di cui this past SO answer. Ho eseguito alcuni test con l'inserimento dei registri per tutta la chiamata didUpdateToLocation e sono stati tutti richiamati ma la richiesta 'get' non è stata inviata. Invece, quando finalmente lancio l'app in primo piano, ho inviato tutte le richieste di rete (oltre 10).

EDIT (2) Ho aggiunto RKRequestBackgroundPolicyContinua alla mia richiesta ma non ha modificato i miei risultati. (Come si può vedere here in background caricare/scaricare per restkit). Vedo che Restkit inizializza l'host ma non riesce a inviare la richiesta finché l'app non diventa attiva.

RISPOSTA

RestKit deve fare qualcosa che è proibito in background. L'utilizzo di un NSURLRequest funziona perfettamente.

NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.example.com/api/locations/background_update"]]; 
[urlRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"]; 
[urlRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 
[urlRequest setHTTPMethod:@"POST"]; 
[urlRequest setHTTPBody:jsonData]; 

NSHTTPURLResponse *response = nil; 
[NSURLConnection sendSynchronousRequest:urlRequest 
         returningResponse:&response 
            error:&error]; 

E 'bene utilizzare una richiesta sincrona poiché non v'è alcuna interfaccia utente di distruggere con le operazioni in background

+0

Avete provato a sostituire le vostre chiamate di restKit con un NSURLConnection sincrono di serie? – dklt

+0

concordo con la domanda di dklt, perché sembra probabile che la chiamata a '[[RKClient sharedClient] post: params: delegate:]' sta causando qualcosa che potrebbe accadere in una coda GCD dietro le quinte che non è coperta da il tuo bracketing backgroundTask ... e che le chiamate sincrone per ottenere i tuoi dati possono essere di aiuto in modo tale che le richieste vengano inviate mentre sono in background. sì, la RKRequestBackgroundPolicyContinue può essere pensata per occuparsi di questo, ma in realtà non lo stai impostando fino a dopo la chiamata al post: params: delegate: ea quel punto potrebbe essere troppo tardi. –

+0

@dklt Sono riuscito a farlo funzionare con una richiesta NSURLConnection, grazie per il suggerimento. Se metti una risposta, la accetterò. –

risposta

3

Ricreare suggerimento originale come una risposta

Avere il provare a sostituire il vostro restKit chiamate con uno stock NSURLConnection sincrono? - dklt set 20

-1

Quando sei applicazione è in esecuzione in background si può finire una richiesta HTTP è stato avviato prima di entrare lo sfondo ma non è possibile avviare una richiesta nuova. Puoi avviare certain network operations solo in background (voip, edicola).

+0

Grazie per la risposta, continuo a vedere informazioni contrastanti su questo argomento. Dai un'occhiata a questa risposta SO precedente, http://stackoverflow.com/questions/5394880/can-iphone-app-woken-in-background-for-significant-location-change-do-network-ac –

+0

@KyleC Quello che è dicendo, se trovi che la tua richiesta HTTP (che hai iniziato in primo piano) non termina prima che la tua app sia terminata, dovresti richiedere più tempo per completare la richiesta usando il metodo beginBackgroundTaskWithExpirationHandler :. Questo metodo consente di guadagnare tempo in più quando si accede allo sfondo per completare tutte le attività che si sono avviate e si desidera terminare, ma non è possibile avviare nuove richieste HTTP mentre si trova in questo stato, ho trovato questo intervallo tra 5 secondi e oltre 10 minuti. – Shizam

+2

Capisco questa parte e conosco il metodo beginBackgroundTaskWithExpirationHandler: è usato per le attività più lunghe da completare quando l'app va in background. Tuttavia, la sua risposta suggerisce che la tua app viene riattivata nello stato di sfondo dal cambiamento significativo della posizione e può utilizzare beginBackgroundTaskWithExpirationHandler: per completare una richiesta http in background. –

2

Sto usando esattamente lo stesso codice che hai e funziona per me in RestKit. L'unico modo per farlo funzionare è creare una richiesta sincrona (non ha molto senso farlo in modo asincrono in questo contesto comunque!). Si prega di verificare il codice e fateci sapere se funziona:

// REMEMBER. We are running in the background if this is being executed. 
// We can't assume normal network access. 
// bgTask is defined as an instance variable of type UIBackgroundTaskIdentifier 

// Note that the expiration handler block simply ends the task. It is important that we always 
// end tasks that we have started. 

_bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: 
      ^{ 
       [[UIApplication sharedApplication] endBackgroundTask:_bgTask]; 
      }]; 

// ANY CODE WE PUT HERE IS OUR BACKGROUND TASK 

// For example, I can do a series of SYNCHRONOUS network methods (we're in the background, there is 
// no UI to block so synchronous is the correct approach here). 

NSNumber *latNumber = [NSNumber numberWithDouble:location.coordinate.latitude]; 
NSNumber *lngNumber = [NSNumber numberWithDouble:location.coordinate.longitude]; 
NSNumber *accuracyNumber = [NSNumber numberWithDouble:location.horizontalAccuracy]; 
NSDictionary *params = [NSDictionary dictionaryWithKeysAndObjects:@"lat",latNumber,@"lng",lngNumber,@"accuracy",accuracyNumber, nil]; 
RKURL *URL = [RKURL URLWithBaseURL:[NSURL URLWithString:SERVER_URL] resourcePath:@"/user/location/update" queryParameters:params]; 
RKRequest *request = [RKRequest requestWithURL:URL]; 
request.method = RKRequestMethodGET; 
NSLog(@"Sending location to the server"); 
RKResponse *response = [request sendSynchronously]; 
if (response.isFailure) 
    NSLog(@"Unable to send background location, failure: %@", response.failureErrorDescription); 
else { 
    NSError *error = nil; 
    NSDictionary *parsedBody = [response parsedBody:&error]; 
    if (YES == [[parsedBody objectForKey:@"result"] boolValue]){ 
     NSLog(@"Background location sent to server"); 
    } 
    else { 
     //Something went bad 
     NSLog(@"Failed to send background location"); 
    } 
} 
// AFTER ALL THE UPDATES, close the task 

if (_bgTask != UIBackgroundTaskInvalid) 
{ 
    [[UIApplication sharedApplication] endBackgroundTask:_bgTask]; 
    _bgTask = UIBackgroundTaskInvalid; 
} 

Sono quasi sicuro che il nuovo thread generato per la vostra richiesta RKClient viene ucciso automaticamente dopo la invoca.

Problemi correlati