Passer à la navigation principale

Why Geofences Are Not Triggering on iOS

Les géofences ne déclenchent pas sur iOS dans votre Capacitor application ? Apprenez comment la surveillance de région fonctionne, les règles de permission, de rayon et de limite, et comment déboguer chaque cas.

Crédits de l'article

Martin Donadieu

Auteur

Valeria

Relecteur

Jordan

Éditeur

Pourquoi les géofences ne déclenchent pas sur iOS

Lorsque les géofences ne déclenchent pas sur iOS, la cause est presque toujours l'une de cette liste courte : l'application manque d'autorisation Always, le dispositif était déjà à l'intérieur de la région lorsque vous l'avez ajouté, le rayon est trop petit pour que iOS détecte une traversée, l'application a atteint la limite de 20 régions, ou le test n'a pas attendu longtemps. La géofencing iOS fonctionne bien, mais elle signale les traversées à son propre horaire. Cette guide explique comment la surveillance de région décide quand faire feu, et comment déboguer une application Capacitor en utilisant @capgo/background-geolocationComment la surveillance de région iOS fonctionne

Qui inclut la géofencing native sur iOS et Android.

On iOS, les zones géographiques sont CLCircularRegion des objets enregistrés avec Core Location. Une fois enregistrés, le système d'exploitation les surveille, et non votre application. Votre application peut être suspendue ou ne pas être en cours d'exécution et iOS suit toujours les régions, en utilisant une combinaison de tours cellulaires, Wi-Fi et GPS pour garder la consommation d'énergie basse.

Lorsque iOS décide que le dispositif a franchi une limite, il transmet un événement d'entrée ou de sortie à l'application, la lançant en arrière-plan si nécessaire et autorisé. Quelques règles contrôlent cette décision :

  • iOS ne signale pas le franchissement de la limite au moment où le dispositif touche la limite. La guidance d'Apple est que le dispositif doit franchir, déplacer une distance minimale au-delà de la limite, et y rester pendant au moins environ 20 secondes avant que l'événement soit transmis. Cela évite de faire feu sur le bruit GPS.
  • La précision de la localisation pour la surveillance des régions dépend de ce qui est autour des radios. Dans une ville avec un Wi-Fi dense, cela peut être rapide. Sur une route rurale, cela peut prendre des minutes.
  • Les événements ne sont que pour les transitions. Être à l'intérieur d'une région au moment où le suivi commence ne constitue pas une entrée.

Set up geofencing in a Capacitor app

Installez le plugin et configurez les clés iOS :

bun add @capgo/background-geolocation
bunx cap sync
<key>NSLocationWhenInUseUsageDescription</key>
<string>We use your location to detect when you arrive at a store.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need Always access to notify you when you arrive, even when the app is closed.</string>

Ensuite, enregistrez les régions :

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

await BackgroundGeolocation.setupGeofencing({
  url: 'https://api.example.com/v1/geofence-events',
  headers: { Authorization: 'Bearer <token>' },
  notifyOnEntry: true,
  notifyOnExit: true,
  payload: { userId: 'u-42' },
});

await BackgroundGeolocation.addGeofence({
  identifier: 'store-paris-11',
  latitude: 48.8606,
  longitude: 2.3795,
  radius: 150,
  payload: { storeId: 'paris-11' },
});

await BackgroundGeolocation.addListener('geofenceTransition', (event) => {
  console.log(`${event.transition} ${event.identifier}`, event.payload);
});

await BackgroundGeolocation.addListener('geofenceError', (event) => {
  console.error('Geofence error', event.identifier, event.code, event.message);
});

setupGeofencing demande la permission de géofencing qui est nécessaire par défaut (requestPermissions par défaut true) Sur iOS, cela signifie Toujours.

Maintenant, les modes de panne.

1. Vous n'avez pas autorisation Always.

La surveillance de la région sur iOS nécessite l'autorisation Always. Avec While Using App uniquement, vos régions ne délivreront pas d'événements lorsque l'application est en arrière-plan ou ne fonctionne pas, ce qui est tout l'intérêt d'une zone de géolocalisation.

Vérifiez avant de vous inscrire aux régions, et expliquez la demande dans votre propre interface utilisateur avant:

const status = await BackgroundGeolocation.checkPermissions();

if (status.backgroundLocation !== 'always' && status.backgroundLocation !== 'granted') {
  // Show your own screen explaining the feature, then:
  const next = await BackgroundGeolocation.requestPermissions({
    permissions: ['backgroundLocation'],
  });
  if (next.backgroundLocation === 'when_in_use' || next.backgroundLocation === 'denied') {
    await BackgroundGeolocation.openSettings();
  }
}

