Condividi tramite


Configurare un recinto virtuale

Configurare un Geofence nell'app e imparare a gestire le notifiche in primo piano e sullo sfondo.

Abilitare la funzionalità posizione

  1. In Esplora soluzioni fare doppio clic su package.appxmanifest e selezionare la scheda Funzionalità.
  2. Nell'elenco Funzionalità selezionare Posizione. Ciò aggiunge la Location funzionalità del dispositivo al file manifesto del pacchetto.
  <Capabilities>
    <!-- DeviceCapability elements must follow Capability elements (if present) -->
    <DeviceCapability Name="location"/>
  </Capabilities>

Configurazione del recinto virtuale

Passaggio 1: Richiedere l'accesso alla posizione dell'utente

Importante

È necessario richiedere l'accesso alla posizione dell'utente usando il metodo RequestAccessAsync prima di tentare di accedere alla posizione dell'utente. Si deve chiamare il metodo RequestAccessAsync dal thread dell'interfaccia utente e l'app deve essere in primo piano. L'app non sarà in grado di accedere alle informazioni sulla posizione dell'utente fino a quando l'utente non concede l'autorizzazione all'app.

using Windows.Devices.Geolocation;
...
var accessStatus = await Geolocator.RequestAccessAsync();

Il metodo RequestAccessAsync richiede all'utente l'autorizzazione per accedere alla propria posizione. All'utente viene richiesto una sola volta (per app). Dopo la prima volta che concedono o negano l'autorizzazione, questo metodo non richiede più all'utente l'autorizzazione. Per consentire all'utente di modificare le autorizzazioni relative alla posizione dopo che sono state richieste, è consigliabile fornire un collegamento alle impostazioni della posizione, come illustrato più avanti in questo argomento.

Passaggio 2: eseguire la registrazione per le modifiche apportate alle autorizzazioni relative allo stato del recinto virtuale e alla posizione

In questo esempio, viene usata un'istruzione switch con accessStatus (dall'esempio precedente) per agire solo quando è consentito l'accesso alla posizione dell'utente. Se è consentito l'accesso alla posizione dell'utente, il codice accede ai recinti virtuali correnti, esegue la registrazione per le modifiche dello stato del recinto virtuale e registra le modifiche apportate alle autorizzazioni di posizione.

Suggerimento Quando si usa un recinto virtuale, monitorare le modifiche apportate alle autorizzazioni di posizione usando l'evento StatusChanged dalla classe GeofenceMonitor anziché dall'evento StatusChanged dalla classe Geolocator. Un GeofenceMonitorStatus di Disabilitato è equivalente a un PositionStatus - disabilitato. Entrambi indicano che l'app non dispone dell'autorizzazione per accedere alla posizione dell'utente.

switch (accessStatus)
{
    case GeolocationAccessStatus.Allowed:
        geofences = GeofenceMonitor.Current.Geofences;

        FillRegisteredGeofenceListBoxWithExistingGeofences();
        FillEventListBoxWithExistingEvents();

        // Register for state change events.
        GeofenceMonitor.Current.GeofenceStateChanged += OnGeofenceStateChanged;
        GeofenceMonitor.Current.StatusChanged += OnGeofenceStatusChanged;
        break;


    case GeolocationAccessStatus.Denied:
        _rootPage.NotifyUser("Access denied.", NotifyType.ErrorMessage);
        break;

    case GeolocationAccessStatus.Unspecified:
        _rootPage.NotifyUser("Unspecified error.", NotifyType.ErrorMessage);
        break;
}

Quindi, quando si esce dall'app in primo piano, annullare la registrazione dei listener di eventi.

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
    GeofenceMonitor.Current.GeofenceStateChanged -= OnGeofenceStateChanged;
    GeofenceMonitor.Current.StatusChanged -= OnGeofenceStatusChanged;

    base.OnNavigatingFrom(e);
}

Passaggio 3: Creare il recinto virtuale

