Quando i geofence non si attivano su iOS, la causa è quasi sempre una delle seguenti: l'app non ha l'autorizzazione 'Sempre', il dispositivo era già all'interno della regione quando l'hai aggiunta, il raggio è troppo piccolo per iOS per rilevare un attraversamento, l'app ha raggiunto il limite di 20 regioni, o il test non ha aspettato abbastanza tempo. Il geofencing di iOS funziona bene, ma riferisce gli attraversamenti secondo il suo orario. Questa guida spiega come il monitoraggio delle regioni decide quando attivare e come debuggare un'app Capacitor utilizzando @capgo/background-geolocationche include il geofencing nativo su iOS e Android.
Come funziona il monitoraggio delle regioni di iOS
On iOS, i geofence sono CLCircularRegion gli oggetti registrati con Core Location. Una volta registrati, il sistema operativo li monitora, non il tuo app. Il tuo app può essere sospesa o non in esecuzione e iOS ancora traccia le regioni, utilizzando una combinazione di torri cellulari, Wi-Fi e GPS per mantenere basso il consumo di batteria.
Quando iOS decide che il dispositivo ha attraversato una frontiera, invia un evento di ingresso o uscita all'app, lanciandola in background se necessario e consentito. Un paio di regole controllano quella decisione:
- iOS non segnala il passaggio nel momento in cui il dispositivo tocca la frontiera. La guida di Apple è che il dispositivo debba attraversare, muoversi con una distanza minima oltre la frontiera e rimanere lì per almeno circa 20 secondi prima che l'evento sia inviato. Ciò evita di far partire su jitter GPS.
- La precisione della posizione per la monitoraggio delle regioni dipende da cosa ci sono intorno. In una città con Wi-Fi denso, può essere veloce. Su una strada rurale, può richiedere minuti.
- Gli eventi sono solo per le transizioni. Essere all'interno di una regione quando si inizia a monitorare non conta come un ingresso.
Configura il geofencing in un app Capacitor
Installa il plugin e configura le chiavi 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>
Poi registra le regioni:
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 chiede il permesso di geofencing che serve di default (requestPermissions predefinito a true) Su iOS significa Sempre.
Ora, i modi di fallimento.
1. Non hai autorizzazione Always.
La monitoraggio delle regioni su iOS richiede autorizzazione Always. Con While Using App solo, le tue regioni non invieranno eventi quando l'app è in background o non è in esecuzione, il che è proprio il punto di un geofence.
Controlla prima di registrare le regioni, e spiega la richiesta nella tua UI prima:
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();
}
}
Nota che iOS non mostra immediatamente la richiesta di autorizzazione Always. Gli utenti che hanno scelto “Consenti While Using App” possono vedere la seconda richiesta solo in seguito. Gli utenti che hanno scelto “Consenti una volta” ottengono un'autorizzazione temporanea che si resetta. Se la geofenizzazione è una funzionalità principale, controlla lo stato all'avvio dell'app e mostra un banner chiaro quando non è Always.
2. Il dispositivo era già all'interno della regione
Se aggiungi un geofence mentre il telefono è all'interno di esso, iOS non invia un evento di ingresso. Nulla è stato attraversato. Le squadre colpiscono questo costantemente quando testano al loro tavolo con una regione intorno all'ufficio.
Risolvi in app: quando registrate una regione, confrontate la posizione corrente con la regione e gestite “già all'interno” da voi stessi.
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;
Per testare un evento di ingresso, cammina o guida fuori bene oltre il raggio, aspetta, poi torna.
3. Il raggio è troppo piccolo
iOS accetta piccoli raggi, ma la affidabilità diminuisce rapidamente sotto circa 100 metri, perché il monitoraggio delle regioni si appoggia su Wi-Fi e posizionamento cellulare. Una regione di 30 metri intorno a una porta di negozio può scattare in ritardo, scattare dopo che il cliente ha lasciato, o non scattare affatto.
Valori pratici:
| Utilizzo | Suggerito raggio |
|---|---|
| Arrivo in negozio o ristorante | 100 a 200 m |
| Ufficio, campus, magazzino | 150 a 300 m |
| Zona di quartiere o città | 500 m e oltre |
Se hai bisogno di precisione di livello di porta, combina un geofence più grande con la posizione in primo piano o un beacon una volta che l'utente è all'interno. Capgo ha anche un plugin iBeacon per la prossimità indoor.
4. Hai superato il limite di 20 regioni
Un'app iOS può monitorare al massimo 20 regioni contemporaneamente. Quando ne aggiungi di più, la registrazione fallisce per le extra e ottieni un errore di monitoraggio.
Usa getMonitoredGeofences() per vedere cosa è veramente registrato, e conserva un set rotante delle regioni più vicine:
const { regions } = await BackgroundGeolocation.getMonitoredGeofences();
console.log(`Monitoring ${regions.length} regions`, regions);
Un modello comune:
- Tieni la tua lista completa di luoghi sul server.
- Quando l'app inizia, e quando l'utente si sposta molto (ad esempio all'uscita di una grande “ricarica” regione intorno all'utente), recupera i 19 luoghi più vicini.
- Chiama
removeAllGeofences()poi aggiungi i 19 luoghi più vicini più una grande regione centrata sull'utente. Uscendo da quella grande regione è il tuo segnale per ricaricare.
Android consente fino a 100 geofence per app, quindi code che funziona su Android può fallire su iOS per questo motivo solo.
5. Il test era troppo breve o troppo statico
iOS segnala le transizioni solo dopo che il dispositivo ha chiaramente attraversato e rimasto sull'altra sponda. Se guidi attraverso una regione di 150 metri a 50 km/h, trascorri circa 20 secondi all'interno di essa. Ciò potrebbe non essere sufficiente.
Quando si testa:
- Resta fuori per un minuto, poi entra e resta almeno per un paio di minuti.
- Testa con Wi-Fi attivato. Spegnere Wi-Fi rende la monitorizzazione delle regioni molto meno precisa, anche se non sei collegato a nessuna rete.
- Non affidarti al simulatore per il timing. Utilizzalo con una rotta GPX in Xcode per verificare i tuoi gestori, poi testa su un dispositivo.
6. L'evento è stato attivato, ma il tuo JavaScript non è stato eseguito.
Quando iOS riavvia l'applicazione in background per un evento di regione, il plugin nativo lo riceve, ma il WebView Capacitor potrebbe non essere caricato o potrebbe essere sospeso nuovamente velocemente. Il geofenceTransition listener si attiva solo mentre il WebView è attivo.
È per questo motivo setupGeofencing accetta un url. Il plugin invia la transizione dal nativo code, compresi i tuoi dati combinati payload, quindi il tuo backend li riceve anche quando il JavaScript non viene eseguito. I header persistono con la configurazione quindi funzionano ancora dopo un riavvio, e puoi ruotarli con updateHeaders().
La consegna è a sforzo massimo, senza coda di riprovazione. Assicurati che l'endpoint sia veloce e idempotente, e registra ogni richiesta durante le prove.
I Servizi di Localizzazione o la sincronizzazione di background sono disabilitati
Controlla questi sul dispositivo di test:
- Impostazioni, Privacy & Sicurezza, Servizi di localizzazione sono abilitati.
- La tua app è impostata su 'Sempre'.
- La posizione esatta è abilitata per la tua app. Senza di essa, le piccole aree sono poco affidabili.
- La modalità basso consumo è disabilitata durante i tuoi primi test. Riduce l'attività di background.
8. Riavvio e aggiornamenti dell'app
iOS mantiene le regioni monitorate anche dopo il riavvio dell'app. Dopo un riavvio del dispositivo, il monitoraggio riprende una volta che il sistema è tornato in funzione, ma la tua app dovrebbe ancora sincronizzare le regioni al lancio: confronta getMonitoredGeofences() con ciò che ti aspetti e aggiungi nuovamente quelli mancanti. Fai lo stesso dopo un aggiornamento dell'app e ogni volta che il server modifica l'elenco dei luoghi.
Sui dispositivi Android, i geofencidi vengono eliminati dopo un riavvio e in alcune altre situazioni (localizzazione disabilitata, dati dell'app cancellati), quindi è necessario reregistrare al lancio comunque. Fatto su entrambe le piattaforme mantiene la logica semplice.
9. Forza l'uscita dell'app
Se un utente forza l'uscita dell'app dall'applicazione di gestione delle applicazioni, iOS considera questo un segnale forte che l'utente non vuole l'app in esecuzione. Il comportamento di riavvio delle regioni dopo un forzato uscita dell'app è cambiato attraverso le versioni di iOS. Non costruisci una funzionalità che funzioni solo se l'app viene riavviata dopo un forzato uscita dell'app e testala sulle versioni di iOS utilizzate dai tuoi utenti.
Elenco di controllo di debug
| Controlla | Come |
|---|---|
| L'accesso è sempre | checkPermissions() ritorna always o granted per backgroundLocation |
| L'accesso è sempre | getMonitoredGeofences() elencare l'identificatore |
| Sotto le 20 regioni | per getMonitoredGeofences() |
| Registra la regione | Rivista i addGeofence chiamate |
| Non già all'interno | Confronta la posizione corrente alla registrazione |
| Gli errori vengono registrati | Ascolta geofenceError |
| Il backend riceve gli eventi | Imposta url in setupGeofencing e registra le richieste |
| e registra le richieste | Lascia completamente la regione, attendi, torna e rimani |
Differenze Android da considerare
If il medesimo code funziona su Android ma non su iOS, i 20 limiti di regione e l'obbligo di sempre sono le ragioni più comuni. Se funziona su iOS ma non su Android, controlla di aver aggiunto ACCESS_BACKGROUND_LOCATION al tuo manifesto e impostato backgroundLocation: true in setupGeofencing. Il plugin non aggiunge quella autorizzazione per te, perché Google Play richiede una dichiarazione per la localizzazione di background.
Modifiche di shipping
I geolocalizzazioni e le stringhe di autorizzazione native richiedono una nuova compilazione. Le liste delle regioni, i valori dei raggi e il testo utente possono essere modificati sul server o inviati tramite Capgo aggiornamenti livePer il tracciamento continuo anziché gli eventi di ingresso e uscita, vedere why iOS stops background location updates. Per il tracciamento continuo piuttosto che gli eventi di ingresso e uscita, vedi documentation per il full API.