Je cherche un moyen d'obtenir une mise à jour de l'emplacement en arrière-plan toutes les n minutes dans mon application iOS. J'utilise iOS 4.3 et la solution devrait fonctionner pour les iPhones non jailbreakés.
J'ai essayé / envisagé les options suivantes:
CLLocationManager startUpdatingLocation/startMonitoringSignificantLocationChanges
: Cela fonctionne en arrière-plan comme prévu, en fonction des propriétés configurées, mais il ne semble pas possible de le forcer à mettre à jour l'emplacement toutes les n minutesNSTimer
: Fonctionne lorsque l'application s'exécute au premier plan, mais ne semble pas être conçue pour les tâches en arrière-plan- Notifications locales: les notifications locales peuvent être planifiées toutes les n minutes, mais il n'est pas possible d'exécuter du code pour obtenir l'emplacement actuel (sans que l'utilisateur n'ait à lancer l'application via la notification). Cette approche ne semble pas non plus être une approche propre, car ce n'est pas pour cela que les notifications doivent être utilisées.
UIApplication:beginBackgroundTaskWithExpirationHandler
: D'après ce que je comprends, cela devrait être utilisé pour terminer certains travaux en arrière-plan (également limités dans le temps) lorsqu'une application est déplacée en arrière-plan plutôt que de mettre en œuvre des processus d'arrière-plan "de longue durée".
Comment puis-je implémenter ces mises à jour régulières de l'emplacement en arrière-plan?
Réponses:
J'ai trouvé une solution pour l'implémenter à l'aide des forums des développeurs Apple:
location background mode
NSTimer
en arrière-plan avecUIApplication:beginBackgroundTaskWithExpirationHandler:
n
est plus petit queUIApplication:backgroundTimeRemaining
cela fonctionnera très bien. Lorsquen
est plus grand , lelocation manager
doit être réactivé (et désactivé) avant qu'il ne reste plus de temps pour éviter que la tâche d'arrière-plan ne soit supprimée.Cela fonctionne car l'emplacement est l'un des trois types d'exécution en arrière-plan autorisés .
Remarque: j'ai perdu du temps en testant cela dans le simulateur où cela ne fonctionne pas. Cependant, cela fonctionne bien sur mon téléphone.
la source
Sur iOS 8/9/10 pour effectuer la mise à jour de l'emplacement en arrière-plan toutes les 5 minutes, procédez comme suit:
Allez dans Project -> Capabilities -> Background Modes -> select Location updates
Allez dans Projet -> Info -> ajoutez une clé NSLocationAlwaysUsageDescription avec une valeur vide (ou éventuellement n'importe quel texte)
Pour faire fonctionner l'emplacement lorsque votre application est en arrière-plan et envoyer des coordonnées au service Web ou faire quoi que ce soit avec elles toutes les 5 minutes, implémentez-le comme dans le code ci-dessous.
Je n'utilise aucune tâche d'arrière-plan ni aucun minuteur. J'ai testé ce code avec mon appareil avec iOS 8.1 qui était allongé sur mon bureau pendant quelques heures avec mon application en arrière-plan. L'appareil était verrouillé et le code fonctionnait correctement tout le temps.
la source
if ([self.locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) { [self.locationManager setAllowsBackgroundLocationUpdates:YES]; }
Je l'ai fait dans une application que je développe. Les minuteries ne fonctionnent pas lorsque l'application est en arrière-plan, mais l'application reçoit constamment les mises à jour de l'emplacement. J'ai lu quelque part dans la documentation (je n'arrive pas à le trouver maintenant, je publierai une mise à jour lorsque je le ferai) qu'une méthode ne peut être appelée que sur une boucle d'exécution active lorsque l'application est en arrière-plan. Le délégué de l'application a une boucle d'exécution active même dans le bg, vous n'avez donc pas besoin de créer la vôtre pour que cela fonctionne. [Je ne sais pas si c'est la bonne explication mais c'est comme ça que j'ai compris de ce que j'ai lu]
Tout d'abord, ajoutez l'
location
objet de la cléUIBackgroundModes
dans info.plist de votre application. Maintenant, ce que vous devez faire, c'est commencer les mises à jour de position n'importe où dans votre application:Ensuite, écrivez une méthode pour gérer les mises à jour d'emplacement, par exemple
-(void)didUpdateToLocation:(CLLocation*)location
, dans le délégué d'application. Ensuite, implémentez la méthodelocationManager:didUpdateLocation:fromLocation
deCLLocationManagerDelegate
dans la classe dans laquelle vous avez démarré le gestionnaire d'emplacement (puisque nous avons défini le délégué du gestionnaire d'emplacement sur 'self'). Dans cette méthode, vous devez vérifier si l'intervalle de temps après lequel vous devez gérer les mises à jour de l'emplacement s'est écoulé. Vous pouvez le faire en enregistrant l'heure actuelle à chaque fois. Si ce temps s'est écoulé, appelez la méthode UpdateLocation depuis votre délégué d'application:Cela appellera votre méthode toutes les 5 minutes, même lorsque votre application est en arrière-plan. Imp: Cette implémentation vide la batterie, si la précision de vos données de localisation n'est pas critique, vous devez utiliser
[locationManager startMonitoringSignificantLocationChanges]
Avant d'ajouter ceci à votre application, veuillez lire le Guide de programmation de détection d'emplacement
la source
Maintenant qu'iOS6 est sorti, la meilleure façon d'avoir des services de localisation toujours actifs est ...
Je l'ai juste testé comme ça:
J'ai démarré l'application, je vais en arrière-plan et je me déplace dans la voiture de quelques minutes. Ensuite, je rentre chez moi pendant 1 heure et recommence à bouger (sans rouvrir l'application). Les emplacements ont recommencé. Puis s'est arrêté pendant deux heures et a recommencé. Tout va bien encore ...
N'OUBLIEZ PAS D'UTILISER les nouveaux services de localisation dans iOS6
la source
Pour quelqu'un d'autre ayant un cauchemar, comprenez celui-ci. J'ai une solution simple.
Ajouter un minuteur en utilisant:
N'oubliez pas d'ajouter "Registres d'application pour les mises à jour de localisation" dans info.plist.
la source
Voici ce que j'utilise:
Je démarre le suivi dans AppDelegate comme ça:
la source
Malheureusement, toutes vos hypothèses semblent correctes, et je ne pense pas qu'il existe un moyen de le faire. Afin d'économiser la batterie, les services de localisation de l'iPhone sont basés sur le mouvement. Si le téléphone se trouve au même endroit, il est invisible pour les services de localisation.
Le
CLLocationManager
ne fera qu'appelerlocationManager:didUpdateToLocation:fromLocation:
lorsque le téléphone recevra une mise à jour de localisation, ce qui ne se produit que si l'un des trois services de localisation (tour cellulaire, GPS, Wi-Fi) perçoit un changement.Quelques autres choses qui pourraient aider à éclairer d'autres solutions:
Le démarrage et l'arrêt des services entraînent l'
didUpdateToLocation
appel de la méthode déléguée, mais ilsnewLocation
peuvent avoir un ancien horodatage.La surveillance de la région pourrait aider
Lors de l'exécution en arrière-plan, sachez qu'il peut être difficile d'obtenir une prise en charge «complète» des LocationServices approuvée par Apple. D'après ce que j'ai vu, ils ont été spécifiquement conçus
startMonitoringSignificantLocationChanges
comme une alternative à faible consommation pour les applications qui nécessitent une prise en charge de l'emplacement en arrière-plan, et encouragent fortement les développeurs à l'utiliser à moins que l'application n'en ait absolument besoin.Bonne chance!
MISE À JOUR: Ces pensées peuvent être obsolètes à ce jour. On dirait que les gens ont du succès avec la réponse @wjans, ci-dessus.
la source
startMonitoringSignificantLocationChanges
je ne donnerais aucune mise à jour dans ce cas.J'ai écrit une application à l'aide des services de localisation, l'application doit envoyer une position toutes les 10 secondes. Et cela a très bien fonctionné.
Utilisez simplement le " allowDeferredLocationUpdatesUntilTraveled: timeout ", en suivant le doc d'Apple.
Ce que j'ai fait, c'est:
Obligatoire: enregistrer le mode d'arrière-plan pour l'emplacement de mise à jour.
1. Créez
LocationManger
etstartUpdatingLocation
, avecaccuracy
etfilteredDistance
comme vous voulez:2. Pour que l'application s'exécute indéfiniment en utilisant la
allowDeferredLocationUpdatesUntilTraveled:timeout
méthode en arrière-plan, vous devez redémarrerupdatingLocation
avec un nouveau paramètre lorsque l'application se déplace en arrière-plan, comme ceci:3. L' application est mise à jour comme d'habitude avec un
locationManager:didUpdateLocations:
rappel:4. Mais vous devez gérer les données puis les
locationManager:didFinishDeferredUpdatesWithError:
rappeler en fonction de votre objectif5. REMARQUE: je pense que nous devrions réinitialiser les paramètres de
LocationManager
chaque fois que l'application bascule entre le mode d'arrière-plan / de fondla source
pausesLocationUpdatesAutomatically = true
au gestionnaire de localisation de suspendre les mises à jour s'il n'y a apparemment aucun changement de localisation ( doc d'Apple ). Quoi qu'il en soit, je n'ai pas encore explicitement testé le cas delocation manager pauses updates
: D.pausesLocationUpdatesAutomatically = true
mon application de mettre à jour l'emplacement.Cela est nécessaire pour le suivi de l'emplacement en arrière-plan depuis iOS 9.
la source
J'ai utilisé la méthode de xs2bush pour obtenir un intervalle (en utilisant
timeIntervalSinceDate
) et développé un peu. Je voulais m'assurer que j'obtenais la précision requise dont j'avais besoin et aussi que je n'épuisais pas la batterie en gardant la radio gps allumée plus que nécessaire.Je maintiens la localisation en continu avec les paramètres suivants:
il s'agit d'un drain relativement faible sur la batterie. Lorsque je suis prêt à obtenir ma prochaine lecture d'emplacement périodique, je vérifie d'abord si l'emplacement est dans la précision souhaitée, si c'est le cas, j'utilise ensuite l'emplacement. Si ce n'est pas le cas, j'augmente la précision avec ceci:
obtenir mon emplacement, puis une fois que j'ai l'emplacement, je baisse à nouveau la précision pour minimiser la décharge de la batterie. J'ai écrit un échantillon de travail complet de cela et j'ai également écrit la source du code côté serveur pour collecter les données de localisation, les stocker dans une base de données et permettre aux utilisateurs de visualiser les données GPS en temps réel ou de récupérer et d'afficher les itinéraires précédemment stockés. J'ai des clients pour iOS, android, windows phone et java me. Tous les clients sont écrits en natif et fonctionnent tous correctement en arrière-plan. Le projet est sous licence MIT.
Le projet iOS est ciblé pour iOS 6 à l'aide d'un SDK de base d'iOS 7. Vous pouvez obtenir le code ici .
Veuillez signaler un problème sur github si vous voyez des problèmes avec celui-ci. Merci.
la source
Il semble que stopUpdatingLocation soit ce qui déclenche le temporisateur du chien de garde en arrière-plan, donc je l'ai remplacé dans didUpdateLocation par:
qui semble éteindre efficacement le GPS. Le sélecteur de l'arrière-plan NSTimer devient alors:
Tout ce que je fais, c'est basculer périodiquement la précision pour obtenir une coordonnée de haute précision toutes les quelques minutes et parce que locationManager n'a pas été arrêté, backgroundTimeRemaining reste à sa valeur maximale. Cela a réduit la consommation de batterie de ~ 10% par heure (avec kCLLocationAccuracyBest constante en arrière-plan) à ~ 2% par heure sur mon appareil
la source
Il existe un cocoapod APScheduledLocationManager qui permet d'obtenir des mises à jour de l'emplacement en arrière-plan toutes les n secondes avec la précision de localisation souhaitée.
Le référentiel contient également un exemple d'application écrit en Swift 3.
la source
Dans iOS 9 et watchOS 2.0, il existe une nouvelle méthode sur CLLocationManager qui vous permet de demander l'emplacement actuel: CLLocationManager: requestLocation (). Cela se termine immédiatement, puis renvoie l'emplacement au délégué CLLocationManager.
Vous pouvez utiliser un NSTimer pour demander un emplacement toutes les minutes avec cette méthode maintenant et ne pas avoir à travailler avec les méthodes startUpdatingLocation et stopUpdatingLocation.
Toutefois, si vous souhaitez capturer des emplacements en fonction d'un changement de X mètres par rapport au dernier emplacement, définissez simplement la propriété distanceFilter de CLLocationManger et appelez X startUpdatingLocation ().
la source
Ci-joint une solution Swift basée sur:
Définir
App registers for location updates
dans info.plistGardez le gestionnaire de localisation en cours d'exécution tout le temps
Basculez
kCLLocationAccuracy
entreBestForNavigation
(pendant 5 secondes pour obtenir l'emplacement) etThreeKilometers
pour le reste de la période d'attente pour éviter l'épuisement de la batterieCet exemple met à jour l'emplacement toutes les 1 min en avant-plan et toutes les 15 minutes en arrière-plan.
L'exemple fonctionne correctement avec Xcode 6 Beta 6, exécuté sur un appareil iOS 7.
Dans le délégué d'application (mapView est une option pointant vers le contrôleur mapView)
Dans mapView (locationManager pointe vers l'objet dans AppDelegate)
la source