Aller au contenu principal

Pourquoi iOS arrête la localisation en arrière-plan

Pourquoi iOS interrompt les mises à jour de localisation en arrière-plan dans les apps Capacitor : suspension, modes background, autorisation, pause automatique, précision et comment corriger chaque cause.

Illustration d’une application iPhone exécutant des tâches en arrière-plan tout en suivant la localisation

iOS arrête les mises à jour de localisation en arrière-plan parce qu'il suspend votre app, et non parce que Core Location échoue. À moins que l'app ne déclare le mode background location, n'active les mises à jour en arrière-plan sur son CLLocationManager, et ne les démarre pendant qu'elle est encore au premier plan, iOS gèle le processus quelques secondes après que l'utilisateur a quitté l'app et met en file d'attente ou abandonne les positions. Ce guide recense chaque cause que nous observons dans les apps Capacitor, avec la solution pour chacune, et montre comment @capgo/background-geolocation handles them.

Comment iOS gère une application en arrière-plan

Lorsqu'un utilisateur swipe vers l'écran d'accueil ou verrouille son téléphone, iOS accorde une courte fenêtre à l'application, puis la suspend. Une application suspendue ne dispose plus de temps CPU. Pour une application Capacitor, cela signifie que le côté natif et la WebView cessent de tourner, et votre callback JavaScript cesse lui aussi de s'exécuter.

Apple fait une exception pour les applications qui utilisent activement la localisation. Si l'application est configurée pour la localisation en arrière-plan et qu'une session de localisation active a été démarrée au premier plan, iOS la maintient en cours d'exécution et continue de fournir les mises à jour. Tout ce qui suit porte sur le respect de ce contrat, et sur les cas où le système le rompt délibérément.

Cause 1 : le mode arrière-plan de localisation est absent

Sans location dans UIBackgroundModes, aucun code ne suffira à maintenir le flux de mises à jour. Ajoutez-l’à ios/App/App/Info.plist:

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

Vous pouvez aussi l'activer dans Xcode sous Signing & Capabilities, Background Modes, Location updates. C'est une clé plist, pas un entitlement : aucun changement de profil de provisionnement n'est nécessaire.

La propriété native correspondante est allowsBackgroundLocationUpdates. La définir sur true sans le mode arrière-plan dans le plist fait planter l'application. Le plugin Capgo la définit pour vous lorsque vous passez backgroundMessage vers start(), la clé plist doit donc être présente avant de publier.

L’App Review vérifie que le mode arrière-plan est justifié. Expliquez dans les notes de review quelle fonctionnalité l’utilise, et assurez-vous que la fonctionnalité est visible pour le reviewer.

Cause 2 : les mises à jour ont été lancées en arrière-plan

Règle d’Apple : les mises à jour en arrière-plan continuent si elles ont été démarrées pendant que l’application était au premier plan. Tenter de démarrer une session à partir d’une notification push silencieuse, d’un background fetch ou d’une BGTaskScheduler tâche ne fonctionne pas pour les mises à jour de localisation standard.

Start tracking from a user action or on app resume:

import { App } from '@capacitor/app';
import { BackgroundGeolocation } from '@capgo/background-geolocation';

let tracking = false;

export async function startTracking() {
  if (tracking) return;
  tracking = true;
  await BackgroundGeolocation.start(
    {
      backgroundMessage: 'Recording your route',
      backgroundTitle: 'Route recording',
      requestPermissions: true,
      distanceFilter: 10,
      url: 'https://api.example.com/v1/points',
    },
    (location, error) => {
      if (error) return console.error(error);
      if (location) console.log(location.latitude, location.longitude);
    },
  );
}

// Re-arm when the user comes back, if the session should be active
App.addListener('appStateChange', ({ isActive }) => {
  if (isActive && shouldBeTracking()) startTracking();
});

declare function shouldBeTracking(): boolean;

Cause 3 : backgroundMessage n’a pas été transmis

C’est spécifique au plugin Capgo et c’est le rapport de bug le plus courant. Si backgroundMessage est undefined, le plugin configure le gestionnaire de localisation pour un usage en premier plan uniquement : allowsBackgroundLocationUpdates reste false et les mises à jour s’arrêtent lorsque l’application est suspendue. Passez un message sur les deux plateformes. Sur Android, il devient aussi le texte de la notification du service de premier plan.

Cause 4 : niveau d’autorisation incorrect, ou « Autoriser une fois »

