Configurare un recinto virtuale

Un Geofence definisce un confine geografico circolare intorno a un punto di interesse. L'app riceve notifiche quando l'utente entra o esce dal limite. Le geofence sono utili per promemoria, avvisi, check-in e fornitura di contenuti contestuali basati sulla posizione.

Questo articolo illustra come creare un recinto virtuale, monitorare le modifiche dello stato e gestire gli eventi di recinto virtuale in un'app SDK per app di Windows (WinUI 3).

Prerequisiti

  • Un progetto WinUI 3 creato dal modello App vuota, con pacchetto (WinUI 3 su Desktop).
  • La funzionalità Location dichiarata nel manifesto del pacchetto. Per istruzioni, vedere Ottenere la posizione dell'utente .

Richiedere l'accesso alla posizione

Chiamare Geolocator.RequestAccessAsync prima di creare o monitorare i recinti virtuali.

using Windows.Devices.Geolocation;
using Windows.Devices.Geolocation.Geofencing;

var accessStatus = await Geolocator.RequestAccessAsync();
if (accessStatus != GeolocationAccessStatus.Allowed)
{
    StatusText.Text = "Location access is required for geofencing.";
    return;
}

Creare un geofence

Definire un'area geografica virtuale specificando un identificatore, un centro geografico, un raggio in metri e quali transizioni di stato monitorare (ingresso, uscita o rimozione).

var position = new BasicGeoposition
{
    Latitude = 47.6062,
    Longitude = -122.3321
};

var geocircle = new Geocircle(position, 200); // 200-meter radius

var geofence = new Geofence(
    "SeattleDowntown",                          // Unique identifier
    geocircle,                                  // Geographic boundary
    MonitoredGeofenceStates.Entered |           // States to monitor
    MonitoredGeofenceStates.Exited,
    false,                                      // Single use: false = persistent
    TimeSpan.FromSeconds(10)                    // Dwell time before triggering
);

GeofenceMonitor.Current.Geofences.Add(geofence);

Parametri del geofence

Parametro Description
id Stringa univoca che identifica il recinto virtuale. Usa questo per distinguere gli eventi provenienti da geofence diverse.
geoshape Circuito geografico che definisce il limite. Sono supportati solo i limiti circolari.
monitoredStates Quali transizioni monitorare: Entered, Exited o Removed. Combinare con l'operatore | .
singleUse Se true, il geofence si attiva una sola volta e viene rimosso automaticamente.
dwellTime Per quanto tempo l'utente deve rimanere all'interno (o all'esterno) del limite prima che venga generato l'evento. Aiuta a filtrare i brevi incroci.

Monitora gli eventi geofence in primo piano

Sottoscrivere l'evento GeofenceMonitor.Current.GeofenceStateChanged per ricevere notifiche durante l'esecuzione dell'app.

GeofenceMonitor.Current.GeofenceStateChanged += OnGeofenceStateChanged;

Leggere i report e aggiornare l'interfaccia utente. L'evento viene generato su un thread in background, quindi usare DispatcherQueue per effettuare il marshalling degli aggiornamenti dell'interfaccia utente.

private void OnGeofenceStateChanged(GeofenceMonitor sender, object args)
{
    var reports = sender.ReadReports();

    DispatcherQueue.TryEnqueue(() =>
    {
        foreach (var report in reports)
        {
            var state = report.NewState;
            var id = report.Geofence.Id;

            switch (state)
            {
                case GeofenceState.Entered:
                    StatusText.Text = $"Entered geofence: {id}";
                    break;
                case GeofenceState.Exited:
                    StatusText.Text = $"Exited geofence: {id}";
                    break;
                case GeofenceState.Removed:
                    StatusText.Text = $"Geofence removed: {id}";
                    // Re-add the geofence if it was removed due to expiration
                    break;
            }
        }
    });
}

Monitora i cambiamenti di stato del geofence

Usa GeofenceMonitor.Current.StatusChanged per rilevare quando il monitoraggio del geofence viene disabilitato — ad esempio, quando l'utente disattiva i servizi di posizione.

GeofenceMonitor.Current.StatusChanged += (sender, args) =>
{
    DispatcherQueue.TryEnqueue(() =>
    {
        var status = sender.Status;
        if (status == GeofenceMonitorStatus.Disabled)
        {
            StatusText.Text = "Geofence monitoring is disabled. Check location settings.";
        }
    });
};

Tip

Quando si usano recinti virtuali, monitorare le modifiche delle autorizzazioni tramite GeofenceMonitor.StatusChanged anziché Geolocator.StatusChanged. Un valore GeofenceMonitorStatus di Disabled equivale a un valore PositionStatus di Disabled, ma GeofenceMonitorStatus fornisce un contesto più ampio per gli scenari di geofencing.

Rimuovere un recinto virtuale

Rimuovi un geofence individuandolo nella raccolta GeofenceMonitor.Current.Geofences.

var geofences = GeofenceMonitor.Current.Geofences;
var target = geofences.FirstOrDefault(g => g.Id == "SeattleDowntown");

if (target != null)
{
    geofences.Remove(target);
}

Procedure consigliate

  • Impostare un tempo di attesa ragionevole. Un tempo di attesa di almeno 10 secondi aiuta a filtrare il jitter GPS e impedisce falsi trigger ai bordi limite.
  • Utilizzare un raggio di almeno 50 metri. L'accuratezza GPS varia in base al dispositivo e all'ambiente. Un raggio inferiore a 50 metri può produrre risultati inaffidabili.
  • Controllare l'accesso a Internet, se necessario. Se l'app esegue operazioni di rete quando viene generato un evento di recinto virtuale ,ad esempio l'invio di una notifica a un server, verificare la connettività prima di creare il recinto virtuale.
  • Gestisci lo stato Removed. Le geofence possono essere rimosse dal sistema se scadono o se il sistema si trova in condizioni di carenza di risorse. Verificare la presenza di GeofenceState.Removed e ricreare il geofence se lo scenario lo richiede.
  • Non monitorare il primo piano e lo sfondo contemporaneamente per lo stesso recinto virtuale, a meno che non sia necessario. In tal caso, annulla la registrazione del listener in foreground quando l'app viene sospesa e registralo nuovamente quando l'app riprende.