web-dev-qa-db-fra.com

Mises à jour périodiques de l'emplacement d'arrière-plan iOS

J'écris une application qui nécessite des mises à jour d'emplacement en arrière-plan avec haute précision et basse fréquence. La solution semble être une tâche NSTimer d'arrière-plan qui lance les mises à jour du gestionnaire d'emplacement, qui s'arrête immédiatement. Cette question a déjà été posée:

Comment obtenir une mise à jour d'emplacement d'arrière-plan toutes les n minutes dans mon application iOS?

Obtenir l'emplacement de l'utilisateur toutes les n minutes après le passage de l'application à l'arrière-plan

iOS Pas le problème typique du minuteur de suivi de l'emplacement en arrière-plan

Minuterie de fond iOS longue durée avec mode arrière-plan "emplacement"

Service d'arrière-plan iOS à temps plein basé sur le suivi de la localisation

mais je n'ai pas encore obtenu un exemple minimum fonctionnel. Après avoir essayé toutes les permutations des réponses acceptées ci-dessus, j'ai établi un point de départ. Saisie du fond:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        NSLog(@"ending background task");
        [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
        self.bgTask = UIBackgroundTaskInvalid;
    }];


    self.timer = [NSTimer scheduledTimerWithTimeInterval:60
                                                  target:self.locationManager
                                                selector:@selector(startUpdatingLocation)
                                                userInfo:nil
                                                 repeats:YES];
}

et la méthode déléguée:

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

    NSLog(@"%@", newLocation);

    NSLog(@"background time: %f", [UIApplication sharedApplication].backgroundTimeRemaining);
    [self.locationManager stopUpdatingLocation];

}