Notez que iOS ne montre pas le prompt d'upgrade Always immédiatement. Les utilisateurs qui ont choisi « Autoriser While Using App » ne voient que le deuxième prompt plus tard. Les utilisateurs qui ont choisi « Autoriser Une fois » obtiennent un accord temporaire qui se réinitialise. Si la géolocalisation est une fonctionnalité de base, vérifiez l'état à chaque démarrage de l'application et affichez un bandeau clair lorsque ce n'est pas Always.

2. Le dispositif était déjà à l'intérieur de la région.

Si vous ajoutez une zone de géolocalisation alors que le téléphone est à l'intérieur, iOS ne renvoie pas d'événement d'entrée. Rien n'a été franchi. Les équipes rencontrent souvent ce problème lorsqu'elles testent à leur bureau avec une région autour de l'entreprise.

Corrigez-le dans votre application : lorsque vous vous inscrivez à une région, comparez la position actuelle avec la région et gérez « déjà à l'intérieur » vous-même.

import { Geolocation } from '@capacitor/geolocation';

function distanceMeters(lat1: number, lon1: number, lat2: number, lon2: number) {
  const R = 6371000;
  const toRad = (d: number) => (d * Math.PI) / 180;
  const dLat = toRad(lat2 - lat1);
  const dLon = toRad(lon2 - lon1);
  const a =
    Math.sin(dLat / 2) ** 2 +
    Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
  return 2 * R * Math.asin(Math.sqrt(a));
}

const region = { identifier: 'store-paris-11', latitude: 48.8606, longitude: 2.3795, radius: 150 };
await BackgroundGeolocation.addGeofence(region);

const pos = await Geolocation.getCurrentPosition({ enableHighAccuracy: true });
if (distanceMeters(pos.coords.latitude, pos.coords.longitude, region.latitude, region.longitude) < region.radius) {
  handleAlreadyInside(region.identifier);
}

declare function handleAlreadyInside(id: string): void;

Pour tester un événement d'entrée, marchez ou conduisez bien au-delà du rayon, attendez, puis revenez.

3. Le rayon est trop petit.

iOS accepte des rayons petits, mais la fiabilité chute rapidement en dessous d'environ 100 mètres, car la surveillance de la région repose sur la positionnement Wi-Fi et cellulaire. Une région de 30 mètres autour d'une porte de magasin peut déclencher tard, déclencher après que le client a quitté ou ne déclencher pas du tout.

Valeurs pratiques :

Utilisation Rayon suggéré
Arrivée au magasin ou restaurant // Suggested radius
bureaux, campus, entrepôts // Store or restaurant arrival
Quartier ou zone urbaine // 100 to 200 m

If you need door level precision, combine a larger geofence with foreground location or a beacon once the user is inside. Capgo also has an // Office, campus, warehouse proche de l'intérieur.

4. Vous avez atteint la limite de 20 régions

Un appareil iOS peut surveiller au plus 20 régions à la fois. Lorsque vous ajoutez plus, l'enregistrement échoue pour les autres et vous obtenez une erreur de suivi.

Utilisez getMonitoredGeofences() pour voir ce qui est vraiment enregistré, et maintenez un ensemble roulant des régions les plus proches :

const { regions } = await BackgroundGeolocation.getMonitoredGeofences();
console.log(`Monitoring ${regions.length} regions`, regions);

