Xamarin.Essentials: Geolocalización

La clase Geolocation proporciona las API para recuperar las coordenadas de geolocalización actuales del dispositivo.

Primeros pasos

Para empezar a usar esta API, lea la guía de introducción para Xamarin.Essentials con el fin de asegurarse de que la biblioteca está correctamente instalada y configurada en los proyectos.

Para acceder a la funcionalidad de Geolocation, se requiere la siguiente configuración específica para la plataforma:

Los permisos Coarse y Fine Location son requeridos y se deben configurar en el proyecto de Android. Además, si la aplicación tiene como destino Android 5.0 (nivel de API 21) o versiones posteriores, debe declarar que la aplicación usa las características de hardware en el archivo de manifiesto. Se puede agregar de las siguientes maneras:

Abra el archivo AssemblyInfo.cs de la carpeta Propiedades y agregue lo siguiente:

[assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessFineLocation)]
[assembly: UsesFeature("android.hardware.location", Required = false)]
[assembly: UsesFeature("android.hardware.location.gps", Required = false)]
[assembly: UsesFeature("android.hardware.location.network", Required = false)]

O bien, actualice el manifiesto de Android:

Abra el archivo AndroidManifest.xml de la carpeta Propiedades y agregue lo siguiente dentro del nodo manifest:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false" />

O bien, haga clic con el botón derecho en el proyecto de Android y abra las propiedades del proyecto. En Manifiesto de Android, busque el área Permisos requeridos: y active los permisos ACCESS_COARSE_LOCATION y ACCESS_FINE_LOCATION. Esto actualizará automáticamente el archivo AndroidManifest.xml.

Si su aplicación tiene como destino Android 10-Q (nivel de API 29 o superior) y solicita LocationAlways, debe agregar también el siguiente permiso en AssemblyInfo.cs:

[assembly: UsesPermission(Manifest.Permission.AccessBackgroundLocation)]

O directamente en el AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Se recomienda leer la documentación de Android sobre las actualizaciones de la ubicación en segundo plano, ya que hay muchas restricciones que deben tenerse en cuenta.

Esta API usa permisos en tiempo de ejecución en Android. Asegúrese de que Xamarin.Essentials se haya inicializado por completo y de que el control de permisos esté configurado en la aplicación.

En el elemento MainLauncher del proyecto de Android o cualquier Activity que se inicie, Xamarin.Essentials se debe inicializar en el método OnCreate:

protected override void OnCreate(Bundle savedInstanceState) 
{
    //...
    base.OnCreate(savedInstanceState);
    Xamarin.Essentials.Platform.Init(this, savedInstanceState); // add this line to your code, it may also be called: bundle
    //...
}    

Para controlar los permisos en tiempo de ejecución de Android, Xamarin.Essentials debe recibir cualquier OnRequestPermissionsResult. Agregue el código siguiente a todas las clases Activity:

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults)
{
    Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

Uso de Geolocation

Agregue una referencia a Xamarin.Essentials en la clase:

using Xamarin.Essentials;

La API Geolocation también le pedirá permisos al usuario cuando sea necesario.

Puede obtener la última ubicación conocida del dispositivo mediante una llamada al método GetLastKnownLocationAsync. A menudo, esto es más rápido que hacer una consulta completa, pero puede ser menos preciso y probablemente devuelva null si no existe ninguna ubicación en caché.

try
{
    var location = await Geolocation.GetLastKnownLocationAsync();

    if (location != null)
    {
        Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
    }
}
catch (FeatureNotSupportedException fnsEx)
{
    // Handle not supported on device exception
}
catch (FeatureNotEnabledException fneEx)
{
    // Handle not enabled on device exception
}
catch (PermissionException pEx)
{
    // Handle permission exception
}
catch (Exception ex)
{
    // Unable to get location
}

Para consultar las coordenadas de ubicación del dispositivo actual, se puede usar GetLocationAsync. Es mejor pasar un valor GeolocationRequest completo y CancellationToken, ya que se puede tardar algún tiempo en obtener la ubicación del dispositivo.

CancellationTokenSource cts;

async Task GetCurrentLocation()
{
    try
    {
        var request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromSeconds(10));
        cts = new CancellationTokenSource();
        var location = await Geolocation.GetLocationAsync(request, cts.Token);

        if (location != null)
        {
            Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
        }
    }
    catch (FeatureNotSupportedException fnsEx)
    {
        // Handle not supported on device exception
    }
    catch (FeatureNotEnabledException fneEx)
    {
        // Handle not enabled on device exception
    }
    catch (PermissionException pEx)
    {
        // Handle permission exception
    }
    catch (Exception ex)
    {
        // Unable to get location
    }
}

protected override void OnDisappearing()
{
    if (cts != null && !cts.IsCancellationRequested)
        cts.Cancel();
    base.OnDisappearing();
}

Tenga en cuenta que todos los valores pueden estar disponibles debido al modo en que cada dispositivo consulta la geolocalización mediante diferentes proveedores. Por ejemplo, la propiedad Altitude podría ser null o tener un valor de 0 o positivo(por encima del nivel del mar). Otros valores que pueden no estar presentes son, entre otros, Speed y Course.

Precisión de la ubicación geográfica

En la tabla siguiente se describe la precisión por plataforma:

Mínima

Plataforma Distancia (en metros)
Android 500
iOS 3000
UWP 1000 - 5000

Bajo

Plataforma Distancia (en metros)
Android 500
iOS 1000
UWP 300 - 3000

Media (valor predeterminado)

Plataforma Distancia (en metros)
Android 100 - 500
iOS 100
UWP 30-500

Alto

Plataforma Distancia (en metros)
Android 0 - 100
iOS 10
UWP <= 10

Óptima

Plataforma Distancia (en metros)
Android 0 - 100
iOS ~0
UWP <= 10

Detección de ubicaciones ficticias

Algunos dispositivos pueden devolver una ubicación ficticia desde el proveedor o desde una aplicación que proporciona ubicaciones ficticias. Puede detectarlo usando IsFromMockProvider en cualquier Location.

var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);

if (location != null)
{
    if(location.IsFromMockProvider)
    {
        // location is from a mock provider
    }
}

Distancia entre dos ubicaciones

Las clases Location y LocationExtensions definen métodos CalculateDistance que permiten calcular la distancia entre dos ubicaciones geográficas. Esta distancia calculada no tiene en cuenta las carreteras ni otros caminos, y simplemente es la distancia más corta entre los dos puntos a lo largo de la superficie de la Tierra, lo que también se conoce como distancia ortodrómica o coloquialmente, "distancia a vuelo de pájaro".

Por ejemplo:

Location boston = new Location(42.358056, -71.063611);
Location sanFrancisco = new Location(37.783333, -122.416667);
double miles = Location.CalculateDistance(boston, sanFrancisco, DistanceUnits.Miles);

El constructor Location tiene argumentos de latitud y longitud en ese orden. Los valores de latitud positivos están al norte del Ecuador, y los valores de longitud positivos están al este del meridiano de Greenwich. Use el argumento final CalculateDistance para especificar millas o kilómetros. La clase UnitConverters también define los métodos KilometersToMiles y MilesToKilometers para la conversión entre las dos unidades.

Diferencias entre plataformas

La altitud se calcula de forma diferente en cada plataforma.

En Android, la altitud, si está disponible, se devuelve en metros por encima del elipsoide de referencia WGS 84. Si esta ubicación no tiene ninguna altitud, se devuelve 0.

API

Encuentre más vídeos de Xamarin en Channel 9 y YouTube.