Comportement de l'API d'emplacement de changement significatif en cas d'arrêt / suspension?

108

Voici la section de la documentation CLLocationManager décrivant le comportement de l'application avec startMonitoringSignificantLocationChanges :

Si vous démarrez ce service et que votre application est par la suite arrêtée, le système relance automatiquement l'application en arrière-plan si un nouvel événement arrive. Dans un tel cas, le dictionnaire d'options passé à l'application: didFinishLaunchingWithOptions: méthode de votre délégué d'application contient la clé UIApplicationLaunchOptionsLocationKey pour indiquer que votre application a été lancée en raison d'un événement de localisation. Lors du redémarrage, vous devez toujours configurer un objet de gestionnaire d'emplacement et appeler cette méthode pour continuer à recevoir des événements d'emplacement. Lorsque vous redémarrez les services de localisation, l'événement en cours est remis à votre délégué immédiatement. En outre, la propriété d'emplacement de votre objet de gestionnaire d'emplacement est remplie avec l'objet d'emplacement le plus récent avant même de démarrer les services de localisation.

Donc, je crois comprendre que si votre application se termine (et je suppose que si vous n'appelez pas stopMonitoringSignificantLocationChanges depuis applicationWillTerminate ), vous serez réveillé avec un paramètre UIApplicationLaunchOptionsLocationKey à application: didFinishLaunchingWithOptions . À ce stade, vous créez votre CLLocationManager , appelez startMonitoringSignificantLocationChanges et effectuez le traitement de votre emplacement en arrière-plan pendant une durée limitée . Donc je suis d'accord avec ce morceau.

Le paragraphe précédent ne parle que de ce qui se passe lorsque l'application est arrêtée, il ne suggère pas ce que vous faites lorsque l'application est suspendue. La documentation de didFinishLaunchingWithOptions dit:

L'application suit les mises à jour d'emplacement en arrière-plan, a été purgée et a maintenant été relancée. Dans ce cas, le dictionnaire contient une clé indiquant que l'application a été relancée en raison d'un nouvel événement de localisation.

Suggérer que vous ne recevrez cet appel que lorsque votre application sera lancée (en raison d'un changement d'emplacement) après la résiliation.

Cependant, le paragraphe sur le service de changement significatif dans le Guide de programmation de la détection de l' emplacement a ce qui suit:

Si vous laissez ce service en cours d'exécution et que votre application est par la suite suspendue ou résiliée, le service réveille automatiquement votre application lorsque de nouvelles données de localisation arrivent. Au moment du réveil, votre application est mise en arrière-plan et dispose d'un peu de temps pour traiter les données de localisation. Étant donné que votre application est en arrière-plan, elle doit effectuer un travail minimal et éviter toutes les tâches (telles que l'interrogation du réseau) qui pourraient l'empêcher de revenir avant l'expiration du délai alloué. Si ce n'est pas le cas, votre application peut être résiliée.

Cela suggère que vous êtes réveillé avec des données de localisation si votre application a été suspendue, mais ne mentionne pas comment vous vous êtes réveillé:

  • Le UIApplicationDelegate obtenir un rappel en me disant que je reprends à partir d' un état suspendu dans un état d'arrière - plan?
  • Le gestionnaire d'emplacement (qui a été lyophilisé lorsque l'application a été suspendue) commence-t-il à recevoir des rappels locationManager: didUpdateToLocation: fromLocation ?
  • Dois-je simplement implémenter du code dans mon message didUpdateToLocation qui vérifie l'état de l'application et effectue un traitement minimal en mode arrière-plan?

En rédigeant ceci, je pense que je viens de répondre à ma propre question, mais ce serait formidable que ma compréhension de cela soit confirmée par quelqu'un de plus compétent.

RougeBlueThing
la source

Réponses:

80

Depuis que j'ai posé cette question, j'ai fait pas mal de tests (principalement dans le train entre la maison et le travail) et j'ai confirmé que le comportement des applications suspendues était celui que je soupçonnais à la fin de la question.

Autrement dit, votre application suspendue est réveillée, vous ne recevez aucun rappel sur votre délégué d'application, mais vous recevez les mises à jour de votre emplacement via votre CLLocationManagerDelegate existant . Vous pouvez détecter que vous exécutez en arrière-plan en vérifiant l' applicationState et effectuer un travail limité dans le cas où vous êtes réveillé d'un état suspendu pour effectuer le traitement de l'emplacement.

[UIApplication sharedApplication].applicationState == UIApplicationStateBackground

Je suis arrivé à cette conclusion avec un harnais de test de localisation que vous êtes invité à télécharger et à essayer. C'est une application assez simple qui vous permet d'activer des modifications significatives et des API de modification GPS via l'interface utilisateur et de consigner toutes les réponses que vous obtenez.

NB Le point six de la réponse précédente n'est pas correct. Les applications suspendues lyophilisées reçoivent des rappels CLLocationManagerDelegate lorsqu'elles sont réveillées à partir d'un état suspendu.

RougeBlueThing
la source
1
Biffé # 6 dans ma réponse pour ne pas confondre les gens.
Aaron
Ironiquement, j'ai également ressenti la même confusion lors de l'élaboration du changement significatif. J'ai encore des doutes sur ce qui se passe si l'application est fermée. le rappel UIApplicationDelegate ne se produira-t-il pas? est-ce la bonne façon de démarrer l'application. si le gestionnaire d'emplacement n'a pas encore été déclenché, comment peut-il obtenir les notifications en arrière-plan? (il est temps pour un peu plus de R&D)
darshansonde
Merci beaucoup pour l'exemple d'application, cela m'a été très utile. J'ai une question: que se passerait-il si j'utilisais le service de localisation standard en arrière-plan, et non le service important, l'application sera-t-elle également relancée après la résiliation dans ce cas? J'ai posé cette question ici en détail, je serais heureux si vous pouviez
m'éclaircir
2
Non travaillé sur ios7 stackoverflow.com/questions/18946881/…
Igor
Savez-vous combien de temps il a fallu pour que votre application soit résiliée? Et puis obtenir un rappel appDelegate à la place? (Est-ce comme 30 minutes? 2 heures? 5 heures?) La raison pour laquelle je pose cette question est que j'ai mis en place une région à surveiller. J'ai essayé plusieurs fois de voir mon application se lancer, mais seulement une fois que j'ai pu la relancer. Les autres fois, le didExitRegionrappel, mais je n'ai pas pu le faire à startLocationUpdatespartir de là car ce n'était pas par le lancement de l'application ...
Chérie
25

Ma compréhension est la suivante (je suis en train d'écrire une application qui repose sur cette API, mais je n'ai pas suffisamment terminé ce composant pour commencer les tests):

  1. Votre application est exécutée pour la première fois, vous vous inscrivez à startMonitoringSignificantLocationChanges et fournissez une fonction de rappel. Pendant que votre application est en cours d'exécution, elle appellera ce rappel chaque fois qu'elle recevra un changement significatif.
  2. Si votre application est mise en arrière-plan, UIApplication recevra applicationWillResignActive , suivi de applicationDidEnterBackground .
  3. Si votre application est supprimée alors qu'elle est suspendue en arrière-plan, vous ne serez pas averti; cependant, si votre application est tuée pendant son exécution (premier plan ou arrière-plan à ma connaissance), vous obtiendrez un moment avec applicationWillTerminate . Vous ne pouvez pas demander de temps d'arrière-plan supplémentaire à partir de cette fonction.
  4. Bien qu'il ait été tué en arrière-plan, le système d'exploitation relancera votre application. Si votre application est simplement lancée par l'OS pour un changement, vous recevrez un appel à l' application didFinishLaunchingWithOptions :

    if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey])

    vous aidera à déterminer si vous êtes revenu d'un changement d'emplacement en arrière-plan.

  5. Si, à la place, vous exécutiez actuellement en arrière-plan et que votre application est relancée manuellement par l'utilisateur, vous recevrez une applicationWillEnterForeground suivie de applicationDidBecomeActive .
  6. Indépendamment de la façon dont cela s'est produit, lorsque votre application est relancée (à moins qu'elle ne soit toujours en cours d'exécution en arrière-plan à la suite d'une tâche en arrière-plan et que ladite tâche ait commencé à surveiller les modifications), vous devez lui dire explicitement de recommencer à démarrerMonitoringSignificantLocationChanges car le rappel est non plus attaché après "lyophilisation". Et oui, il vous suffit d'implémenter du code dans didUpdateToLocation une fois que vous avez réattaché un gestionnaire d'emplacement d'une sorte une fois revenu de l'état suspendu.

