Negli ultimi anni è diventato importante offrire contenuti personalizzati e servizi sulla base della posizione dell’utente. In questa lezione si introdurranno i meccanismi necessari per sfruttare i servizi di localizzazione offerti dalle diverse piattaforme.
Fatta eccezione per i meccanismi di geocoding e reverse geocoding, ossia di conversione di un indirizzo in coordinate geografiche e viceversa, Xamarin.Forms non offre servizi di localizzazione come navigazione e, cosa più importante, la posizione corrente dell’utente.
Per integrare tale funzione nell’app, il primo passo è la definizione di una classe che rappresenti le coordinate geografiche come coppia di punti latitudine e longitudine. Definiamo quindi nel progetto Portable una nuova cartella, Location, che conterrà al suo interno la classe LocationPoint
(disponibili a questo link).
Successivamente, va definita un’interfaccia che verrà estesa in ogni piattaforma. L’interfaccia ILocationProvider
definisce i seguenti tre metodi:
Metodo | Descrizione |
---|---|
LocationChanged |
Definisce un evento che permette di gestire i cambi di posizione del dispositivo, ossia quando un nuovo LocationPoint è disponibile |
StartAcquisition |
Inizia l’acquisizione della posizione corrente del dispositivo |
StopAcquisition |
Ferma l’acquisizione della posizione del dispositivo quando l’app viene messa in pausa |
In un’app composta da più pagine, è importante che l’acquisizione della posizione inizi quando la pagina sta per essere visualizzata dall’utente, richiamando il metodo StartAcquisition
all’interno del metodo OnAppearing
, e termini quando la pagina sta per non essere più visibile richiamando il metodo StopAcquisition
all’interno del metodo OnDisappearing
.
Implementiamo ora l’interfaccia in ogni piattaforma.
iOS
Aggiungiamo una nuova classe, LocationProvide_iOS
, che definisce l’attributo Dependency
prima del namespace e implementa l’interfaccia ILocationProvider
.
A partire da iOS 8, è necessario fornire un’autorizzazione esplicita (fornita ad esempio dal metodo RequestWhenInUseAuthorization
) per abilitare la localizzazione che viene effettuata dalla classe CLLocationManager
fornita da iOS.
La classe sarà quindi definita come segue:
CLLocationManager locationManager;
public event EventHandler<LocationPoint> LocationChanged;
public LocationProvider_iOS()
{
locationManager = new CLLocationManager();
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
locationManager.RequestWhenInUseAuthorization();
}
locationManager.LocationsUpdated +=
(object sender, CLLocationsUpdatedEventArgs args) =>
{
CLLocationCoordinate2D coordinate = args.Locations[0].Coordinate;
EventHandler<LocationPoint> handler = LocationChanged;
if (handler != null)
{
handler(this, new LocationPoint(coordinate.Latitude, coordinate.Longitude));
}
};
}
public void StartAcquisition()
{
if (CLLocationManager.LocationServicesEnabled)
{
locationManager.StartUpdatingLocation();
}
}
public void StopAcquisition()
{
locationManager.StopUpdatingLocation();
}
Android
Per Android, l’acquisizione della posizione può essere effettuata impiegando una tra le seguenti API:
- la classe
LocationManager
, offerta nativamente; - la classe
FusedLocationProviderApi
, fornita dalla libreria Google Play Services da scaricare attraverso SDK manager.
Per semplicità, in questa lezione useremo la classe LocationManager
, ma i miglioramenti introdotti dalle API offerte dalle Google Play Services fanno sì che in futuro diventeranno le principali API da utilizzare non solo per la localizzazione ma anche per le mappe e altri servizi, come già trattato in questa guida.
LocationManager definisce tre diversi provider (GPS, network, passive) per ottenere la posizione. Per ottenere la posizione corrente impiegando sia il GPS sia la rete, si deve richiamare il metodo RequestLocationUpdates
che, per fornire una nuova posizione, prende in input un tempo e una distanza di aggiornamento minima.
Per supportare a pieno il LocationManager
, è necessario estendere la classe Java.Lang.Object ed implementare l’interfaccia ILocationListener
. Quest’ultima richiede di implementare quattro metodi di cui solo OnLocationChanged
deve essere implementato da noi (codice).
public class LocationProvider_Android : Java.Lang.Object, ILocationProvider, ILocationListener
{
LocationManager locationManager;
public event EventHandler<LocationPoint> LocationChanged;
public LocationProvider_Android()
{
Activity activity = LocalizationSupport.Activity;
if (activity == null)
throw new InvalidOperationException(
"Must call LocationSupport.Init before using LocationProvider");
locationManager =
activity.GetSystemService(Context.LocationService) as LocationManager;
}
public void StartAcquisition()
{
IList<string> locationProviders = locationManager.AllProviders;
foreach (string locationProvider in locationProviders)
{
locationManager.RequestLocationUpdates(locationProvider, 1000, 1, this);
}
}
public void StopAcquisition()
{
locationManager.RemoveUpdates(this);
}
public void OnLocationChanged(Android.Locations.Location location)
{
EventHandler<LocationPoint> handler = LocationChanged;
if (handler != null)
{
handler(this, new LocationPoint(location.Latitude, location.Longitude));
}
}
. . .
}
Infine, come si è potuto notare, per il corretto funzionamento del LocationManager
è necessaria la creazione di un’Activity
. A tal proposito è stata creata la classe LocationSupport
(codice) che definisce la proprietà Activity
e un metodo di inizializzazione, Init
. Tale metodo viene richiamato staticamente dentro la MainActivity
, come qui riportato.
Windows Phone
Per Windows Phone, è sufficiente istanziare all’interno del costruttore della classe un oggetto di tipo Geolocator
fornito dalle Windows.Devices.Geolocation
API e impostare l’attributo ReportInterval
ad un valore arbitrario espresso in millisecondi. Al seguente link è disponibile l’implementazione completa della classe LocationProvider_WinApp
.
Permessi
Ultimo passo per avere un’app location-aware è l’abilitazione dei permessi:
OS | Procedura |
---|---|
Android | Aprire l’AndroidManifest contenuto nella sezione Properties e selezionare il permesso ACCESS_FINE_LOCATION per una localizzazione puntuale tramite GPS. Se si desidera offrire la localizzazione tramite WiFi, spuntare anche ACCESS_COARSE_LOCATION |
iOS | Per i permessi per la localizzazione, iOS richiama il metodo RequestWhenInUseAuthorization . Ciò genera un alert che viene mostrato all’utente con un messaggio che può essere modificato nel file Info.plist. Ad esempio all’interno del tag <dict> possiamo aggiungere:<key>NSLocationWhenInUseUsageDescription</key> <string>This app display your current location</string> |
Windows Phone | Selezionare il file Package.appxmanifest e alla voce Funzionalità spuntare la voce Posizione. Se si usa la visualizzazione del file tramite XML, all’interno del tag Capabilities aggiungere <DeviceCapability Name="location"/> |
Infine, non resta che creare una nuova Form Xaml Page per visualizzare la posizione corrente. Di seguito si riporta il risultato per tutte e tre le piattaforme.