Le comportement actuel est que la variable backgroundTimeRemaining diminue de 180 secondes à zéro (lors de la journalisation de l'emplacement), puis que le gestionnaire d'expiration est exécuté et qu'aucune autre mise à jour d'emplacement n'est générée. Comment modifier le code ci-dessus afin de recevoir indéfiniment des mises à jour d'emplacement périodiques en arrière-plan?

Update: je cible iOS 7 et certains éléments semblent indiquer que les tâches en arrière-plan se comportent différemment:

Démarrez Location Manager dans iOS 7 à partir de la tâche en arrière-plan

87
pcoving

Il semble que stopUpdatingLocation est ce qui déclenche le chronomètre de surveillance en arrière-plan. Je l'ai donc remplacé dans didUpdateLocation par:

[self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
[self.locationManager setDistanceFilter:99999];

qui semble éteindre efficacement le GPS. Le sélecteur pour l'arrière-plan NSTimer devient alors:

- (void) changeAccuracy {
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
    [self.locationManager setDistanceFilter:kCLDistanceFilterNone];
}

Tout ce que je fais, c'est d'inverser périodiquement la précision pour obtenir une coordonnée de haute précision toutes les quelques minutes. Étant donné que locationManager n'a pas été arrêté, backgroundTimeRemaining conserve sa valeur maximale. Cela a réduit la consommation de la batterie d'environ 10% par heure (avec une constante kCLLocationAccuracyBest en arrière-plan) à environ 2% par heure sur mon appareil.

61
pcoving
  1. Si vous avez la UIBackgroundModes dans votre plist avec la clé location, vous n'avez pas besoin d'utiliser la méthode beginBackgroundTaskWithExpirationHandler. C'est redondant. De plus, vous l'utilisez incorrectement (voir ici ), mais c'est inutile puisque votre plist est en place. 

  2. Avec UIBackgroundModes location dans la fenêtre d’application, l’application continuera de fonctionner en arrière-plan indéfiniment aussi longtemps que CLLocationManger est en cours d’exécution. Si vous appelez stopUpdatingLocation en arrière-plan, l'application s'arrête et ne redémarre plus. 

    Peut-être pourriez-vous appeler beginBackgroundTaskWithExpirationHandler juste avant d'appeler stopUpdatingLocation et ensuite, après avoir appelé startUpdatingLocation, vous pourriez appeler endBackgroundTask pour le garder en arrière-plan lorsque le GPS est arrêté, mais je n'ai jamais essayé cela - ce n'est qu'une idée.

    Une autre option (que je n'ai pas encore essayée) est de laisser le gestionnaire de localisation actif en arrière-plan, mais une fois que vous avez trouvé un emplacement précis, modifiez la propriété desiredAccuracy à 1000 m ou plus pour permettre à la puce GPS de s'éteindre (pour économiser la batterie). . Puis, 10 minutes plus tard, lorsque vous avez besoin d'une autre mise à jour d'emplacement, modifiez la valeur desiredAccuracy à 100m pour allumer le GPS jusqu'à obtenir un emplacement précis. Répétez l'opération.

  3. Lorsque vous appelez startUpdatingLocation sur le responsable de la localisation, vous devez lui laisser le temps d’obtenir un poste. Vous ne devez pas appeler immédiatement stopUpdatingLocation. Nous le laissons fonctionner pendant 10 secondes maximum ou jusqu'à ce que nous obtenions un emplacement haute précision non mis en cache.

  4. Vous devez filtrer les emplacements mis en cache et vérifier l'exactitude de l'emplacement que vous obtenez pour vous assurer qu'il correspond au minimum requis (voir ici ). La première mise à jour que vous obtenez peut être vieille de 10 minutes ou 10 minutes. La première précision que vous obtenez peut être 3000m. 

  5. Pensez plutôt à utiliser les API de changement d'emplacement significatif. Une fois que vous avez reçu la notification de changement significatif, vous pouvez démarrer CLLocationManager pendant quelques secondes pour obtenir une position très précise. Je ne suis pas certain, je n'ai jamais utilisé les services importants de changement de lieu.

32
progrmr

Lorsqu'il est temps de démarrer le service de localisation et d'arrêter la tâche en arrière-plan, celle-ci doit être arrêtée avec un retard (une seconde devrait suffire). Sinon, le service de localisation ne démarrera pas. De plus, le service de localisation doit rester allumé pendant quelques secondes (par exemple, 3 secondes).

Il existe un cocoapod APScheduledLocationManager qui permet d'obtenir des mises à jour d'emplacement d'arrière-plan toutes les n secondes avec la précision d'emplacement souhaitée.

let manager = APScheduledLocationManager(delegate: self)
manager.startUpdatingLocation(interval: 170, acceptableLocationAccuracy: 100)

Le référentiel contient également un exemple d'application écrit dans Swift 3.

8
sash

Pourquoi ne pas essayer avec l'API startMonitoringSignificantLocationChanges:? Il tire définitivement avec moins de fréquence et la précision est raisonnablement bonne. De plus, il présente de nombreux avantages par rapport aux autres API locationManager.

Beaucoup plus concernant cette API a déjà été discuté à ce sujet link

1
thatzprem

Vous devez ajouter le mode de mise à jour d'emplacement dans votre application en ajoutant la clé suivante dans votre info.plist.

<key>UIBackgroundModes</key>
<array>
    <string>location</string>
</array>

La méthode didUpdateToLocation sera appelée (même si votre application est en arrière-plan). Vous pouvez effectuer n'importe quoi sur les bases de cet appel de méthode

1
aahsanali

Après iOS 8, Apple a apporté plusieurs modifications à l'extraction en arrière-plan et aux mises à jour liées à la structure CoreLocation.

1) Apple introduit la demande AlwaysAuthorization pour extraire la mise à jour de la localisation dans l'application.

2) Apple introduit backgroundLocationupdates pour extraire l’emplacement de l’arrière-plan dans iOS.

Pour récupérer l'emplacement en arrière-plan, vous devez activer la mise à jour de l'emplacement dans les fonctionnalités de Xcode.

//
//  ViewController.Swift
//  DemoStackLocation
//
//  Created by iOS Test User on 02/01/18.
//  Copyright © 2018 iOS Test User. All rights reserved.
//

import UIKit
import CoreLocation

class ViewController: UIViewController {

    var locationManager: CLLocationManager = CLLocationManager()
    override func viewDidLoad() {
        super.viewDidLoad()
        startLocationManager()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    internal func startLocationManager(){
        locationManager.requestAlwaysAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.delegate = self
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.startUpdatingLocation()
    }

}

extension ViewController : CLLocationManagerDelegate {

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
        let location = locations[0] as CLLocation
        print(location.coordinate.latitude) // prints user's latitude
        print(location.coordinate.longitude) //will print user's longitude
        print(location.speed) //will print user's speed
    }

}
0
Tech

Pour utiliser les services de localisation standard lorsque l'application est en arrière-plan, vous devez d'abord activer les modes de fond dans l'onglet Capacités des paramètres de la cible, puis sélectionner Mises à jour de la localisation.

Ou, ajoutez-le directement à la Info.plist .

<key>NSLocationAlwaysUsageDescription</key>
 <string>I want to get your location Information in background</string>
<key>UIBackgroundModes</key>
 <array><string>location</string> </array>

Ensuite, vous devez configurer le CLLocationManager

Objectif C

//The Location Manager must have a strong reference to it.
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
//Request Always authorization (iOS8+)
if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { [_locationManager requestAlwaysAuthorization];
}
//Allow location updates in the background (iOS9+)
if ([_locationManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) { _locationManager.allowsBackgroundLocationUpdates = YES;
}
[_locationManager startUpdatingLocation];

Rapide

self.locationManager.delegate = self
if #available (iOS 8.0,*) {
    self.locationManager.requestAlwaysAuthorization()
}
if #available (iOS 9.0,*) {
    self.locationManager.allowsBackgroundLocationUpdates = true
}
self.locationManager.startUpdatingLocation()

Réf.: https://medium.com/@javedmultani16/location-service-in-the-background-ios-942c89cd99ba

0
Mr.Javed Multani