2016-05-05 44 views
10

Sto costruendo un app che utilizza CoreLocation per due scopi:partire CLLocationManager localizzazione aggiornamenti mentre applicazione è in background

  1. In primo luogo, il monitoraggio regioni beacon. Principalmente lavoriamo con un dispositivo hardware specifico che funge da faro e tracciamo con CoreLocation lo stato di quella connessione beacon.

  2. In secondo luogo, quando l'app rileva una disconnessione dal dispositivo beacon, vogliamo avviare un processo GPS per individuare dove si è verificata la disconnessione.

Nella maggior parte dei casi, la richiamata eventuale disconnessione beacon accade mentre l'applicazione è in background. Pertanto l'app deve avviare il tracciamento GPS chiamando lo -startUpdatingLocation mentre si trova in background.

E questo è il problema. iOS sembra non attivare gli aggiornamenti in background della posizione se la chiamata -startUpdatingLocation si è verificata mentre l'app era in background.

Ovviamente, ho configurato correttamente le modalità di sfondo, , impostare la proprietà _locationManager.allowsBackgroundLocationUpdates su YES.

La cosa sorprendente: se chiamo -startUpdatingLocation mentre sono in primo piano e poi passo allo sfondo, gli aggiornamenti di posizione vengono inviati correttamente mentre sono in background. Tuttavia, quando si chiama -startUpdatingLocation mentre si trova in background, l'applicazione riceve 2 o 3 aggiornamenti di posizione e quindi si interrompe per sempre .. finché non riporto manualmente l'applicazione in primo piano, quando gli aggiornamenti di posizione riprendono e continuano a funzionare anche se si passa l'app allo sfondo di nuovo.

Qualcuno sa o capisce cosa devo fare per risolvere questo problema? o è un vincolo principale di iOS? A causa dei requisiti della mia app ho davvero bisogno di iniziare a localizzare gli aggiornamenti mentre l'app è in background (all'interno della callback di un beacon ha fatto uscire la regione).

Btw, se si desidera riprodurre questo problema è molto semplice. Basta creare un progetto vuoto in Xcode e aggiungere questo codice al controller di visualizzazione predefinito. Ricorda di abilitare le modalità di background aggiungere una descrizione alla tua chiave info.plist "NSLocationAlwaysUsageDescription".

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    _locationManager = [[CLLocationManager alloc] init]; 

    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_8_3) 
     _locationManager.allowsBackgroundLocationUpdates = YES; 

    _locationManager.delegate = self; 
    _locationManager.activityType = CLActivityTypeOther; 
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest; 
    _locationManager.distanceFilter = kCLDistanceFilterNone; 

    [_locationManager requestAlwaysAuthorization]; 

    // Creating a background task to delay the start of the startUpdatingLocation 
    __block UIBackgroundTaskIdentifier taskIdentifier = UIBackgroundTaskInvalid; 
    taskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     [[UIApplication sharedApplication] endBackgroundTask:taskIdentifier]; 
    }]; 

    // Delaying the call to startUpdatingLocation 10 seconds, enough time to dismiss the application 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     [_locationManager startUpdatingLocation]; 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
      [[UIApplication sharedApplication] endBackgroundTask:taskIdentifier]; 
     }); 
    }); 
} 

Poi, traccia il delegato CLLocationManager facendo alcuni NSLogs e vediamo cosa succede.

Grazie,

+0

Ho lo stesso problema. Nel mio caso, le posizioni potrebbero essere piuttosto lunghe, o solo pochi secondi, poi si interrompe o non si avvia affatto. Cerco anche di mantenere l'attività in background in esecuzione quando si avvia la posizione in background, ma non ho fortuna ... – nahung89

risposta

2

Sono passati 3 mesi da quando hai postato questa domanda. L'hai già capito da solo?

Ho provato il codice. Ho aggiunto un po 'di alle funzioni di delegato AppDelegate e allo viewDidLoad. Inoltre, nella classe AppDelegate, ho interrotto il tempo di fondo rimasto.

