Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Determinare la posizione dell'utente

Link copiato negli appunti

Windows 8 può determinare la posizione dell'utente tramite due fonti: la prima, piuttosto imprecisa, si basa sul Windows Location Provider (parte della Windows Sensor and Location Platform), il quale utilizza la triangolazione tramite reti wireless e l'analisi dell'indirizzo IP. La seconda, assai più affidabile, si basa sul sensore GPS, ove presente sul device.

In entrambi i casi, WinRT mette a disposizione degli sviluppatori una stessa Location API. Spetta infatti a WinRT il compito di determinare quale sia il provider - se il Windows Location Provider o il sensore GPS - più adatto nel caso concreto. Se entrambi i provider sono presenti sul device, WinRT sceglierà quello in grado di assicurare i dati più precisi in quel particolare contesto. Dal punto di vista dello sviluppatore, i meccanismi interni utilizzati dal sistema per recuperare la posizione dell'utente sono del tutto trasparenti.

Nel caso di applicazioni Windows Store in esecuzione su un normale PC desktop (normalmente sprovvisto di sensore GPS), è importante non aspettarsi dati troppo accurati in merito alla localizzazione dell'utente: la posizione ottenuta triangolando le reti Wi-Fi ha un margine d'errore di 350 metri nelle aree urbane (dove le reti wireless sono molto più numerose), aumentando al rarefarsi di hot-spot e reti wireless; nel caso di analisi dell'indirizzo IP, invece, l'approssimazione è di circa 50 km.

Per testare un'applicazione con informazioni più accurate, è possibile usare Windows 8 Simulator. Il simulatore permette di impostare le coordinate geografiche, inclusa l'altitudine e il margine d'errore, che verranno utilizzate per testare il comportamento della tua app. La prossima immagine mostra il dialog del simulatore.

I dati geo localizzati rappresentano informazioni delicate, in quanto potenzialmente lesive della privacy dell'utente (per i cosiddetti "sensitive device", ossia i sensori e le periferiche suscettibili di raccogliere dati sensibili sugli utenti, come webcam e sensori GPS, la documentazione ufficiale Microsoft prevede delle specifiche linee guida). Per questa ragione, per poter accedere alla Location API via codice non solo è necessario aggiungere la "capability" Location nell'application manifest, mostrato nella prossima figura, ma è anche necessario il consenso esplicito dell'utente all'uso del sensore di localizzazione geografica.

La prima volta che l'app tenta di accedere alla posizione dell'utente, WinRT mostra infatti all'utente un dialog box con la richiesta di autorizzazione all'uso delle relative API, illustrato nella prossima immagine. Per questo la nostra app dovrà essere in grado di gestire l'eventuale rifiuto da parte dell'utente.

Recuperare i dati sulla posizione dell'utente

Il namespace Windows.Devices.Geolocation espone tutte le classi, i tipi e i metodi necessari a recuperare le informazioni sulla posizione geografica dell'utente. La classe responsabile per gestire le varie operazioni è la classe Geolocator. Il prossimo listato mostra come usare questa classe per recuperare la posizione corrente:

private Geolocator _geoLocator;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
	this._geoLocator = new Geolocator();
	this._geoLocator.DesiredAccuracy = PositionAccuracy.High;
	this._geoLocator.StatusChanged += GeoLocator_StatusChanged;
}
private async void GetLocation_Click(object sender, RoutedEventArgs e)
{
	try
	{
		var position = await this._geoLocator.GetGeopositionAsync();
		this.DisplayPosition(position);
	}
	catch (UnauthorizedAccessException ex)
	{
		// l'app ha bisogno del permesso dell'utente
		// per recuperare i dati sulla posizione
	}
	catch (Exception)
	{
		// qualcosa è andato storto
	}
}
private async void GeoLocator_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
{
	await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
	{
		switch (args.Status)
		{
			case PositionStatus.Ready:
				GpsStatusTextBlock.Text += "Geolocation: Ready\n";
				break;
			case PositionStatus.Initializing:
				GpsStatusTextBlock.Text += "Geolocation: Initializing\n";
				break;
			case PositionStatus.NoData:
				GpsStatusTextBlock.Text += " Geolocation: No data\n";
				break;
			case PositionStatus.Disabled:
				GpsStatusTextBlock.Text += " Geolocation: Disabled\n";
				break;
			case PositionStatus.NotInitialized:
				GpsStatusTextBlock.Text += " Geolocation: Not initialized\n";
				break;
			case PositionStatus.NotAvailable:
				GpsStatusTextBlock.Text += " Geolocation: Not available\n";
				break;
			default:
				GpsStatusTextBlock.Text += " Geolocation: Unknown\n";
				break;
		}
	});
}
private async void DisplayPosition(Geoposition position)
{
	await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
	{
		LongitudeTextBlock.Text = String.Format("Longitudine: {0} gradi", position.Coordinate.Longitude);
		LatitudeTextBlock.Text = String.Format("Latitudine: {0} gradi", position.Coordinate.Latitude);
		HeadingTextBlock.Text = String.Format("Direzione: {0} gradi", position.Coordinate.Heading == null ? 0 : position.Coordinate.Heading);
		SpeedTextBlock.Text = String.Format("Velocità: {0} m/s", position.Coordinate.Speed == null ? 0 : position.Coordinate.Speed);
		AltitudeTextBlock.Text = String.Format("Altitudine: {0} m", position.Coordinate.Altitude == null ? 0 : position.Coordinate.Altitude);
		AccuracyTextBlock.Text = String.Format("Accuratezza: {0} m", position.Coordinate.Accuracy);
		TimestampTextBlock.Text = String.Format("Timestamp: {0:H:mm:ss.FF}", position.Coordinate.Timestamp);
		TrackPositionPanel.Visibility = Windows.UI.Xaml.Visibility.Visible;
	});
}

Nel metodo OnNavigatedTo, dopo aver istanziato un nuovo oggetto di tipo Geolocator, il codice sfrutta la proprietà DesiredAccuracy per impostare il livello di accuratezza delle rilevazioni. Maggiore è la precisione, maggiore è il consumo di batterie, per cui sarebbe meglio impostare la proprietà a High solo se e quando l'applicazione necessita di dati precisi. Tieni inoltre presente che, anche in questo caso, l'accuratezza effettiva dei dati registrati dal sensore dipende da numerosi altri fattori.

L'evento StatusChanged viene sollevato quando lo stato del sensore, espresso dalla proprietà Status dell'oggetto PositionChangedEventArgs ricevuto come parametro dall'event handler, cambia. La proprietà Status può assumere uno dei seguenti valori (espresso tramite l'enum PositionStatus):

Valore Descrizione
Ready Sono disponibili dati sulla posizione
Initializing Il location provider è in corso di inizializzazione (ad esempio, perché sta cercando il numero minimo di satelliti necessari per determinare la posizione)
NoData Nessun dato disponibile
Disabled L'utente non ha prestato all'applicazione il suo consenso per accedere alla posizione. Accertati che la tua app sia in grado di gestire questa eventualità
NotInitialized Il location provider non è stato ancora inizializzato
NotAvailable La Windows Sensor and Location platform non è disponibile sul sistema

Lo stato corrente del location provider può essere verificato in ogni momento tramite la proprietà LocationStatus della classe Geolocator.

Per recuperare la posizione dell'utente, è sufficiente invocare il metodo GetGeopositionAsync tramite il pattern asincrono async/await. Questo metodo restituisce un oggetto Geoposition contenente i dati geolocalizzati. Più in particolare, la classe Geoposition espone due tipi di dati relativi alla posizione dell'utente.

Il primo tipo di dati è incapsulato dalla proprietà Coordinate (di tipo Geocoordinate). Questa proprietà rappresenta le coordinate geografiche (come longitudine e latitudine), assieme ad altri dati complementari, come l'altitudine (espressa in metri sopra il livello del mare), la direzione corrente (espressa in gradi rispetto al nord geografico), la velocità (in metri per secondo), l'accuratezza della rilevazione e un timestamp che indica il momento della rilevazione. La disponibilità di alcuni di questi dati, come altitudine e velocità, dipendono dall'implementazione concreta del dispositivo GPS montato sul device, per cui è sempre buona regola verificare che non siano null prima di usarli. Il Windows Location Provider, invece, mette a disposizione unicamente dati relativi a longitudine, latitudine e accuratezza.