A questo scopo, è possibile definire e configurare un oggetto Geofence. Esistono diversi overload del costruttore tra cui scegliere, a seconda delle esigenze. Nel costruttore di recinto virtuale specificare solo Id e la Geoshape come mostrato qui.

// Set the fence ID.
string fenceId = "fence1";

// Define the fence location and radius.
BasicGeoposition position;
position.Latitude = 47.6510;
position.Longitude = -122.3473;
position.Altitude = 0.0;
double radius = 10; // in meters

// Set a circular region for the geofence.
Geocircle geocircle = new Geocircle(position, radius);

// Create the geofence.
Geofence geofence = new Geofence(fenceId, geocircle);

È possibile ottimizzare ulteriormente il recinto virtuale usando uno degli altri costruttori. Nell'esempio seguente il costruttore del recinto virtuale specifica questi parametri aggiuntivi:

  • MonitoredStates: indica gli eventi di recinto virtuale da ricevere per l'immissione dell'area definita, l'uscita dall'area definita o la rimozione del recinto virtuale.
  • SingleUse: rimuove il recinto virtuale dopo che tutti gli stati per cui viene monitorato il recinto virtuale sono stati soddisfatti.
  • DwellTime: indica per quanto tempo l'utente deve trovarsi all'interno o all'esterno dell'area definita prima che vengano attivati gli eventi di immissione/uscita.
  • StartTime: indica quando avviare il monitoraggio del recinto virtuale.
  • Duration: indica il periodo per il quale monitorare il recinto virtuale.
// Set the fence ID.
string fenceId = "fence2";

// Define the fence location and radius.
BasicGeoposition position;
position.Latitude = 47.6510;
position.Longitude = -122.3473;
position.Altitude = 0.0;
double radius = 10; // in meters

// Set the circular region for geofence.
Geocircle geocircle = new Geocircle(position, radius);

// Remove the geofence after the first trigger.
bool singleUse = true;

// Set the monitored states.
MonitoredGeofenceStates monitoredStates =
                MonitoredGeofenceStates.Entered |
                MonitoredGeofenceStates.Exited |
                MonitoredGeofenceStates.Removed;

// Set how long you need to be in geofence for the enter event to fire.
TimeSpan dwellTime = TimeSpan.FromMinutes(5);

// Set how long the geofence should be active.
TimeSpan duration = TimeSpan.FromDays(1);

// Set up the start time of the geofence.
DateTimeOffset startTime = DateTime.Now;

// Create the geofence.
Geofence geofence = new Geofence(fenceId, geocircle, monitoredStates, singleUse, dwellTime, startTime, duration);

Dopo la creazione, ricordarsi di registrare il nuovo recinto virtuale nel monitoraggio.

// Register the geofence
try {
   GeofenceMonitor.Current.Geofences.Add(geofence);
} catch {
   // Handle failure to add geofence
}

Passaggio 4: Gestire le modifiche nelle autorizzazioni per la posizione

L'oggetto GeofenceMonitor attiva l'evento StatusChanged per indicare che le impostazioni della posizione dell'utente sono state modificate. Tale evento passa lo stato corrispondente tramite il mittente dell'argomento. Proprietà dello stato (di tipo GeofenceMonitorStatus). Si noti che questo metodo non viene chiamato dal thread dell'interfaccia utente e l'oggetto Dispatcher richiama le modifiche dell'interfaccia utente.