C'est ce que je fais actuellement avec mon développement de code. Comme je l'ai déjà mentionné, je ne suis pas tout à fait prêt à tester cela sur un appareil, donc je ne peux pas dire si j'ai tout interprété correctement, alors commentateurs, n'hésitez pas à me corriger (même si j'ai fait des lectures substantielles sur le sujet).

Oh, et si par malchance, vous sortez une application qui fait ce que je veux que la mienne fasse, je pourrais pleurer :)

Bonne chance!

Aaron
la source
1
@Tegeril +1 Merci pour la réponse. Je commençais à entendre des grillons sur celui-ci. :) Je suis surpris que les applications qui ont commencé à être suspendues doivent rappeler startMonitoringSignificantLocationChanges. Avez-vous un lien vers le doco où cela est décrit? Je crois comprendre que le chargement à partir d'un état suspendu instanciera tous vos objets tels qu'ils étaient lorsque l'application a été suspendue. Je m'attends donc à ce que la demande de modification importante soit en vigueur.
RedBlueThing
Vous en parlez peut-être? "Lors du redémarrage, vous devez toujours configurer un objet de gestionnaire d'emplacement et appeler cette méthode pour continuer à recevoir des événements d'emplacement" Mais je pense que cela fait référence au cas où votre application a été lancée à partir d'un état terminé (par un événement d'emplacement). C'est essentiellement la racine de ma question, «que se passe-t-il pour le cas suspendu?».
RedBlueThing
Morgan Grainger sur les forums de développement a suggéré ceci: «Vous devez créer un CLLocationManager, définir un délégué et appeler startMonitoringSignificantLocationChanges lorsque votre application est lancée, sinon Core Location n'aura nulle part où fournir les mises à jour.» dans le contexte du redémarrage d'une application indépendamment d'un état terminé ou suspendu. De "l'application a été relancée après startMonitoringSignificantLocationChanges et maintenant quoi?"
Aaron
Je suis d'accord que cela pourrait encore être vague même dans le contexte de ce message sur le forum (l'affiche parlait de réveil depuis l'arrière-plan, mais Morgan a utilisé le redémarrage plus général d'une application). Je pense toujours que vous devez appeler à nouveau pour surveiller le redémarrage de votre application si vous souhaitez travailler avec la fonction de changements importants. Si vous souhaitez plutôt lancer une tâche d'arrière-plan et mettre à jour avec le service de localisation standard et la fonctionnalité GPS, c'est une option alternative. Je ne pense pas que vous deviez vous réinscrire à chaque lancement avec des changements significatifs pour pouvoir être relancé.
Aaron
1
Je suis heureux que quelque chose de définitif en soit sorti, devrait m'aider à l'avenir :)
Aaron
1

Si l'application est évoquée de l'état suspendu à la suite d'un changement d'emplacement, l'application se lancera en arrière-plan.

Tous les objets seront en direct et vous recevrez une mise à jour de l'emplacement dans le délégué existant.

Anshu
la source