Il secondo tipo di informazioni esposte dalla classe Geoposition è rappresentato dalla proprietà CivicAddress, la quale rappresenta l'indirizzo civico associato ad una determinata posizione geografica. Tuttavia, questa informazione è disponibile solo se è stato installato un Civic Address provider. In caso contrario, l'API restituirà solo le informazioni regionali accessibili tramite il Control Panel. Windows 8 non fornisce infatti alcun Civic Address provider di default (almeno per adesso), né al momento risultano disponibili provider di terze parti. Se la tua app ha bisogno di questo tipo di informazioni, potresti considerare la possibilità di utilizzare servizi esterni, come il servizio Bing Maps Geocode.

La classe Geolocator espone anche un overload del metodo GetGeopositionAsync che accetta come parametri due oggetti di tipo TimeSpan: il primo indica l'età massima dei dati geolocalizzati eventualmente presenti in cache, mentre il secondo rappresenta il time-out per concludere l'operazione (il tempo di default è di 7 secondi). Se nessun location provider viene trovato entro questo termine, viene sollevato l'evento StatusChanged e la proprietà Status viene impostata a NoData.

Tracciare la posizione dell'utente

Oltre a determinare la posizione geografica dell'utente in un certo momento, la classe Geolocator permette anche di tenere traccia dei movimenti dell'utente, grazie all'evento PositionChanged. Questo evento viene sollevato ogni volta che il location provider si accorge che la posizione geografica dell'utente è cambiata. Il prossimo listato mostra un esempio di come utilizzare questo evento:

private async void TrackPosition_Click(object sender, RoutedEventArgs e)
{
	try
	{
		this._geoLocator.DesiredAccuracy = PositionAccuracy.Default;
		this._geoLocator.MovementThreshold = 5.0;
		this._geoLocator.PositionChanged += GeoLocator_PositionChanged;
		var osition = await this._geoLocator.GetGeopositionAsync();
		this.DisplayPosition(position);
	}
	catch (UnauthorizedAccessException ex)
	{
		// l'app ha bisogno del permesso dell'utente
		// per recuperare i dati sulla posizione
	}
	catch (Exception)
	{
		// qualcosa è andato storto
	}
}
private void GeoLocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
{
	this.DisplayPosition(args.Position);
}

Per evitare che l'evento sia invocato a fronte anche del più piccolo spostamento dell'utente, è possibile impostare la proprietà MovementThreshold con la distanza minima (espressa in metri) da percorrere prima che l'evento PositionChanged venga sollevato (il valore di default di questa proprietà è zero).

Il prossimo listato mostra il codice XAML che possiamo usare come riferimento per la pagina MainPage.xaml e testare il codice presentato in questo articolo.

<Page x:Class="Demo.Html.it.GeolocationSample.CS.MainPage"
	  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	  xmlns:local="using:Demo.Html.it.GeolocationSample.CS"
	  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	  mc:Ignorable="d">
	<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
		<StackPanel>
			<StackPanel Orientation="Horizontal">
				<Button Content="Traccia la posizione" Click="TrackPosition_Click" Height="40" Width="200" Margin="20" />
				<Button Content="Ottieni posizione" Click="GetLocation_Click" Height="40" Width="200" Margin="20"/>
			</StackPanel>
			<TextBlock Margin="5" FontSize="18" Width="Auto" Height="Auto" Name="GpsStatusTextBlock" TextWrapping="Wrap" />
			<StackPanel x:Name="TrackPositionPanel" Visibility="Collapsed">
				<TextBlock Margin="5" FontSize="24" Width="Auto" Height="Auto" Name="LatitudeTextBlock" />
				<TextBlock Margin="5" FontSize="24" Width="Auto" Height="Auto" Name="LongitudeTextBlock" />
				<TextBlock Margin="5" FontSize="24" Width="Auto" Height="Auto" Name="AccuracyTextBlock" />
				<TextBlock Margin="5" FontSize="24" Width="Auto" Height="Auto" Name="HeadingTextBlock" />
				<TextBlock Margin="5" FontSize="24" Width="Auto" Height="Auto" Name="SpeedTextBlock" />
				<TextBlock Margin="5" FontSize="24" Width="Auto" Height="Auto" Name="AltitudeTextBlock" />
				<TextBlock Margin="5" FontSize="24" Width="Auto" Height="Auto" Name="TimestampTextBlock" />
			</StackPanel>
		</StackPanel>
	</Grid>
</Page>

Il risultato è mostrato nella prossima immagine. Come si può vedere, i campi relativi alla direzione, alla velocità e all'altitudine non sono stati valorizzati dal location provider in quanto non disponibili:

Ti consigliamo anche