using Windows.UI.Core;
...
public async void OnGeofenceStatusChanged(GeofenceMonitor sender, object e)
{
   await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
   {
    // Show the location setting message only if the status is disabled.
    LocationDisabledMessage.Visibility = Visibility.Collapsed;

    switch (sender.Status)
    {
     case GeofenceMonitorStatus.Ready:
      _rootPage.NotifyUser("The monitor is ready and active.", NotifyType.StatusMessage);
      break;

     case GeofenceMonitorStatus.Initializing:
      _rootPage.NotifyUser("The monitor is in the process of initializing.", NotifyType.StatusMessage);
      break;

     case GeofenceMonitorStatus.NoData:
      _rootPage.NotifyUser("There is no data on the status of the monitor.", NotifyType.ErrorMessage);
      break;

     case GeofenceMonitorStatus.Disabled:
      _rootPage.NotifyUser("Access to location is denied.", NotifyType.ErrorMessage);

      // Show the message to the user to go to the location settings.
      LocationDisabledMessage.Visibility = Visibility.Visible;
      break;

     case GeofenceMonitorStatus.NotInitialized:
      _rootPage.NotifyUser("The geofence monitor has not been initialized.", NotifyType.StatusMessage);
      break;

     case GeofenceMonitorStatus.NotAvailable:
      _rootPage.NotifyUser("The geofence monitor is not available.", NotifyType.ErrorMessage);
      break;

     default:
      ScenarioOutput_Status.Text = "Unknown";
      _rootPage.NotifyUser(string.Empty, NotifyType.StatusMessage);
      break;
    }
   });
}

Configurare le notifiche in primo piano

Dopo aver creato i recinti virtuali, è necessario aggiungere la logica per gestire ciò che accade quando si verifica un evento recinto virtuale. A seconda degli stati monitorati configurati, è possibile ricevere un evento quando:

  • L'utente entra in un'area di interesse.
  • L'utente lascia un'area di interesse.
  • Il recinto virtuale è scaduto o è stato rimosso. Si noti che un'app in background non è attivata per un evento di rimozione.

È possibile ascoltare gli eventi direttamente dall'app quando è in esecuzione o registrarsi per un'attività in background in modo da ricevere una notifica in background quando si verifica un evento.

Passaggio 1: Eseguire la registrazione per gli eventi di modifica dello stato del recinto virtuale

Affinché l'app riceva una notifica in primo piano di una modifica dello stato del recinto virtuale, è necessario registrare un gestore di eventi. Questa operazione viene in genere configurata quando si crea il recinto virtuale.

private void Initialize()
{
    // Other initialization logic

    GeofenceMonitor.Current.GeofenceStateChanged += OnGeofenceStateChanged;
}

Passaggio 2: Implementare il gestore eventi recinto virtuale

Il passaggio successivo consiste nell'implementare i gestori eventi. L'azione eseguita qui dipende dall'uso del recinto virtuale dell'app.

public async void OnGeofenceStateChanged(GeofenceMonitor sender, object e)
{
    var reports = sender.ReadReports();

    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        foreach (GeofenceStateChangeReport report in reports)
        {
            GeofenceState state = report.NewState;

            Geofence geofence = report.Geofence;

            if (state == GeofenceState.Removed)
            {
                // Remove the geofence from the geofences collection.
                GeofenceMonitor.Current.Geofences.Remove(geofence);
            }
            else if (state == GeofenceState.Entered)
            {
                // Your app takes action based on the entered event.

                // NOTE: You might want to write your app to take a particular
                // action based on whether the app has internet connectivity.

            }
            else if (state == GeofenceState.Exited)
            {
                // Your app takes action based on the exited event.

                // NOTE: You might want to write your app to take a particular
                // action based on whether the app has internet connectivity.

            }
        }
    });
}

Configurare le notifiche in background

Dopo aver creato i recinti virtuali, è necessario aggiungere la logica per gestire ciò che accade quando si verifica un evento recinto virtuale. A seconda degli stati monitorati configurati, è possibile ricevere un evento quando:

  • L'utente entra in un'area di interesse.
  • L'utente lascia un'area di interesse.
  • Il recinto virtuale è scaduto o è stato rimosso. Si noti che un'app in background non è attivata per un evento di rimozione.

Per restare in ascolto di un evento di recinto virtuale in background

  • Dichiarare l'attività in background nel manifesto dell'app.
  • Registrare l'attività in background nell'app. Se l'app richiede l'accesso a Internet, ad esempio per l'accesso a un servizio cloud, è possibile impostare un flag per tale accesso quando viene attivato l'evento. È anche possibile impostare un flag per assicurarsi che l'utente sia presente quando viene attivato l'evento in modo da assicurarsi che l'utente riceva una notifica.
  • Mentre l'app è in esecuzione in primo piano, chiedere all'utente di concedere le autorizzazioni per la posizione dell'app.