Se startUpdatingLocation è chiamato prima di andare in secondo piano:

2016-08-18 01:22:52.355 test background GPS from StackOF[2267:745042] viewDidLoad 
2016-08-18 01:22:52.376 test background GPS from StackOF[2267:745042] _locationManager.allowsBackgroundLocationUpdates = YES; 
2016-08-18 01:22:52.382 test background GPS from StackOF[2267:745042] _locationManager requestAlwaysAuthorization 
2016-08-18 01:22:52.410 test background GPS from StackOF[2267:745042] applicationDidBecomeActive 
2016-08-18 01:22:52.469 test background GPS from StackOF[2267:745042] viewDidAppear 
2016-08-18 01:23:03.361 test background GPS from StackOF[2267:745042] [_locationManager startUpdatingLocation]; 
2016-08-18 01:23:03.362 test background GPS from StackOF[2267:745042] start updating location, _locationManager.allowsBackgroundLocationUpdates == YES 
2016-08-18 01:23:03.382 test background GPS from StackOF[2267:745042] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 65.000000 
2016-08-18 01:23:03.630 test background GPS from StackOF[2267:745042] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 1743.000000 
2016-08-18 01:23:03.709 test background GPS from StackOF[2267:745042] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 1743.000000 
2016-08-18 01:23:03.716 test background GPS from StackOF[2267:745042] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 1743.000000 
2016-08-18 01:23:03.720 test background GPS from StackOF[2267:745042] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 1743.000000 
2016-08-18 01:23:03.814 test background GPS from StackOF[2267:745042] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 65.000000 
2016-08-18 01:23:05.004 test background GPS from StackOF[2267:745042] inner block [[UIApplication sharedApplication] endBackgroundTask:taskIdentifier]; 
2016-08-18 01:23:05.005 test background GPS from StackOF[2267:745042] inner block start updating location, _locationManager.allowsBackgroundLocationUpdates == YES 
2016-08-18 01:23:08.287 test background GPS from StackOF[2267:745042] applicationDidEnterBackground. Background time left: 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000 
2016-08-18 01:23:10.319 test background GPS from StackOF[2267:745042] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 65.000000 
2016-08-18 01:23:19.321 test background GPS from StackOF[2267:745042] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 65.000000 
/**** 
Keep on polling... 
****/ 

Se startUpdatingLocation è chiamato dopo essere andato in secondo piano:

2016-08-18 01:34:29.023 test background GPS from StackOF[2285:747132] viewDidLoad 
2016-08-18 01:34:29.030 test background GPS from StackOF[2285:747132] _locationManager.allowsBackgroundLocationUpdates = YES; 
2016-08-18 01:34:29.033 test background GPS from StackOF[2285:747132] _locationManager requestAlwaysAuthorization 
2016-08-18 01:34:29.047 test background GPS from StackOF[2285:747132] applicationDidBecomeActive 
2016-08-18 01:34:29.104 test background GPS from StackOF[2285:747132] viewDidAppear 
2016-08-18 01:34:31.612 test background GPS from StackOF[2285:747132] applicationDidEnterBackground. Background time left: 179.964144 
2016-08-18 01:34:40.004 test background GPS from StackOF[2285:747132] [_locationManager startUpdatingLocation]; 
2016-08-18 01:34:40.006 test background GPS from StackOF[2285:747132] start updating location, _locationManager.allowsBackgroundLocationUpdates == YES 
2016-08-18 01:34:40.290 test background GPS from StackOF[2285:747132] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 10.000000 
2016-08-18 01:34:40.332 test background GPS from StackOF[2285:747132] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 355.117789 
2016-08-18 01:34:40.336 test background GPS from StackOF[2285:747132] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 355.118536 
2016-08-18 01:34:40.493 test background GPS from StackOF[2285:747132] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 355.141209 
2016-08-18 01:34:40.496 test background GPS from StackOF[2285:747132] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 355.147748 
2016-08-18 01:34:40.505 test background GPS from StackOF[2285:747132] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 355.148158 
2016-08-18 01:34:40.507 test background GPS from StackOF[2285:747132] Lat/Long: <redacted GPS coordinates>, horizontal accuracy: 65.000000 
2016-08-18 01:34:41.640 test background GPS from StackOF[2285:747132] inner block [[UIApplication sharedApplication] endBackgroundTask:taskIdentifier]; 
2016-08-18 01:34:41.642 test background GPS from StackOF[2285:747132] inner block start updating location, _locationManager.allowsBackgroundLocationUpdates == YES 
/**** 
stops polling... 
****/ 

