Servizi di posizione in Android

Questa guida presenta la consapevolezza della posizione nelle applicazioni Android e illustra come ottenere la posizione dell'utente usando l'API del servizio di posizione Android, nonché il provider di posizioni fuso disponibile con l'API Google Location Services.

Android consente l'accesso a varie tecnologie di posizione, ad esempio la posizione della torre cellulare, il Wi-Fi e il GPS. I dettagli di ogni tecnologia di posizione vengono astratti tramite provider di località, consentendo alle applicazioni di ottenere posizioni nello stesso modo indipendentemente dal provider usato. Questa guida presenta il provider di posizione fuso, una parte di Google Play Services, che determina in modo intelligente il modo migliore per ottenere la posizione dei dispositivi in base ai provider disponibili e al modo in cui viene usato il dispositivo. API del servizio location Android e illustra come comunicare con il servizio di posizione di sistema usando un .LocationManager La seconda parte della guida esplora l'API di Servizi location Android usando .LocationManager

Come regola generale, le applicazioni devono preferire l'uso del provider di posizioni fuse, il fallback dell'API del servizio location Android precedente solo quando necessario.

Nozioni fondamentali sulla posizione

In Android, indipendentemente dall'API scelta per l'uso dei dati sulla posizione, diversi concetti rimangono invariati. Questa sezione presenta i provider di località e le autorizzazioni correlate alla posizione.

Provider di località

Diverse tecnologie vengono usate internamente per individuare la posizione dell'utente. L'hardware usato dipende dal tipo di provider di posizione selezionato per il processo di raccolta dei dati. Android usa tre provider di località:

  • Gps Provider – GPS offre la posizione più accurata, utilizza la potenza più potente, e funziona meglio all'aperto. Questo provider utilizza una combinazione di GPS e GPS assistito (aGPS), che restituisce i dati GPS raccolti dalle torri cellulari.

  • Provider di rete: fornisce una combinazione di dati Wi-Fi e Cellulare, inclusi i dati aGPS raccolti dalle torri di cella. Usa meno potenza del provider GPS, ma restituisce i dati sulla posizione di accuratezza variabile.

  • Provider passivo: opzione "piggyback" che usa provider richiesti da altre applicazioni o servizi per generare dati sulla posizione in un'applicazione. Si tratta di un'opzione meno affidabile ma di risparmio energia ideale per le applicazioni che non richiedono aggiornamenti di posizione costanti per funzionare.

I provider di località non sono sempre disponibili. Ad esempio, potremmo voler usare il GPS per la nostra applicazione, ma il GPS potrebbe essere spento in Impostazioni, o il dispositivo potrebbe non avere gps affatto. Se un provider specifico non è disponibile, la scelta di tale provider potrebbe restituire null.

Autorizzazioni per la posizione

Un'applicazione che riconosce la posizione deve accedere ai sensori hardware di un dispositivo per ricevere dati GPS, Wi-Fi e cellulare. L'accesso viene controllato tramite le autorizzazioni appropriate nel manifesto Android dell'applicazione. Sono disponibili due autorizzazioni: a seconda dei requisiti dell'applicazione e della scelta dell'API, si vuole consentire una:

  • ACCESS_FINE_LOCATION – Consente a un'applicazione di accedere al GPS. Obbligatorio per le opzioni Provider GPS e Provider passivo (il provider passivo deve disporre dell'autorizzazione per accedere ai dati GPS raccolti da un'altra applicazione o servizio). Autorizzazione facoltativa per il provider di rete.

  • ACCESS_COARSE_LOCATION – Consente a un'applicazione di accedere alla posizione Cellulare e Wi-Fi. Obbligatorio per il provider di rete se ACCESS_FINE_LOCATION non è impostato.

Per le app destinate all'API versione 21 (Android 5.0 Lollipop) o successive, è possibile abilitare ACCESS_FINE_LOCATION ed eseguire ancora nei dispositivi che non dispongono di hardware GPS. Se l'app richiede hardware GPS, è consigliabile aggiungere in modo esplicito un android.hardware.location.gpsuses-feature elemento al manifesto Android. Per altre informazioni, vedere le informazioni di riferimento sull'elemento uses-feature di Android.

Per impostare le autorizzazioni, espandere la cartella Proprietà nel riquadro della soluzione e fare doppio clic su AndroidManifest.xml. Le autorizzazioni verranno elencate in Autorizzazioni necessarie:

Screenshot delle impostazioni autorizzazioni necessarie per il manifesto Android

L'impostazione di una di queste autorizzazioni indica ad Android che l'applicazione necessita dell'autorizzazione dell'utente per accedere ai provider di posizioni. I dispositivi che eseguono il livello API 22 (Android 5.1) o versioni precedenti chiederanno all'utente di concedere queste autorizzazioni ogni volta che l'app è installata. Nei dispositivi che eseguono il livello API 23 (Android 6.0) o versione successiva, l'app deve eseguire un controllo delle autorizzazioni di runtime prima di effettuare una richiesta del provider di posizione.

Nota

Nota: l'impostazione ACCESS_FINE_LOCATION implica l'accesso ai dati di posizione grossolana e fine. Non è mai necessario impostare entrambe le autorizzazioni, ma solo l'autorizzazione minima richiesta dall'app.

Questo frammento di codice è un esempio di come verificare che un'app disponga dell'autorizzazione per l'autorizzazione ACCESS_FINE_LOCATION :

 if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.AccessFineLocation) == Permission.Granted)
{
    StartRequestingLocationUpdates();
    isRequestingLocationUpdates = true;
}
else
{
    // The app does not have permission ACCESS_FINE_LOCATION 
}

Le app devono essere tolleranti dello scenario in cui l'utente non concede l'autorizzazione (o ha revocato l'autorizzazione) e ha un modo per gestire correttamente tale situazione. Per altre informazioni sull'implementazione dei controlli delle autorizzazioni in fase di esecuzione in Xamarin.Android, vedere la Guida alle autorizzazioni.

Uso del provider di posizioni fuse

Il provider di posizioni fuse è il modo preferito per le applicazioni Android di ricevere gli aggiornamenti della posizione dal dispositivo perché selezionerà in modo efficiente il provider di posizione durante l'esecuzione per fornire le informazioni sulla posizione migliori in modo efficiente a batteria. Ad esempio, un utente che cammina all'aperto ottiene la migliore lettura della posizione con GPS. Se l'utente cammina in interni, dove GPS funziona male (se affatto), il provider di posizione fuso può passare automaticamente al WiFi, che funziona meglio al chiuso.

L'API del provider di posizioni fuse offre un'ampia gamma di altri strumenti per consentire alle applicazioni in grado di supportare la posizione, tra cui il geofencing e il monitoraggio delle attività. In questa sezione verranno descritti i concetti di base relativi alla configurazione LocationClientdi , alla definizione dei provider e alla posizione dell'utente.

Il provider di località fuse fa parte di Google Play Services. Il pacchetto di Google Play Services deve essere installato e configurato correttamente nell'applicazione per il funzionamento dell'API del provider di percorsi fusi e il dispositivo deve avere l'APK di Google Play Services installato.

Prima che un'applicazione Xamarin.Android possa usare il provider di percorsi fusi, deve aggiungere il pacchetto Xamarin.GooglePlayServices.Location al progetto. Inoltre, le istruzioni seguenti using devono essere aggiunte a tutti i file di origine che fanno riferimento alle classi descritte di seguito:

using Android.Gms.Common;
using Android.Gms.Location;

Verifica se Google Play Services è installato

Xamarin.Android si arresterà in modo anomalo se tenta di usare il provider di percorsi fusi quando Google Play Services non è installato (o non aggiornato), si verificherà un'eccezione di runtime. Se Google Play Services non è installato, l'applicazione deve eseguire il fallback al servizio location Android descritto in precedenza. Se Google Play Services non è aggiornato, l'app potrebbe visualizzare un messaggio all'utente che chiede di aggiornare la versione installata di Google Play Services.

Questo frammento di codice è un esempio di come un'attività Android può controllare a livello di codice se Google Play Services è installato:

bool IsGooglePlayServicesInstalled()
{
    var queryResult = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
    if (queryResult == ConnectionResult.Success)
    {
        Log.Info("MainActivity", "Google Play Services is installed on this device.");
        return true;
    }

    if (GoogleApiAvailability.Instance.IsUserResolvableError(queryResult))
    {
        // Check if there is a way the user can resolve the issue
        var errorString = GoogleApiAvailability.Instance.GetErrorString(queryResult);
        Log.Error("MainActivity", "There is a problem with Google Play Services on this device: {0} - {1}",
                  queryResult, errorString);

        // Alternately, display the error to the user.
    }

    return false;
}

FusedLocationProviderClient

Per interagire con il provider di percorsi fusi, un'applicazione Xamarin.Android deve avere un'istanza FusedLocationProviderClientdi . Questa classe espone i metodi necessari per sottoscrivere gli aggiornamenti della posizione e recuperare l'ultima posizione nota del dispositivo.

Il OnCreate metodo di un'attività è un luogo adatto per ottenere un riferimento a FusedLocationProviderClient, come illustrato nel frammento di codice seguente:

public class MainActivity: AppCompatActivity
{
    FusedLocationProviderClient fusedLocationProviderClient;

    protected override void OnCreate(Bundle bundle) 
    {
        fusedLocationProviderClient = LocationServices.GetFusedLocationProviderClient(this);
    }
}

Recupero dell'ultima posizione nota

Il FusedLocationProviderClient.GetLastLocationAsync() metodo fornisce un modo semplice e non di blocco per un'applicazione Xamarin.Android per ottenere rapidamente l'ultima posizione nota del dispositivo con un sovraccarico di codifica minimo.

Questo frammento di codice mostra come usare il GetLastLocationAsync metodo per recuperare la posizione del dispositivo:

async Task GetLastLocationFromDevice()
{
    // This method assumes that the necessary run-time permission checks have succeeded.
    getLastLocationButton.SetText(Resource.String.getting_last_location);
    Android.Locations.Location location = await fusedLocationProviderClient.GetLastLocationAsync();

    if (location == null)
    {
        // Seldom happens, but should code that handles this scenario
    }
    else
    {
        // Do something with the location 
        Log.Debug("Sample", "The latitude is " + location.Latitude);
    }
}

Sottoscrizione degli aggiornamenti della posizione

Un'applicazione Xamarin.Android può anche sottoscrivere gli aggiornamenti della posizione dal provider di percorsi fusi usando il FusedLocationProviderClient.RequestLocationUpdatesAsync metodo , come illustrato in questo frammento di codice:

await fusedLocationProviderClient.RequestLocationUpdatesAsync(locationRequest, locationCallback);

Questo metodo accetta due parametri:

  • Android.Gms.Location.LocationRequest : un LocationRequest oggetto è il modo in cui un'applicazione Xamarin.Android passa i parametri sul funzionamento del provider di percorsi fusi. Contiene LocationRequest informazioni quali la frequenza di esecuzione delle richieste o l'importanza di un aggiornamento accurato della posizione. Ad esempio, una richiesta di posizione importante causerà l'uso del GPS da parte del dispositivo e di conseguenza una maggiore potenza, quando si determina la posizione. Questo frammento di codice mostra come creare un LocationRequest oggetto per una posizione con accuratezza elevata, controllando circa ogni cinque minuti per un aggiornamento della posizione (ma non prima di due minuti tra le richieste). Il provider di posizioni fuse userà come LocationRequest materiale sussidiario per il provider di posizioni da usare quando si tenta di determinare la posizione del dispositivo:

    LocationRequest locationRequest = new LocationRequest()
                                      .SetPriority(LocationRequest.PriorityHighAccuracy)
                                      .SetInterval(60 * 1000 * 5)
                                      .SetFastestInterval(60 * 1000 * 2);
    
  • Android.Gms.Location.LocationCallback : per ricevere gli aggiornamenti della posizione, un'applicazione Xamarin.Android deve sottoclassare la LocationProvider classe astratta. Questa classe ha esposto due metodi che potrebbero essere richiamati dal provider di percorsi fusi per aggiornare l'app con le informazioni sulla posizione. Questo argomento verrà illustrato in modo più dettagliato di seguito.

Per notificare a un'applicazione Xamarin.Android un aggiornamento della posizione, il provider di percorsi fusi richiamerà .LocationCallBack.OnLocationResult(LocationResult result) Il Android.Gms.Location.LocationResult parametro conterrà le informazioni sul percorso di aggiornamento.

Quando il provider di posizioni fuse rileva una modifica nella disponibilità dei dati sulla posizione, chiama il LocationProvider.OnLocationAvailability(LocationAvailability locationAvailability) metodo . Se la LocationAvailability.IsLocationAvailable proprietà restituisce true, si può presumere che i risultati della posizione del dispositivo segnalati da OnLocationResult siano accurati e aggiornati come richiesto da LocationRequest. Se IsLocationAvailable è false, nessun risultato della posizione verrà restituito da OnLocationResult.

Questo frammento di codice è un'implementazione di esempio dell'oggetto LocationCallback :

public class FusedLocationProviderCallback : LocationCallback
{
    readonly MainActivity activity;

    public FusedLocationProviderCallback(MainActivity activity)
    {
        this.activity = activity;
    }

    public override void OnLocationAvailability(LocationAvailability locationAvailability)
    {
        Log.Debug("FusedLocationProviderSample", "IsLocationAvailable: {0}",locationAvailability.IsLocationAvailable);
    }

    public override void OnLocationResult(LocationResult result)
    {
        if (result.Locations.Any())
        {
            var location = result.Locations.First();
            Log.Debug("Sample", "The latitude is :" + location.Latitude);
        }
        else
        {
            // No locations to work with.
        }
    }
}

Uso dell'API del servizio di posizione Android

Android Location Service è un'API precedente per l'uso delle informazioni sulla posizione in Android. I dati sulla posizione vengono raccolti dai sensori hardware e raccolti da un servizio di sistema, a cui si accede nell'applicazione con una LocationManager classe e un oggetto ILocationListener.

Il servizio location è più adatto per le applicazioni che devono essere eseguite su dispositivi in cui Google Play Services non è installato.

Il servizio location è un tipo speciale di servizio gestito dal sistema. Un servizio di sistema interagisce con l'hardware del dispositivo ed è sempre in esecuzione. Per accedere agli aggiornamenti della posizione nell'applicazione, si sottoscriveranno gli aggiornamenti della posizione dal servizio di posizione del sistema usando una LocationManager chiamata e .RequestLocationUpdates

Per ottenere la posizione dell'utente usando il servizio posizione Android, sono necessari diversi passaggi:

  1. Ottenere un riferimento al LocationManager servizio.
  2. Implementare l'interfaccia ILocationListener e gestire gli eventi quando cambia la posizione.
  3. Utilizzare per richiedere gli aggiornamenti del LocationManager percorso per un provider specificato. L'oggetto ILocationListener del passaggio precedente verrà usato per ricevere i callback da LocationManager.
  4. Arrestare gli aggiornamenti della posizione quando l'applicazione non è più appropriata per ricevere gli aggiornamenti.

Location Manager

È possibile accedere al servizio di posizione del sistema con un'istanza della LocationManager classe . LocationManager è una classe speciale che consente di interagire con il servizio di posizione del sistema e di chiamare i metodi su di esso. Un'applicazione può ottenere un riferimento a LocationManager chiamando GetSystemService e passando un tipo di servizio, come illustrato di seguito:

LocationManager locationManager = (LocationManager) GetSystemService(Context.LocationService);

OnCreate è un buon posto per ottenere un riferimento a LocationManager. È consigliabile mantenere l'oggetto LocationManager come variabile di classe, in modo da poterlo chiamare in vari punti del ciclo di vita dell'attività.

Richiedere gli aggiornamenti della posizione da LocationManager

Una volta che l'applicazione ha un riferimento a LocationManager, deve indicare il LocationManager tipo di informazioni sulla posizione necessarie e la frequenza con cui tali informazioni devono essere aggiornate. Eseguire questa operazione chiamando RequestLocationUpdates sull'oggetto LocationManager e passando alcuni criteri per gli aggiornamenti e un callback che riceverà gli aggiornamenti del percorso. Questo callback è un tipo che deve implementare l'interfaccia ILocationListener (descritta più dettagliatamente più avanti in questa guida).

Il RequestLocationUpdates metodo indica al servizio di posizione di sistema che l'applicazione vuole iniziare a ricevere gli aggiornamenti della posizione. Questo metodo consente di specificare il provider, nonché le soglie di tempo e distanza per controllare la frequenza di aggiornamento. Ad esempio, il metodo seguente richiede aggiornamenti della posizione dal provider di posizione GPS ogni 2000 millisecondi e solo quando la posizione cambia più di 1 metro:

// For this example, this method is part of a class that implements ILocationListener, described below
locationManager.RequestLocationUpdates(LocationManager.GpsProvider, 2000, 1, this);

Un'applicazione deve richiedere gli aggiornamenti della posizione solo se necessario per ottenere prestazioni buone per l'applicazione. Questo mantiene la durata della batteria e crea un'esperienza migliore per l'utente.

Risposta agli aggiornamenti da LocationManager

Dopo che un'applicazione ha richiesto aggiornamenti da LocationManager, può ricevere informazioni dal servizio implementando l'interfaccia ILocationListener . Questa interfaccia fornisce quattro metodi per l'ascolto del servizio di posizione e del provider di posizione, OnLocationChanged. Il sistema chiamerà OnLocationChanged quando la posizione dell'utente cambia abbastanza da qualificarsi come posizione cambia in base al set di criteri quando si richiedono gli aggiornamenti della posizione.

Il codice seguente illustra i metodi nell'interfaccia ILocationListener :

public class MainActivity : AppCompatActivity, ILocationListener
{
    TextView latitude;
    TextView longitude;
    
    public void OnLocationChanged (Location location)
    {
        // called when the location has been updated.
    }
    
    public OnProviderDisabled(string locationProvider)
    {
        // called when the user disables the provider
    }
    
    public OnProviderEnabled(string locationProvider)
    {
        // called when the user enables the provider
    }
    
    public OnStatusChanged(string locationProvider, Availability status, Bundle extras)
    {
        // called when the status of the provider changes (there are a variety of reasons for this)
    }
}

Annullamento della sottoscrizione agli aggiornamenti di LocationManager

Per risparmiare risorse di sistema, un'applicazione deve annullare la sottoscrizione agli aggiornamenti della posizione il prima possibile. Il RemoveUpdates metodo indica a di interrompere l'invio LocationManager di aggiornamenti all'applicazione. Ad esempio, un'attività può chiamare RemoveUpdates nel OnPause metodo in modo che sia possibile risparmiare energia se un'applicazione non necessita di aggiornamenti della posizione mentre l'attività non è visualizzata sullo schermo:

protected override void OnPause ()
{
    base.OnPause ();
    locationManager.RemoveUpdates (this);
}

Se l'applicazione deve ottenere gli aggiornamenti della posizione in background, è necessario creare un servizio personalizzato che sottoscrive il servizio location di sistema. Per altre informazioni, vedere la guida Backgrounding with Android Services (Informazioni in background con i servizi Android).

Determinazione del provider di posizione migliore per LocationManager

L'applicazione precedente imposta GPS come provider di posizione. Tuttavia, il GPS potrebbe non essere disponibile in tutti i casi, ad esempio se il dispositivo è al chiuso o non ha un ricevitore GPS. In questo caso, il risultato è un null ritorno per provider.

Per ottenere il funzionamento dell'app quando il GPS non è disponibile, usa il metodo per richiedere il GetBestProvider provider di posizione migliore disponibile (supportato dal dispositivo e abilitato per l'utente) all'avvio dell'applicazione. Invece di passare un provider specifico, è possibile indicare GetBestProvider i requisiti per il provider, ad esempio l'accuratezza e l'alimentazione, con un Criteria oggetto . GetBestProvider restituisce il provider migliore per i criteri specificati.

Il codice seguente illustra come ottenere il provider migliore disponibile e usarlo quando si richiedono gli aggiornamenti del percorso:

Criteria locationCriteria = new Criteria();   
locationCriteria.Accuracy = Accuracy.Coarse;
locationCriteria.PowerRequirement = Power.Medium;

locationProvider = locationManager.GetBestProvider(locationCriteria, true);

if(locationProvider != null)
{
    locationManager.RequestLocationUpdates (locationProvider, 2000, 1, this);
}
else
{
    Log.Info(tag, "No location providers available");
}

Nota

Se l'utente ha disabilitato tutti i provider di percorsi, GetBestProvider restituirà null. Per vedere come funziona questo codice su un dispositivo reale, assicurarsi di abilitare GPS, Wi-Fi e reti cellulari in Google Impostazioni > Modalità posizione>, come illustrato in questo screenshot:

Impostazioni schermata Modalità posizione in un telefono Android

Lo screenshot seguente illustra l'applicazione di posizione in esecuzione usando GetBestProvider:

App GetBestProvider che visualizza latitudine, longitudine e provider

Tenere presente che GetBestProvider non cambia il provider in modo dinamico. Determina invece il provider più adatto una volta durante il ciclo di vita dell'attività. Se lo stato del provider cambia dopo l'impostazione, l'applicazione richiederà codice aggiuntivo nei ILocationListener metodi , OnProviderDisabledOnProviderEnabled, e OnStatusChanged , per gestire ogni possibilità correlata all'opzione del provider.

Riepilogo

Questa guida ha illustrato come ottenere la posizione dell'utente usando sia android Location Service che il provider di località fusi dall'API google Location Services.