Un modèle courant :

  1. Conservez votre liste complète de lieux sur le serveur.
  2. Lorsque l'application démarre, et lorsque l'utilisateur se déplace loin (par exemple, à l'entrée d'une grande « région de mise à jour » autour de l'utilisateur), récupérez les 19 lieux les plus proches.
  3. Appelez removeAllGeofences()Ajoutez ensuite les 19 régions les plus proches, ainsi qu'une grande région centrée sur l'utilisateur. C'est votre signal de rafraîchissement lorsque vous quittez cette grande région.

Android permet jusqu'à 100 géofences par application, donc code qui fonctionne sur Android peut échouer sur iOS pour cette raison seule.

5. Le test était trop court ou trop statique.

iOS reports transitions only after the device has clearly crossed and stayed on the other side. If you drive through a 150 meter region at 50 km/h, you spend about 20 seconds inside it. That may not be enough.

Lors de la mise en œuvre :

  • Restez dehors pendant une minute, puis allez à l'intérieur et restez au moins quelques minutes.
  • Testez avec le Wi-Fi activé. L'arrêt du Wi-Fi rend la surveillance des régions beaucoup moins précise, même si vous n'êtes pas connecté à un réseau.
  • N'ayez pas confiance dans le simulateur pour la chronologie. Utilisez-l’avec une trajectoire GPX dans Xcode pour vérifier vos gestionnaires, puis testez sur un appareil.

L'événement s'est déclenché, mais votre code JavaScript n'a pas été exécuté.

When iOS relaunches your app in the background for a region event, the native plugin receives it, but the Capacitor WebView may not be loaded or may be suspended again quickly. The geofenceTransition se déclenche uniquement pendant que la fenêtre WebView est active.

C'est pourquoi setupGeofencing accepte un urlLe plugin envoie la transition depuis le natif code, y compris votre fusion payload, so your backend gets it even when JavaScript never runs. Headers are persisted with the setup so they still work after a relaunch, and you can rotate them with updateHeaders().

La livraison est de meilleure qualité, sans file d'attente de réessai. Faites de l'endpoint une opération rapide et idempotente, et enregistrez chaque requête pendant les tests.

7. Location Services or Background App Refresh are off

Vérifiez ces paramètres sur le dispositif de test :

  • Paramètres, Vie privée et sécurité, Services de localisation sont activés.
  • Votre application est configurée pour toujours.
  • La localisation précise est activée pour votre application. Sans elle, les petites régions sont peu fiables.
  • Le mode économise l'énergie est désactivé pendant vos premiers tests. Il réduit l'activité en arrière-plan.

8. Redémarrage et mises à jour de l'application

iOS conserve les régions surveillées à travers les lancements d'application. Après un redémarrage du dispositif, la surveillance reprend une fois le système réactivé, mais votre application devrait toujours synchroniser à nouveau ses régions à l'ouverture : comparez getMonitoredGeofences() Réajoutez les places manquantes et faites de même après une mise à jour de l'application, ainsi que chaque fois que le serveur modifie la liste des endroits.

Sur Android, les zones géographiques sont supprimées après un redémarrage et dans quelques autres situations (localisation désactivée, données de l'application supprimées), il est donc nécessaire de les réinscrire à l'ouverture. Faire cela sur les deux plateformes simplifie la logique.

9. Fermer l'application

Si un utilisateur ferme l'application à partir du gestionnaire d'applications, iOS considère cela comme un signal fort que l'utilisateur ne veut pas l'application en cours d'exécution. Le comportement de relance de la région après un fermeture force a changé à travers les versions iOS. N'implémentez pas de fonctionnalité qui ne fonctionne que si l'application est relancée après un fermeture force, et testez-la sur les versions iOS utilisées par vos utilisateurs.

Liste de vérification de débogage

Vérifiez Comment
L'autorisation est toujours checkPermissions() renvoie always ou granted for backgroundLocation
Région enregistrée getMonitoredGeofences() La région est enregistrée
liste l'identifiant Sous 20 régions getMonitoredGeofences()
Comptez à partir de Rayon ≥ 100 mètres addGeofence appels
pas déjà à l'intérieur Comparer la position actuelle lors de l'enregistrement
Les erreurs sont enregistrées Écoutez geofenceError
Le serveur reçoit des événements Définir url in setupGeofencing et les requêtes de journal
et enregistrez les requêtes Partez complètement de la zone, attendez, revenez et restez-y

Différences Android à prendre en compte

If le même code fonctionne sur Android mais pas sur iOS, les 20 limites de région et l'exigence Always sont les raisons habituelles. Si cela fonctionne sur iOS mais pas sur Android, vérifiez que vous avez ajouté ACCESS_BACKGROUND_LOCATION à votre fichier de manifeste et défini backgroundLocation: true dans setupGeofencing. Le plugin ne vous ajoute pas cette permission, car Google Play exige une déclaration pour la localisation de fond.

Les modifications de livraison

Les chaînes de permission et la configuration native nécessitent une nouvelle build. Les listes de régions, les valeurs de rayon et les textes d'interface peuvent être modifiés côté serveur ou envoyés à travers Capgo mises à jour en directPour un suivi continu plutôt que des événements d'entrée et de sortie, voir pourquoi iOS arrête les mises à jour de localisation de fondet la documentation du plugin documentation pour la pleine API.

Mises à jour en temps réel pour les applications Capacitor

Lorsqu'un bug de la couche web est en ligne, expédiez la correction par Capgo au lieu d'attendre des jours pour l'approbation de l'app store. Les utilisateurs reçoivent la mise à jour en arrière-plan tandis que les modifications natives restent dans la voie de revue normale.

Dernières actualités de notre Blog

Capgo vous donne les meilleures informations dont vous avez besoin pour créer une application mobile vraiment professionnelle.