2016-03-22 51 views
11

Ho scritto il codice seguente che ha un timer che chiama una funzione di richiamata ogni minuto. Quando l'app va in secondo piano, ho avviato un altro timer che chiama lo stesso metodo di callback, ma il timer dello sfondo funziona solo per tre minuti.Eseguire un'app Swift 2.0 per sempre in background per aggiornare la posizione sul server

Comprendo che Apple consente attività in background per soli tre minuti. La mia app è più simile a un'app di monitoraggio che traccia la posizione dell'utente ogni minuto anche quando l'app è in background, quindi ho bisogno di implementare questa funzionalità.

Ho appreso che è necessario utilizzare beginBackgroundTaskWithExpirationHandler ma non so se la mia implementazione è corretta.

Nota: sono necessarie le modalità in background nei registri plist su app per gli aggiornamenti di posizione.

Qualsiasi codice o collegamento funzionante è molto apprezzato.

override func viewDidLoad() { 
    super.viewDidLoad() 

    timeInMinutes = 1 * 60 

    self.locationManager.requestAlwaysAuthorization() 

    self.locationManager.requestWhenInUseAuthorization() 

    if CLLocationManager.locationServicesEnabled() { 
     locationManager.delegate = self 
     locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters 
     locationManager.startUpdatingLocation() 
    } 

    var timer = NSTimer.scheduledTimerWithTimeInterval(timeInMinutes, target: self, selector: "updateLocation", userInfo: nil, repeats: true) 
} 

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){ 
    let locValue:CLLocationCoordinate2D = manager.location!.coordinate 

    self.latitude = locValue.latitude 
    self.longitude = locValue.longitude 

    if UIApplication.sharedApplication().applicationState == .Active { 

    } else { 
     backgroundTaskIdentifier = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({() -> Void in 
      self.backgroundTimer.invalidate() 
      self.backgroundTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: "updateLocation", userInfo: nil, repeats: true) 
     }) 
    } 
} 

func updateLocation() { 
    txtlocationLabel.text = String(n) 
    self.n = self.n+1 

    var timeRemaining = UIApplication.sharedApplication().backgroundTimeRemaining 

    print(timeRemaining) 

    if timeRemaining > 60.0 { 
     self.GeoLogLocation(self.latitude,Longitude: self.longitude) { 
      results in 
      print("View Controller: \(results)") 
      self.CheckResult(String(results)) 
     } 
    } else { 
     if timeRemaining == 0 { 
      UIApplication.sharedApplication().endBackgroundTask(backgroundTaskIdentifier) 
     } 

     backgroundTaskIdentifier2 = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({() -> Void in 
      self.backgroundTimer.invalidate() 
      self.backgroundTimer = NSTimer.scheduledTimerWithTimeInterval(60.0, target: self, selector: "updateLocation", userInfo: nil, repeats: true) 
     }) 
    } 
} 

risposta

16

aggiornamenti sulla posizione periodici sono un po 'complicato in un buon filo di IOS.There che discute questo, si può leggere di più here

iOS sospendere l'applicazione dopo pochi minuti, a prescindere se il timer è in funzione o no. C'è un modo per aggirare questo, però, ho dovuto fare qualcosa di simile quando ho scritto un'app ionica in modo da poter controllare il codice per questo here, quel collegamento ha una classe veloce che gestisce gli aggiornamenti periodici di posizione in iOs.

Per ottenere posizioni periodiche in background e non scaricare la batteria del dispositivo, è necessario giocare con la precisione dei record di posizione, ridurre la precisione del gestore località impostando la sua accuratezza desiderata su kCLLocationAccuracyThreeKilometers, quindi, ogni 60 secondi è necessario modificare l'accuratezza in kCLLocationAccuracyBest, ciò consentirà al delegato di ottenere un nuovo aggiornamento preciso della posizione, quindi ripristinare la precisione al minimo. Il timer deve essere inizializzato ogni volta che viene ricevuto un aggiornamento.

C'è anche un modo per riattivare l'app in background dopo che è stata uccisa dall'utente, utilizzare il delegato dell'app per fare in modo che l'app ascolti cambiamenti significativi nella posizione prima della sua morte. Questo farà riattivare l'app in background quando la posizione dell'utente fa un grande salto (può essere intorno ai 200 ms). Quando l'app si riattiva, interrompi il monitoraggio per apportare modifiche significative e riavvia i servizi di localizzazione come di consueto per continuare gli aggiornamenti periodici.

Spero che questo aiuti.

Aggiornamento

In Swift 2 Avrete anche bisogno di:

self.locationManager.allowsBackgroundLocationUpdates = true 
+0

Grazie per l'aiuto ... Sono abbastanza nuovo per Swift ... Ho provato a cambiare il valore di precisione ogni 60 secondi come hai detto ... Ho ancora lo stesso risultato (cioè l'app esegue e aggiorna la posizione solo per tre minuti dopo lo sfondo) – Carey

+1

Ciao, scusami ho dimenticato di menzionare, e credo che questo manchi nel tuo codice, devi anche abilitare le posizioni in background nel tuo location manager, qualcosa sulla falsariga di self.locationManager.allowsBackgroundLocationUpdates = true –

+0

Grazie mille. Ha funzionato! – Carey

0

È possibile utilizzare libreria per background location tracking, esempio di utilizzo:

var backgroundLocationManager = BackgroundLocationManager() 

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { 

    backgroundLocationManager.startBackground() { result in 
      if case let .Success(location) = result { 
       LocationLogger().writeLocationToFile(location: location) 
      } 
    } 

    return true 
} 

che sta funzionando quando l'applicazione è ucciso o sospeso.