De nombreux développeurs pensent qu’ils ont besoin de « Toujours » pour suivre en arrière-plan. Ce n’est pas le cas. Apple indique qu’une app avec l’autorisation « Lors de l’utilisation » continue de tourner en arrière-plan tant qu’elle a des services de localisation actifs, à condition que les mises à jour en arrière-plan soient activées.

Toujours utile pour autre chose : relancer une app terminée. Seuls le monitoring de région, les changements significatifs de localisation et les visites peuvent relancer une app, et uniquement avec Always.

Deux choix de l’utilisateur cassent discrètement le suivi en arrière-plan :

  • Autoriser une fois. Il s’agit d’une autorisation temporaire « Lors de l’utilisation » qui expire quand l’app n’est plus utilisée. La session suivante repart de « non déterminé ».
  • Pendant l'utilisation, puis Toujours : l'invite n'apparaît jamais. Lorsque vous demandez Always, iOS peut afficher la demande de mise à niveau plus tard, à un moment qu’il choisit, souvent lorsque l’app n’est pas à l’écran.

Vérifiez l’état réel avant de démarrer une session :

import { BackgroundGeolocation } from '@capgo/background-geolocation';

const status = await BackgroundGeolocation.checkPermissions();

if (status.location !== 'granted') {
  await BackgroundGeolocation.requestPermissions({ permissions: ['location'] });
}

if (status.backgroundLocation === 'when_in_use') {
  // Background tracking still works for standard updates.
  // Explain why Always helps if you also rely on geofences.
}

Sur iOS, backgroundLocation renvoie when_in_use ou granted / always, afin d’afficher la bonne explication au lieu de deviner.

Cause 5 : Core Location met automatiquement les mises à jour en pause

CLLocationManager.pausesLocationUpdatesAutomatically par défaut sur true. Quand iOS estime que l’utilisateur ne bouge pas, il met en pause les mises à jour pour économiser la batterie. Pour une app When In Use, cette pause met fin à l’accès à la localisation jusqu’à ce que l’app soit relancée, et Core Location ne reprend pas de lui-même.

Le plugin Capgo définit pausesLocationUpdatesAutomatically = false dans son code natif, donc ce point est géré. Si vous écrivez votre propre code natif, ou utilisez un autre plugin, vérifiez d’abord cette propriété.

Cause 6 : l’appareil est immobile et le filtre est large

Avec un distanceFilter de 50 mètres, un téléphone posé sur un bureau ne génère aucune mise à jour. Cela ressemble à un « suivi arrêté » dans vos logs, mais c’est le comportement prévu.

  • Si vous avez besoin de heartbeats à l’arrêt, utilisez une valeur faible ou nulle distanceFilter.
  • Utiliser minIntervalMs pour limiter la fréquence des POST natifs, plutôt qu’un filtre de distance élevé.
await BackgroundGeolocation.start(
  {
    backgroundMessage: 'Vehicle tracking active',
    distanceFilter: 0,
    minIntervalMs: 120_000, // at most one native POST every 2 minutes
    url: 'https://api.example.com/v1/vehicle-points',
  },
  () => {},
);

Cause 7 : la localisation précise est désactivée

Depuis iOS 14, les utilisateurs peuvent désactiver la localisation précise pour votre application. Vous recevez toujours des mises à jour, mais approximatives (plusieurs kilomètres) et beaucoup moins fréquentes. Détectez cela dans vos données (grandes accuracy valeurs) et expliquez à l’utilisateur pourquoi la localisation précise est essentielle pour votre fonctionnalité. Si vous déployez une application de livraison ou de fitness, présentez-le lors de l’onboarding, pas après un trajet raté.

Cause 8 : l’utilisateur a fermé l’application

Si l’utilisateur ferme l’application via le sélecteur d’applications, iOS arrête les mises à jour de localisation standard. Aucun plugin ne peut les maintenir. C’est une surprise courante pour les équipes venant d’Android, où un service en premier plan peut continuer à tourner après la suppression de la tâche.

Options :

  • Tell users not to force quit during a session. Most fleet apps do this in onboarding.
  • Ajoutez des géorepères avec l’autorisation « Toujours » autour des lieux importants pour que iOS puisse relancer l’application en arrière-plan à l’entrée ou à la sortie.
  • Envoyez une notification push pour rappeler à l’utilisateur de rouvrir l’application lorsque votre serveur cesse de recevoir des points pour une session.

Cause 9 : JavaScript ne s’exécute pas, même si le natif fonctionne