Passaggio 1: Eseguire la registrazione per le modifiche dello stato del recinto virtuale

Nel manifesto dell'app, nella scheda Dichiarazioni aggiungere una dichiarazione per un'attività in background della posizione. A questo scopo, è necessario:

  • Aggiungere una dichiarazione di tipo Attività in background.
  • Impostare un tipo di attività di proprietà della Posizione.
  • Impostare un punto di ingresso nell'app per chiamare quando viene attivato l'evento.

Passaggio 2: Registrare l'attività in background

Il codice in questo passaggio registra l'attività in background di geofencing. Tenere presente che quando è stato creato il recinto virtuale, è stata verificata la presenza di autorizzazioni per la posizione.

async private void RegisterBackgroundTask(object sender, RoutedEventArgs e)
{
    // Get permission for a background task from the user. If the user has already answered once,
    // this does nothing and the user must manually update their preference via PC Settings.
    BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();

    // Regardless of the answer, register the background task. Note that the user can use
    // the Settings app to prevent your app from running background tasks.
    // Create a new background task builder.
    BackgroundTaskBuilder geofenceTaskBuilder = new BackgroundTaskBuilder();

    geofenceTaskBuilder.Name = SampleBackgroundTaskName;
    geofenceTaskBuilder.TaskEntryPoint = SampleBackgroundTaskEntryPoint;

    // Create a new location trigger.
    var trigger = new LocationTrigger(LocationTriggerType.Geofence);

    // Associate the location trigger with the background task builder.
    geofenceTaskBuilder.SetTrigger(trigger);

    // If it is important that there is user presence and/or
    // internet connection when OnCompleted is called
    // the following could be called before calling Register().
    // SystemCondition condition = new SystemCondition(SystemConditionType.UserPresent | SystemConditionType.InternetAvailable);
    // geofenceTaskBuilder.AddCondition(condition);

    // Register the background task.
    geofenceTask = geofenceTaskBuilder.Register();

    // Associate an event handler with the new background task.
    geofenceTask.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);

    BackgroundTaskState.RegisterBackgroundTask(BackgroundTaskState.LocationTriggerBackgroundTaskName);

    switch (backgroundAccessStatus)
    {
    case BackgroundAccessStatus.Unspecified:
    case BackgroundAccessStatus.Denied:
        rootPage.NotifyUser("This app is not allowed to run in the background.", NotifyType.ErrorMessage);
        break;

    }
}


Passaggio 3: Gestione della notifica in background

L'azione eseguita per notificare all'utente dipende dalle operazioni eseguite dall'app, ma è possibile visualizzare una notifica di tipo avviso popup, riprodurre un suono audio o aggiornare un riquadro animato. Il codice in questo passaggio gestisce la notifica.

async private void OnCompleted(IBackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs e)
{
    if (sender != null)
    {
        // Update the UI with progress reported by the background task.
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            try
            {
                // If the background task threw an exception, display the exception in
                // the error text box.
                e.CheckResult();

                // Update the UI with the completion status of the background task.
                // The Run method of the background task sets the LocalSettings.
                var settings = ApplicationData.Current.LocalSettings;

                // Get the status.
                if (settings.Values.ContainsKey("Status"))
                {
                    rootPage.NotifyUser(settings.Values["Status"].ToString(), NotifyType.StatusMessage);
                }

                // Do your app work here.

            }
            catch (Exception ex)
            {
                // The background task had an error.
                rootPage.NotifyUser(ex.ToString(), NotifyType.ErrorMessage);
            }
        });
    }
}


Modificare le impostazioni di privacy

Se le impostazioni della privacy della posizione non consentono all'app di accedere alla posizione dell'utente, è consigliabile fornire un collegamento pratico alle impostazioni della privacy della posizione nell'app Impostazioni. In questo esempio viene usato un controllo Collegamento ipertestuale per passare all'URI ms-settings:privacy-location.