Prendere nota del tempo di fondo a sinistra. Se l'app va in background prima che CLLocationManager inizi ad aggiornare la posizione, il tempo di sfondo rimasto è di 3 minuti. Non sono troppo sicuro di me stesso perché anch'io ho il mio problema con il GPS in esecuzione, ma da questo breve test sembra che CLLocationManager debba essere chiamato prima che l'app vada in secondo piano.

Ecco dove ho messo le mie NSLogs:

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
    NSLog(@"viewDidLoad"); 

    _locationManager = [[CLLocationManager alloc] init]; 

    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_8_3) 
    { 
     _locationManager.allowsBackgroundLocationUpdates = YES; 
     NSLog(@"_locationManager.allowsBackgroundLocationUpdates = YES;"); 
    } 



    _locationManager.delegate = self; 
    _locationManager.activityType = CLActivityTypeOther; 
    _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation; 
    _locationManager.distanceFilter = kCLDistanceFilterNone; 

    [_locationManager requestAlwaysAuthorization]; 
    NSLog(@"_locationManager requestAlwaysAuthorization"); 

    // Creating a background task to delay the start of the startUpdatingLocation 
    __block UIBackgroundTaskIdentifier taskIdentifier = UIBackgroundTaskInvalid; 
    taskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     [[UIApplication sharedApplication] endBackgroundTask:taskIdentifier]; 
     NSLog(@"[[UIApplication sharedApplication] endBackgroundTask:taskIdentifier];"); 
    }]; 

    // Delaying the call to startUpdatingLocation 10 seconds, enough time to dismiss the application 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     [_locationManager startUpdatingLocation]; 
     NSLog(@"[_locationManager startUpdatingLocation];"); 
     if(_locationManager.allowsBackgroundLocationUpdates == YES) 
     { 
      NSLog(@"start updating location, _locationManager.allowsBackgroundLocationUpdates == YES"); 
     } 
     else 
     { 
      NSLog(@"start updating location, _locationManager.allowsBackgroundLocationUpdates == NO"); 
     } 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
      [[UIApplication sharedApplication] endBackgroundTask:taskIdentifier]; 
      NSLog(@"inner block [[UIApplication sharedApplication] endBackgroundTask:taskIdentifier];"); 
      if(_locationManager.allowsBackgroundLocationUpdates == YES) 
      { 
       NSLog(@"inner block start updating location, _locationManager.allowsBackgroundLocationUpdates == YES"); 
      } 
      else 
      { 
       NSLog(@"inner block start updating location, _locationManager.allowsBackgroundLocationUpdates == NO"); 
      } 

     }); 
    }); 

} 

La funzione CLLocationManager delegato:

-(void)locationManager:(CLLocationManager *) manager didUpdateLocations:(nonnull NSArray<CLLocation *> *)locations 
{ 
    CLLocation *location = [locations firstObject]; 
    NSLog(@"Lat/Long: %f %f, horizontal accuracy: %f", 
      location.coordinate.latitude, 
      location.coordinate.longitude, 
      location.horizontalAccuracy); 
} 

L'AppDelegate:

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

    NSLog(@"applicationDidEnterBackground. Background time left: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]); 

} 

TL; DR: provare a chiamare startUpdatingLocation proprio nel viewDidLoad o AppDelegate application:didFinishLaunchingWithOptions: