Standortdienste unter Android
Dieser Leitfaden bietet eine Einführung in die Standortfunktionen in Android-Anwendungen und veranschaulicht, wie sich über die Standortdienst-API von Android sowie über den in der Standortdienste-API von Google verfügbaren Fused Location Provider der Standort eines Benutzers abrufen lässt.
Android bietet Zugriff auf verschiedene Technologien zur Standortbestimmung, z. B. auf die Funkturmtriangulation, die WLAN-basierte Ortung sowie die GPS-Ortung. Die Details der einzelnen Ortungstechnologien werden durch Standortanbieter abstrahiert, sodass Anwendungen unabhängig vom verwendeten Anbieter auf dieselbe Weise Standorte abrufen können. In diesem Leitfaden wird der Fused Location Provider vorgestellt. Diese Komponente von Google Play Services legt anhand der verfügbaren Anbieter und des Nutzungszwecks des Geräts auf intelligente Weise fest, wie der Standort am besten abgerufen wird. Des Weiteren wird die Standortdienst-API von Android eingeführt und erläutert, wie Sie mithilfe von LocationManager
mit dem Standortdienst des Systems kommunizieren. Im zweiten Teil des Leitfadens wird die Standortdienst-API von Android mithilfe von LocationManager
untersucht.
Die allgemeine Faustregel lautet, dass Anwendungen bevorzugt den Fused Location Provider verwenden und nur bei Bedarf auf die ältere Standortdienst-API von Android zurückfallen sollen.
Grundlagen zu den Standortdiensten
Unabhängig von der API, über die Sie unter Android mit Standortdaten arbeiten, gibt es einige Konzepte, die immer gleich bleiben. In diesem Abschnitt werden Standortanbieter und standortbezogene Berechtigungen vorgestellt.
Standortanbieter
Intern werden mehrere Technologien verwendet, um den Standort eines Benutzers zu ermitteln. Welche Hardware verwendet wird, hängt vom Typ des Standortanbieters ab, der für das Erfassen der Daten ausgewählt wurde. Unter Android werden die folgenden drei Standortanbieter eingesetzt:
GPS-Anbieter – GPS gibt die genaueste Position, verwendet die meiste Leistung und funktioniert am besten im Freien. Dieser Anbieter kombiniert normales und unterstütztes GPS (assisted GPS, aGPS). Letzteres gibt die von den Funktürmen erfassten GPS-Daten zurück.
Netzwerkanbieter – Bietet eine Kombination aus WLAN- und Mobilfunkdaten, einschließlich einer von Zelltürmen gesammeltenGPS-Daten. Der Netzwerkanbieter verbraucht weniger Strom als der GPS-Anbieter, gibt aber Standortdaten von unterschiedlicher Genauigkeit zurück.
Passiver Anbieter – Eine "Piggyback"-Option mit Anbietern, die von anderen Anwendungen oder Diensten angefordert werden, um Standortdaten in einer Anwendung zu generieren. Diese weniger zuverlässige, aber energiesparende Option eignet sich ideal für Anwendungen, für die keine konstanten Standortupdates erforderlich sind.
Standortanbieter sind nicht immer verfügbar. Selbst wenn Ihre Anwendung GPS verwenden soll, ist es möglich, dass die GPS-Funktion in den Einstellungen deaktiviert oder das Gerät nicht GPS-fähig ist. Wenn ein bestimmter Anbieter nicht verfügbar ist, wird nach dem Auswählen dieses Anbieters möglicherweise null
zurückgegeben.
Standortberechtigungen
Eine ortungsfähige Anwendung benötigt Zugriff auf die Hardwaresensoren eines Geräts, um GPS-, WLAN- und Mobilfunkdaten zu erhalten. Der Zugriff wird über die entsprechenden Berechtigungen im Android-Manifest der Anwendung gesteuert. Es stehen zwei Berechtigungen zur Verfügung – je nach den Anforderungen Ihrer Anwendung und ihrer Wahl der API möchten Sie eine zulassen:
ACCESS_FINE_LOCATION
– Ermöglicht einem Anwendungszugriff auf GPS. Diese Berechtigung ist für den GPS-Anbieter und den passiven Anbieter erforderlich (der passive Anbieter benötigt eine Berechtigung, um auf GPS-Daten zugreifen zu können, die von einer anderen Anwendung oder einem anderen Dienst gesammelt wurden). Die Berechtigung ist optional für den Netzwerkanbieter.ACCESS_COARSE_LOCATION
– Ermöglicht einem Anwendungszugriff auf den Mobilfunk- und WLAN-Standort. Die Berechtigung ist für den Netzwerkanbieter erforderlich, wennACCESS_FINE_LOCATION
nicht festgelegt ist.
Bei Apps, die auf API-Version 21 (Android 5.0 Lollipop) oder höher ausgerichtet sind, können Sie ACCESS_FINE_LOCATION
aktivieren und die Apps weiterhin auf Geräten ohne GPS-Hardware ausführen. Wenn Ihre App GPS-Hardware erfordert, sollten Sie dem Android-Manifest explizit ein android.hardware.location.gps
uses-feature
-Element hinzufügen. Weitere Informationen finden Sie in der Referenz zum Android-Element uses-feature.
Erweitern Sie zum Festlegen der Berechtigungen den Ordner Eigenschaften im Lösungspad, und doppelklicken Sie auf AndroidManifest.xml. Die Berechtigungen werden unter Erforderliche Berechtigungen aufgeführt:
Wenn Sie eine dieser Berechtigungen festlegen, teilen Sie Android dadurch mit, dass Ihre Anwendung die Berechtigung des Benutzers benötigt, um auf die Standortanbieter zugreifen zu können. Auf Geräten, die API-Ebene 22 (Android 5.1) oder niedriger ausführen, werden Benutzer bei jeder Installation der App dazu aufgefordert, diese Berechtigungen zu erteilen. Auf Geräten, auf denen API-Ebene 23 (Android 6.0) oder höher ausgeführt wird, muss die App eine Berechtigungsüberprüfung zur Laufzeit durchführen, bevor Sie eine Anforderung an den Standortanbieter sendet.
Hinweis
Hinweis: Die Einstellung ACCESS_FINE_LOCATION
impliziert den Zugriff auf grobe und feine Standortdaten. Sie sollten niemals beide Berechtigungen festlegen müssen, sondern nur die minimale Berechtigung, die Ihre App zum Funktionieren benötigt.
Der folgende Codeausschnitt zeigt beispielhaft, wie Sie überprüfen können, ob eine App über die Berechtigung für die Berechtigung ACCESS_FINE_LOCATION
verfügt:
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.AccessFineLocation) == Permission.Granted)
{
StartRequestingLocationUpdates();
isRequestingLocationUpdates = true;
}
else
{
// The app does not have permission ACCESS_FINE_LOCATION
}
Apps müssen auch auf das Szenario ausgelegt sein, dass der Benutzer keine Berechtigungen erteilt (oder die Berechtigung widerruft), und mit dieser Situation umgehen können. Weitere Informationen zu Laufzeitüberprüfungen von Berechtigungen in Xamarin.Android finden Sie unter Berechtigungen in Xamarin.Android.
Verwenden des Fused Location Providers
Der Fused Location Provider ist die bevorzugte Methode für die Bereitstellung von Standortupdates für Android-Anwendungen auf einem Gerät. Der Grund ist, dass der Standortanbieter effizient zur Laufzeit ausgewählt wird, um die besten Standortinformationen auf batterieeffiziente Weise bereitzustellen. Ein Benutzer, der im Freien unterwegs ist, erhält beispielsweise die zuverlässigsten Standortdaten per GPS. Wenn der Benutzer dann ein Gebäude betritt, wo GPS (wenn überhaupt) nur schlecht funktioniert, kann der Fused Location Provider automatisch zur WLAN-basierten Ortung wechseln, da diese in geschlossenen Räumen zuverlässiger ist.
Die Fused Location Provider-API enthält eine Vielzahl anderer Tools wie Geofencing und Aktivitätsüberwachung, die ortungsfähige Anwendungen optimieren. In diesem Abschnitt geht es um die Grundlagen der Einrichtung von LocationClient
und von Anbietern sowie um das Abrufen des Benutzerstandorts.
Der Fused Location Provider ist Teil von Google Play Services. Das Google Play Services-Paket muss in der Anwendung installiert und ordnungsgemäß konfiguriert sein, damit die Fused Location Provider-API funktioniert. Außerdem muss auf dem Gerät das Google Play Services-APK installiert sein.
Bevor eine Xamarin.Android-Anwendung den Fused Location Provider verwenden kann, muss sie dem Projekt das Paket Xamarin.GooglePlayServices.Location hinzufügen. Außerdem sollten allen Quelldateien, die auf die nachfolgend beschriebenen Klassen verweisen, die folgenden using
-Anweisungen hinzugefügt werden:
using Android.Gms.Common;
using Android.Gms.Location;
Überprüfen der Installation von Google Play Services
Eine Xamarin.Android-Anwendung stürzt ab, wenn sie versucht, den Fused Location Provider zu verwenden, obwohl Google Play Services nicht installiert (oder veraltet) ist. In diesem Fall tritt eine Runtimeausnahme auf. Wenn Google Play Services nicht installiert ist, sollte die Anwendung ein Fallback auf den zuvor erwähnten Android-Standortdienst durchführen. Wenn die installierte Version von Google Play Services veraltet ist, kann die App dem Benutzer eine Meldung mit der Aufforderung anzeigen, die installierte Version von Google Play Services zu aktualisieren.
Der folgende Codeausschnitt zeigt beispielhaft, wie eine Activity-Klasse unter Android programmgesteuert überprüfen kann, ob Google Play Services installiert ist:
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
Eine Xamarin.Android-Anwendung muss über eine Instanz von FusedLocationProviderClient
verfügen, um mit dem Fused Location Provider interagieren zu können. Diese Klasse macht die erforderlichen Methoden zum Abonnieren von Standortupdates und zum Abrufen des letzten bekannten Gerätestandorts verfügbar.
Die Methode OnCreate
der Activity-Klasse ist die geeignete Stelle, um einen Verweis auf FusedLocationProviderClient
abzurufen. Dies wird im nachfolgenden Codeausschnitt veranschaulicht:
public class MainActivity: AppCompatActivity
{
FusedLocationProviderClient fusedLocationProviderClient;
protected override void OnCreate(Bundle bundle)
{
fusedLocationProviderClient = LocationServices.GetFusedLocationProviderClient(this);
}
}
Abrufen des zuletzt bekannten Standorts
Die Methode FusedLocationProviderClient.GetLastLocationAsync()
bietet eine einfache, nicht blockierende Methode für Xamarin.Android-Anwendungen dar, den letzten bekannten Gerätestandort mit minimalem Programmieraufwand schnell abzurufen.
In diesem Codeausschnitt wird gezeigt, wie Sie mit der Methode GetLastLocationAsync
den Standort eines Geräts abrufen:
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);
}
}
Abonnieren von Standortupdates
Eine Xamarin.Android-Anwendung kann auch Standortupdates vom fused Location Provider mithilfe der FusedLocationProviderClient.RequestLocationUpdatesAsync
Methode abonnieren, wie in diesem Codeausschnitt gezeigt:
await fusedLocationProviderClient.RequestLocationUpdatesAsync(locationRequest, locationCallback);
Diese Methode nimmt zwei Parameter:
Android.Gms.Location.LocationRequest
– EinLocationRequest
Objekt ist, wie eine Xamarin.Android-Anwendung die Parameter übergibt, wie der anbieter für fused-Speicherorte funktionieren soll.LocationRequest
enthält z. B. Informationen dazu, wie häufig Anforderungen gesendet werden sollten oder wie wichtig ein genaues Standortupdate sein soll. Für ein wichtiges Standortupdate verwendet das Gerät beispielsweise GPS und verbraucht folglich auch mehr Akkuleistung beim Bestimmen des Standorts. In diesem Codeausschnitt wird gezeigt, wie Sie einLocationRequest
-Objekt für einen Standort mit hoher Genauigkeit erstellen, das etwa alle fünf Minuten auf ein Standortupdate prüft (aber nicht, bevor nicht mindestens zwei Minuten zwischen Anforderungen vergangen sind). Der Fused Location Provider wählt beim Ermitteln des Gerätestandorts anhand einesLocationRequest
-Objekts den Standortanbieter aus:LocationRequest locationRequest = new LocationRequest() .SetPriority(LocationRequest.PriorityHighAccuracy) .SetInterval(60 * 1000 * 5) .SetFastestInterval(60 * 1000 * 2);
Android.Gms.Location.LocationCallback
– Um Standortupdates zu erhalten, muss eine Xamarin.Android-Anwendung dieLocationProvider
abstrakte Klasse unterklassen. Diese Klasse macht zwei Methoden verfügbar, die vom Fused Location Provider aufgerufen werden können, um die App mit neuen Standortinformationen zu versorgen. Dies wird in später in diesem Artikel ausführlicher erläutert.
Der Fused Location Provider ruft LocationCallBack.OnLocationResult(LocationResult result)
auf, um ein Standortupdate an eine Xamarin.Android-Anwendung weiterzugeben. Der Parameter Android.Gms.Location.LocationResult
enthält die Informationen zum aktualisierten Standort.
Wenn der Fused Location Provider eine Änderung bei der Verfügbarkeit von Standortdaten erkennt, wird die Methode LocationProvider.OnLocationAvailability(LocationAvailability locationAvailability)
aufgerufen. Wenn die Eigenschaft LocationAvailability.IsLocationAvailable
den Wert true
zurückgibt, kann davon ausgegangen werden, dass die von OnLocationResult
gemeldeten Gerätestandortergebnisse so genau und aktuell sind, wie vom LocationRequest
-Objekt gefordert. Wenn IsLocationAvailable
FALSE ist, werden von OnLocationResult
keine Standortergebnisse zurückgegeben.
Dieser Codeausschnitt zeigt eine Beispielimplementierung des LocationCallback
-Objekts:
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.
}
}
}
Verwenden der Standortdienst-API von Android
Der Android-Standortdienst ist eine ältere API für die Verwendung von Standortinformationen unter Android. Standortdaten werden von Hardwaresensoren erfasst und von einem Systemdienst gesammelt, auf den in der Anwendung mit einer LocationManager
-Klasse und einem ILocationListener
zugegriffen wird.
Der Standortdienst eignet sich am besten für Anwendungen, die auf Geräten ausgeführt werden müssen, auf denen Google Play Services nicht installiert ist.
Der Standortdienst ist eine besondere Art von Dienst, der vom System verwaltet wird. Ein Systemdienst interagiert mit der Gerätehardware und wird immer ausgeführt. Damit Ihre Anwendung Standortupdates abrufen kann, müssen Sie Standortsupdates mithilfe eines LocationManager
- und eines RequestLocationUpdates
-Aufrufs beim Standortdienst des Systems abonnieren.
Das Abrufen eines Benutzerstandorts mithilfe des Android-Standortdiensts umfasst mehrere Schritte:
- Rufen Sie einen Verweis auf den
LocationManager
-Dienst ab. - Implementieren Sie die Schnittstelle
ILocationListener
, und lassen Sie Ereignisse verarbeiten, wenn sich der Standort ändert. - Fordern Sie mit
LocationManager
Standortupdates für einen angegebenen Anbieter an.ILocationListener
aus dem vorherigen Schritt wird dazu verwendet, Rückrufe vonLocationManager
zu empfangen. - Beenden Sie die Standortupdates, wenn die Anwendung nicht mehr für den Empfang von Updates geeignet ist.
LocationManager
Der Zugriff auf den Standortdienst des Systems ist mit einer Instanz der Klasse LocationManager
möglich. LocationManager
ist eine besondere Klasse, die die Interaktion mit dem Standortdienst des Systems und das Aufrufen Methoden für den Standortdienst ermöglicht. Eine Anwendung kann einen Verweis auf LocationManager
abrufen, indem sie GetSystemService
aufruft und so wie unten dargestellt einen Diensttyp übergibt:
LocationManager locationManager = (LocationManager) GetSystemService(Context.LocationService);
OnCreate
ist die geeignete Methode, um einen Verweis auf LocationManager
abzurufen.
Es empfiehlt sich, LocationManager
als Klassenvariable beizubehalten, damit Sie sie an verschiedenen Stellen im Activity-Lebenszyklus abrufen können.
Anfordern von Standortupdates von LocationManager
Sobald die Anwendung über einen Verweis auf LocationManager
verfügt, muss sie LocationManager
darüber informieren, welche Art von Standortinformationen erforderlich sind und wie oft diese Informationen aktualisiert werden sollen. Rufen Sie hierzu RequestLocationUpdates
für das LocationManager
-Objekt auf, und übergeben Sie einige Updatekriterien und einen Rückruf, der die Standortupdates empfängt. Dieser Rückruf ist ein Typ, der die Schnittstelle ILocationListener
implementieren muss (wird weiter unten in diesem Leitfaden ausführlicher beschrieben).
Die Methode RequestLocationUpdates
teilt dem Standortdienst des Systems mit, dass Ihre Anwendung bereit ist, Standortupdates zu empfangen. Mit dieser Methode können Sie den Anbieter sowie Zeit- und Entfernungsschwellenwerte angeben, um die Updatehäufigkeit zu steuern. Die nachfolgende Methode fordert beispielsweise alle 2.000 Millisekunden Standortupdates vom GPS-Standortanbieter an, und zwar nur dann, wenn sich der Standort um mehr als einen Meter ändert:
// For this example, this method is part of a class that implements ILocationListener, described below
locationManager.RequestLocationUpdates(LocationManager.GpsProvider, 2000, 1, this);
Eine Anwendung sollte Standortupdates nur so oft anfordern, wie dies für eine gute Anwendungsleistung erforderlich ist. Dies schont die Akkulaufzeit und sorgt für ein besseres Benutzererlebnis.
Antworten auf Updates von LocationManager
Nachdem eine Anwendung Updates von LocationManager
angefordert hat, kann sie Informationen vom Dienst empfangen, indem sie die Schnittstelle ILocationListener
implementiert. Diese Schnittstelle stellt vier Methoden für das Lauschen am Standortdienst und am Standortanbieter (OnLocationChanged
) bereit. Das System ruft OnLocationChanged
auf, wenn sich der Standort des Benutzers so deutlich ändert, dass gemäß dem Kriterienset für das Anfordern von Standortupdates eine Standortänderung vorliegt.
Der folgende Code zeigt die Methoden in der ILocationListener
Schnittstelle:
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)
}
}
Abbestellen von LocationManager-Updates
Zum Einsparen von Systemressourcen sollte eine Anwendung Standortupdates so bald wie möglich abbestellen. Die Methode RemoveUpdates
informiert LocationManager
darüber, das keine Updates mehr an Ihre Anwendung gesendet werden sollen. Beispielsweise kann eine Aktivität in der OnPause
Methode aufgerufen RemoveUpdates
werden, damit wir Energie sparen können, wenn eine Anwendung keine Positionsaktualisierungen benötigt, während sich die Aktivität nicht auf dem Bildschirm befindet:
protected override void OnPause ()
{
base.OnPause ();
locationManager.RemoveUpdates (this);
}
Wenn Ihre Anwendung Standortupdates abrufen muss, während sie im Hintergrund ausgeführt wird, sollten Sie einen benutzerdefinierten Dienst erstellen, der den Standortdienst des Systems abonniert. Weitere Informationen finden Sie im Leitfaden Erstellen von Android-Diensten.
Ermitteln des optimalen Standortanbieters für LocationManager
Die zuvor beschriebene Anwendung legt GPS als Standortanbieter fest. Das GPS-Signal ist jedoch möglicherweise nicht in allen Situationen verfügbar, z. B. wenn sich das Gerät in geschlossenen Räumen befindet oder nicht über einen GPS-Empfänger verfügt. Wenn dies der Fall ist, wird null
für den Anbieter zurückgegeben.
Damit Ihre App auch dann funktioniert, wenn kein GPS-Signal verfügbar ist, müssen Sie mit der Methode GetBestProvider
beim Anwendungsstart den besten verfügbaren Standortanbieter abrufen (der vom Gerät unterstützt wird und vom Benutzer aktiviert wurde). Anstatt einen bestimmten Anbieter zu übergeben, können Sie in der Methode GetBestProvider
mit einem Criteria
-Objekt die Anforderungen für den Anbieter angeben, z. B. Genauigkeit und Stromverbrauch. GetBestProvider
gibt den besten Anbieter für die angegebenen Kriterien zurück.
Der folgende Code zeigt, wie Sie den besten verfügbaren Anbieter abrufen können und ihn bei der Anforderung von Standortupdates verwenden:
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");
}
Hinweis
Wenn der Benutzer alle Standortanbieter deaktiviert hat, gibt GetBestProvider
den Wert null
zurück. Um zu sehen, wie dieser Code auf einem echten Gerät funktioniert, stellen Sie sicher, dass Sie GPS, WLAN und Mobilfunknetze unter dem Google Settings > Location > Mode aktivieren, wie in diesem Screenshot gezeigt:
Im folgenden Screenshot wird die Standortanwendung gezeigt, die mit GetBestProvider
ausgeführt wird:
Beachten Sie, dass GetBestProvider
den Anbieter nicht dynamisch ändert. Stattdessen wird der beste verfügbare Anbieter einmal während des Activity-Lebenszyklus bestimmt. Wenn sich der Anbieterstatus nach dem Festlegen ändert, benötigt die Anwendung zusätzlichen Code in den ILocationListener
Methoden – OnProviderEnabled
, OnProviderDisabled
und OnStatusChanged
– um jede Möglichkeit im Zusammenhang mit dem Anbieterwechsel zu behandeln.
Zusammenfassung
In diesem Leitfaden wurde das Abrufen von Benutzerstandorten mit dem Android-Standortdienst und dem Fused Location Provider aus der Standortdienste-API von Google behandelt.