Un point subtil. Le code natif peut recevoir une localisation alors que le WebView est suspendu, ou qu’il est toujours actif mais ne traite pas rapidement les timers ou les appels réseau. Si vous envoyez des points avec fetch depuis le callback, ils peuvent arriver en retard ou ne pas arriver du tout.

Utilisez l’option url du plugin. Chaque point est POSTé depuis le code natif avec le même JSON que le Location tapez plus "source": "native", indépendamment de la WebView. Réservez le callback uniquement aux mises à jour de l’interface. La livraison est « best effort » sans file d’attente sur disque : si vous ne pouvez pas perdre un point, enregistrez-l’aussi localement lors du déclenchement du callback et réconciliez plus tard.

For background work beyond location, read how background tasks work in Capacitor et consultez @capgo/capacitor-background-task.

Cause 10 : mode Économie d’énergie et état thermique

Le mode Économie d’énergie réduit l’activité en arrière-plan sur tout le système. La localisation fonctionne toujours, mais d’autres éléments dont votre session dépend (nouvelles tentatives réseau, actualisation en arrière-plan) sont ralentis. Testez avec le mode Économie d’énergie activé avant de valider une release.

L’indicateur bleu

Lorsqu’une app disposant de l’autorisation « Lors de l’utilisation » utilise la localisation en arrière-plan, iOS affiche une pastille bleue dans la barre d’état. Le plugin Capgo définit showsBackgroundLocationIndicator vers true pour les sessions en arrière-plan, ce que les utilisateurs attendent et ce que les reviewers vérifient. Ne cherchez pas à le masquer, ils lui font confiance.

Un plan de test pour détecter ces bugs

Le test sur simulateur ne suffit pas pour la localisation en arrière-plan. Utilisez un vrai iPhone et :

  1. Compilez en configuration release, pas seulement en debug. Les builds debug lancés depuis Xcode ont un traitement du cycle de vie différent.
  2. Démarrez une session au premier plan, verrouillez le téléphone, puis marchez ou conduisez pendant 20 minutes.
  3. Répétez avec « Autoriser une fois », localisation précise désactivée, mode Économie d’énergie activé.
  4. Vérifiez les logs de votre serveur pour source: "native" points, pas seulement votre log in-app.
  5. Force quittez l’application pendant une session et vérifiez qu’elle explique ce qui s’est passé au prochain lancement.

Si vous avez besoin d’un UDID d’appareil pour des builds ad hoc, le Recherche d'UDID iOS le récupère depuis Safari. Si vous n’avez pas de Mac avec Xcode 26 pour les builds, Build Capgo peut générer des builds iOS signés dans le cloud.

Checklist de dépannage

Symptôme Cause probable Corriger
Arrête quelques secondes après le verrouillage Non location mode arrière-plan ou non backgroundMessage Ajoutez la clé plist et validez backgroundMessage
Crash au démarrage allowsBackgroundLocationUpdates sans mode arrière-plan Ajoutez UIBackgroundModes → location
Fonctionne une fois, puis plus du tout L'utilisateur a choisi « Autoriser une fois » Expliquez et redemandez, ou redirigez vers openSettings()
S'arrête une fois stationné Grand distanceFilter Réduisez-le, utilisez minIntervalMs
Points éloignés, faible précision Localisation précise désactivée Demander à l'utilisateur de l'activer
Arrêt après balayage L'utilisateur a fermé l'application Expected on iOS, use geofences for relaunch
Le natif reçoit les points, le serveur non JavaScript fetch dans le callback Utilisez le url option

Publier des correctifs

La plupart de ces correctifs modifient Info.plist ou la configuration native, ce qui nécessite un nouveau build App Store. Les parties JavaScript, comme les explications des permissions, les textes d'onboarding et la logique de retry, peuvent être déployées auprès des utilisateurs existants avec les live updates Capgo une fois le build natif publié.

Si vous hésitez entre plusieurs plugins, notre comparatif de Transistorsoft et du plugin gratuit Capgo détaille les compromis.

Live updates pour les apps Capacitor

Lorsqu'un bug de la couche web est en ligne, déployez le correctif via Capgo au lieu d'attendre des jours l'approbation des stores. Les utilisateurs reçoivent la mise à jour en arrière-plan, tandis que les changements natifs suivent le circuit de validation habituel.

Les derniers articles du blog

Capgo vous offre les meilleures informations pour créer une application mobile vraiment professionnelle.