<!--Set Visibility to Visible when access to the user's location is denied. -->  
<TextBlock x:Name="LocationDisabledMessage" FontStyle="Italic"
                 Visibility="Collapsed" Margin="0,15,0,0" TextWrapping="Wrap" >
          <Run Text="This app is not able to access Location. Go to " />
              <Hyperlink NavigateUri="ms-settings:privacy-location">
                  <Run Text="Settings" />
              </Hyperlink>
          <Run Text=" to check the location privacy settings."/>
</TextBlock>

In alternativa, l'app può chiamare il metodo LaunchUriAsync per avviare l'app Impostazioni dal codice. Per maggiori informazioni, vedere Avviare l'app Impostazioni di Windows.

using Windows.System;
...
bool result = await Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-location"));

Testare ed eseguire il debug dell'app

Il test e il debug delle app con recinto virtuale possono essere un problema perché dipendono dalla posizione di un dispositivo. In questo caso vengono descritti diversi metodi per testare sia i recinti virtuali sia in primo piano che in background.

Per eseguire il debug di un'app con recinto virtuale

  1. Spostare fisicamente il dispositivo in nuove posizioni.
  2. Testare l'ingresso in un recinto virtuale creando un'area recinto virtuale che include la posizione fisica corrente, quindi si è già all'interno del recinto virtuale e l'evento "recinto virtuale di ingresso" viene attivato immediatamente.
  3. Usare l'emulatore di Microsoft Visual Studio per simulare le posizioni per il dispositivo.

Testare ed eseguire il debug di un'app con recinto virtuale in esecuzione in primo piano

Per testare l'app geofencing in esecuzione in primo piano

  1. Creare l'app in Visual Studio.
  2. Avviare l'app nell'emulatore di Visual Studio.
  3. Usare questi strumenti per simulare diverse posizioni all'interno e all'esterno dell'area del recinto virtuale. Assicurarsi di attendere abbastanza tempo oltre il tempo specificato dalla proprietà DwellTime per attivare l'evento. Si noti che è necessario accettare il prompt per abilitare le autorizzazioni per la posizione per l'app. Per altre info sulla simulazione delle posizioni, vedere Impostare la georilevazione simulata del dispositivo.
  4. È anche possibile usare l'emulatore per stimare le dimensioni delle recinzioni e i tempi di attesa approssimativamente necessari per essere rilevati a velocità diverse.

Testare ed eseguire il debug di un'app con recinto virtuale in esecuzione in background

Per testare l'app con recinto virtuale in esecuzione in background

  1. Creare l'app in Visual Studio. Tenere presente che l'app deve impostare il tipo di attività In posizione background.
  2. Distribuire prima l'app in locale.
  3. Chiudere l'app in esecuzione in locale.
  4. Avviare l'app nell'emulatore di Visual Studio. Si noti che la simulazione di geofencing in background è supportata in una sola app alla volta all'interno dell'emulatore. Non avviare più app con recinto virtuale all'interno dell'emulatore.
  5. Dall'emulatore simulare varie posizioni all'interno e all'esterno dell'area del recinto virtuale. Assicurarsi di attendere abbastanza tempo oltre l'elemento DwellTime per attivare l'evento. Si noti che è necessario accettare il prompt per abilitare le autorizzazioni per la posizione per l'app.
  6. Usare Visual Studio per attivare l'attività in background della posizione. Per altre informazioni sull'attivazione di attività in background in Visual Studio, vedere Come attivare attività in background.

Risolvere i problemi dell’app

Prima che l'app possa accedere alla posizione, la posizione deve essere abilitata nel dispositivo. Nell'app Impostazioni verificare che le impostazioni di privacy della posizione seguenti siano attivate:

  • Posizione per questo dispositivo... è attivato (non applicabile in Windows 10 Mobile)
  • L'impostazione dei servizi di posizione, Location, è attivata
  • In Scegliere app che possono usare la posizione, l'app è impostata su on