Eine der besonderen Funktionen mobiler Apps ist die Standorterkennung. Wenn die Standorterkennung auf Mobilgeräten verwendet wird, bietet die App den Nutzern ein stärker kontextbezogenes Erlebnis.
Codebeispiele
Das ApiDemos-Repository auf GitHub enthält Beispiele, in denen die Verwendung der Standorterkennung auf einer Karte veranschaulicht wird:
Kotlin
- MyLocationDemoActivity: Verwendung der Ebene „Mein Standort“, einschließlich Laufzeitberechtigungen
- LocationSourceDemoActivity: Verwendung eines benutzerdefinierten
LocationSource
-Elements - CurrentPlaceDetailsOnMap: Ermittlung des aktuellen Standorts eines Android-Geräts und Angabe von Details zu diesem Ort (einem Unternehmen oder POI). Weitere Informationen finden Sie im Tutorial zum Einblenden aktueller Ortsdetails auf einer Karte.
Java
- MyLocationDemoActivity: Verwendung der Ebene „Mein Standort“, einschließlich Laufzeitberechtigungen
- LocationSourceDemoActivity: Verwendung eines benutzerdefinierten
LocationSource
-Elements - CurrentPlaceDetailsOnMap: Ermittlung des aktuellen Standorts eines Android-Geräts und Angabe von Details zu diesem Ort (einem Unternehmen oder POI). Weitere Informationen finden Sie im Tutorial zum Einblenden aktueller Ortsdetails auf einer Karte.
Mit Standortdaten arbeiten
Die für ein Android-Gerät verfügbaren Standortdaten beinhalten den aktuellen Standort des Geräts, der mithilfe verschiedener Technologien bestimmt wird, die Richtung und Methode der Fortbewegung sowie die Angabe, ob das Gerät über eine vordefinierte geografische Begrenzung, einen sogenannten Geofence, hinwegbewegt wurde. Je nach den Anforderungen Ihrer App können Sie zwischen verschiedenen Methoden zum Arbeiten mit Standortdaten wählen:
- Die Ebene Mein Standort bietet eine einfache Möglichkeit, den Standort eines Geräts auf der Karte anzuzeigen. Mit der Ebene werden keine Daten bereitgestellt.
- Wenn Standortdaten programmatisch angefordert werden sollen, empfehlen wir die Location API der Google Play-Dienste.
- Über die Schnittstelle
LocationSource
können Sie einen benutzerdefinierten Standortanbieter angeben.
Berechtigungen zur Standortermittlung
Wenn Ihre App Zugriff auf den Standort des Nutzers benötigt, müssen Sie die Berechtigung anfordern. Dazu fügen Sie Ihrer App die entsprechenden Android-Berechtigungen zur Standortermittlung hinzu.
In Android sind zwei Berechtigungen zur Standortermittlung verfügbar: ACCESS_COARSE_LOCATION
und ACCESS_FINE_LOCATION
. Die Genauigkeit des von der API zurückgegebenen Standorts richtet sich nach der ausgewählten Berechtigung.
android.permission.ACCESS_COARSE_LOCATION
: Damit kann die API den ungefähren Gerätestandort zurückgeben. Mit dieser Berechtigung erhalten Sie eine Schätzung des Gerätestandorts von den Standortdiensten, wie in der Dokumentation zur ungefähren Standortgenauigkeit beschrieben.android.permission.ACCESS_FINE_LOCATION
: Damit kann die API den Standort so genau wie möglich bestimmen. Dazu werden Daten von Standortanbietern wie GPS-Daten (Global Positioning System) sowie WLAN- und Mobilfunkdaten verwendet.
App-Manifest Berechtigungen hinzufügen
Wenn der ungefähre Standort für Ihre App ausreicht, fügen Sie die Berechtigung ACCESS_COARSE_LOCATION
in Ihre Manifestdatei ein:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp" > ... <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> ... </manifest>
Sollte der genaue Standort erforderlich sein, müssen Sie die Berechtigungen ACCESS_COARSE_LOCATION
und ACCESS_FINE_LOCATION
in die Manifestdatei aufnehmen:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp" > ... <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> ... </manifest>
Laufzeitberechtigungen anfordern
Mit Android 6.0 (Marshmallow) wird ein neues Modell zur Verwaltung von Berechtigungen eingeführt, das die Installation und Aktualisierung von Apps für Nutzer vereinfacht. Wenn Ihre App auf API-Level 23 oder höher ausgerichtet ist, können Sie das neue Berechtigungsmodell verwenden.
Falls Ihre App das neue Berechtigungsmodell unterstützt und auf dem Gerät Android 6.0 (Marshmallow) oder höher ausgeführt wird, muss der Nutzer beim Installieren oder Aktualisieren der App keine Berechtigungen erteilen. In der App muss geprüft werden, ob die erforderlichen Berechtigungen zur Laufzeit vorliegen. Ist das nicht der Fall, müssen diese Berechtigungen angefordert werden. Vom System wird ein kleines Fenster angezeigt, in dem der Nutzer aufgefordert wird, die Berechtigung zu erteilen.
Aus Gründen der Nutzerfreundlichkeit sollte die Berechtigung im entsprechenden Kontext angefordert werden. Wenn der Standort erforderlich ist, um die App nutzen zu können, sollte die Berechtigung beim Start der App angefordert werden. Eine gute Möglichkeit dazu ist ein freundlicher Begrüßungsbildschirm oder ein Assistent, der die Nutzer darüber informiert, warum die Berechtigung erforderlich ist.
Wenn die Berechtigung nur für einen Teil der App-Funktionen erforderlich ist, sollten Sie die Standortberechtigungen dann anfordern, wenn die entsprechende Aktion ausgeführt wird.
In der App muss angemessen auf die Entscheidung der Nutzer reagiert werden, wenn diese die Berechtigung nicht erteilen. Wenn die Berechtigung beispielsweise für eine bestimmte Funktion benötigt wird, kann die Funktion in der App deaktiviert werden. Ist eine Berechtigung für das Funktionieren der App an sich erforderlich, ist die gesamte Funktionalität der App betroffen. In diesem Fall wird der Nutzer informiert, dass er für das Verwenden der App die entsprechende Berechtigung erteilen muss.
Im folgenden Codebeispiel wird die Berechtigung mithilfe der AndroidX-Bibliothek überprüft, bevor die Ebene „Mein Standort“ aktiviert wird. Das Ergebnis dieser Anfrage wird dann verarbeitet, indem der ActivityCompat.OnRequestPermissionsResultCallback
aus der Support Library implementiert wird:
Kotlin
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.example.kotlindemos import android.Manifest import android.annotation.SuppressLint import android.content.pm.PackageManager import android.location.Location import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback import androidx.core.content.ContextCompat import com.example.kotlindemos.PermissionUtils.PermissionDeniedDialog.Companion.newInstance import com.example.kotlindemos.PermissionUtils.isPermissionGranted import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener import com.google.android.gms.maps.GoogleMap.OnMyLocationClickListener import com.google.android.gms.maps.OnMapReadyCallback import com.google.android.gms.maps.SupportMapFragment /** * This demo shows how GMS Location can be used to check for changes to the users location. The * "My Location" button uses GMS Location to set the blue dot representing the users location. * Permission for [Manifest.permission.ACCESS_FINE_LOCATION] and [Manifest.permission.ACCESS_COARSE_LOCATION] * are requested at run time. If either permission is not granted, the Activity is finished with an error message. */ class MyLocationDemoActivity : AppCompatActivity(), OnMyLocationButtonClickListener, OnMyLocationClickListener, OnMapReadyCallback, OnRequestPermissionsResultCallback { /** * Flag indicating whether a requested permission has been denied after returning in * [.onRequestPermissionsResult]. */ private var permissionDenied = false private lateinit var map: GoogleMap override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.my_location_demo) val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment? mapFragment?.getMapAsync(this) } override fun onMapReady(googleMap: GoogleMap) { map = googleMap googleMap.setOnMyLocationButtonClickListener(this) googleMap.setOnMyLocationClickListener(this) enableMyLocation() } /** * Enables the My Location layer if the fine location permission has been granted. */ @SuppressLint("MissingPermission") private fun enableMyLocation() { // 1. Check if permissions are granted, if so, enable the my location layer if (ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { map.isMyLocationEnabled = true return } // 2. If if a permission rationale dialog should be shown if (ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_FINE_LOCATION ) || ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_COARSE_LOCATION ) ) { PermissionUtils.RationaleDialog.newInstance( LOCATION_PERMISSION_REQUEST_CODE, true ).show(supportFragmentManager, "dialog") return } // 3. Otherwise, request permission ActivityCompat.requestPermissions( this, arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION ), LOCATION_PERMISSION_REQUEST_CODE ) } override fun onMyLocationButtonClick(): Boolean { Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT) .show() // Return false so that we don't consume the event and the default behavior still occurs // (the camera animates to the user's current position). return false } override fun onMyLocationClick(location: Location) { Toast.makeText(this, "Current location:\n$location", Toast.LENGTH_LONG) .show() } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray ) { if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) { super.onRequestPermissionsResult( requestCode, permissions, grantResults ) return } if (isPermissionGranted( permissions, grantResults, Manifest.permission.ACCESS_FINE_LOCATION ) || isPermissionGranted( permissions, grantResults, Manifest.permission.ACCESS_COARSE_LOCATION ) ) { // Enable the my location layer if the permission has been granted. enableMyLocation() } else { // Permission was denied. Display an error message // Display the missing permission error dialog when the fragments resume. permissionDenied = true } } override fun onResumeFragments() { super.onResumeFragments() if (permissionDenied) { // Permission was not granted, display error dialog. showMissingPermissionError() permissionDenied = false } } /** * Displays a dialog with error message explaining that the location permission is missing. */ private fun showMissingPermissionError() { newInstance(true).show(supportFragmentManager, "dialog") } companion object { /** * Request code for location permission request. * * @see .onRequestPermissionsResult */ private const val LOCATION_PERMISSION_REQUEST_CODE = 1 } }
Java
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.example.mapdemo; import android.Manifest.permission; import android.annotation.SuppressLint; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener; import com.google.android.gms.maps.GoogleMap.OnMyLocationClickListener; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import android.Manifest; import android.content.pm.PackageManager; import android.location.Location; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.widget.Toast; /** * This demo shows how GMS Location can be used to check for changes to the users location. The "My * Location" button uses GMS Location to set the blue dot representing the users location. * Permission for {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and {@link * android.Manifest.permission#ACCESS_COARSE_LOCATION} are requested at run time. If either * permission is not granted, the Activity is finished with an error message. */ public class MyLocationDemoActivity extends AppCompatActivity implements OnMyLocationButtonClickListener, OnMyLocationClickListener, OnMapReadyCallback, ActivityCompat.OnRequestPermissionsResultCallback { /** * Request code for location permission request. * * @see #onRequestPermissionsResult(int, String[], int[]) */ private static final int LOCATION_PERMISSION_REQUEST_CODE = 1; /** * Flag indicating whether a requested permission has been denied after returning in {@link * #onRequestPermissionsResult(int, String[], int[])}. */ private boolean permissionDenied = false; private GoogleMap map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.my_location_demo); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this); } @Override public void onMapReady(@NonNull GoogleMap googleMap) { map = googleMap; map.setOnMyLocationButtonClickListener(this); map.setOnMyLocationClickListener(this); enableMyLocation(); } /** * Enables the My Location layer if the fine location permission has been granted. */ @SuppressLint("MissingPermission") private void enableMyLocation() { // 1. Check if permissions are granted, if so, enable the my location layer if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { map.setMyLocationEnabled(true); return; } // 2. Otherwise, request location permissions from the user. PermissionUtils.requestLocationPermissions(this, LOCATION_PERMISSION_REQUEST_CODE, true); } @Override public boolean onMyLocationButtonClick() { Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT).show(); // Return false so that we don't consume the event and the default behavior still occurs // (the camera animates to the user's current position). return false; } @Override public void onMyLocationClick(@NonNull Location location) { Toast.makeText(this, "Current location:\n" + location, Toast.LENGTH_LONG).show(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); return; } if (PermissionUtils.isPermissionGranted(permissions, grantResults, Manifest.permission.ACCESS_FINE_LOCATION) || PermissionUtils .isPermissionGranted(permissions, grantResults, Manifest.permission.ACCESS_COARSE_LOCATION)) { // Enable the my location layer if the permission has been granted. enableMyLocation(); } else { // Permission was denied. Display an error message // Display the missing permission error dialog when the fragments resume. permissionDenied = true; } } @Override protected void onResumeFragments() { super.onResumeFragments(); if (permissionDenied) { // Permission was not granted, display error dialog. showMissingPermissionError(); permissionDenied = false; } } /** * Displays a dialog with error message explaining that the location permission is missing. */ private void showMissingPermissionError() { PermissionUtils.PermissionDeniedDialog .newInstance(true).show(getSupportFragmentManager(), "dialog"); } }
Ebene „Mein Standort“
Über die Ebene „Mein Standort“ und die Schaltfläche „Mein Standort“ können Sie dem Nutzer seinen aktuellen Standort zeigen. Rufen Sie mMap.setMyLocationEnabled()
auf, um die Ebene „Mein Standort“ auf der Karte zu aktivieren.
Im folgenden Beispiel wird eine einfache Verwendung der Ebene „Mein Standort“ veranschaulicht:
Kotlin
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.maps.example.kotlin import android.annotation.SuppressLint import android.location.Location import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.google.android.gms.maps.GoogleMap import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener import com.google.android.gms.maps.GoogleMap.OnMyLocationClickListener import com.google.android.gms.maps.OnMapReadyCallback import com.google.android.gms.maps.SupportMapFragment import com.google.maps.example.R internal class MyLocationLayerActivity : AppCompatActivity(), OnMyLocationButtonClickListener, OnMyLocationClickListener, OnMapReadyCallback { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_my_location) val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment mapFragment.getMapAsync(this) } @SuppressLint("MissingPermission") override fun onMapReady(map: GoogleMap) { // TODO: Before enabling the My Location layer, you must request // location permission from the user. This sample does not include // a request for location permission. map.isMyLocationEnabled = true map.setOnMyLocationButtonClickListener(this) map.setOnMyLocationClickListener(this) } override fun onMyLocationClick(location: Location) { Toast.makeText(this, "Current location:\n$location", Toast.LENGTH_LONG) .show() } override fun onMyLocationButtonClick(): Boolean { Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT) .show() // Return false so that we don't consume the event and the default behavior still occurs // (the camera animates to the user's current position). return false } }
Java
// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.maps.example; import android.annotation.SuppressLint; import android.location.Location; import android.os.Bundle; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; class MyLocationLayerActivity extends AppCompatActivity implements GoogleMap.OnMyLocationButtonClickListener, GoogleMap.OnMyLocationClickListener, OnMapReadyCallback { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_location); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this); } @SuppressLint("MissingPermission") @Override public void onMapReady(GoogleMap map) { // TODO: Before enabling the My Location layer, you must request // location permission from the user. This sample does not include // a request for location permission. map.setMyLocationEnabled(true); map.setOnMyLocationButtonClickListener(this); map.setOnMyLocationClickListener(this); } @Override public void onMyLocationClick(@NonNull Location location) { Toast.makeText(this, "Current location:\n" + location, Toast.LENGTH_LONG) .show(); } @Override public boolean onMyLocationButtonClick() { Toast.makeText(this, "MyLocation button clicked", Toast.LENGTH_SHORT) .show(); // Return false so that we don't consume the event and the default behavior still occurs // (the camera animates to the user's current position). return false; } }
Ist die Ebene „Mein Standort“ aktiviert, wird rechts oben auf der Karte die Schaltfläche „Mein Standort“ angezeigt. Wenn der Nutzer auf die Schaltfläche klickt, ändert die Kamera die Kartenansicht so, dass sich der aktuelle Standort des Geräts, sofern bekannt, in der Mitte der Karte befindet. Der Standort wird auf der Karte durch einen kleinen blauen Punkt gekennzeichnet, wenn das Gerät sich nicht bewegt, oder durch einen Navigationspfeil, wenn das Gerät in Bewegung ist.
Im folgenden Screenshot ist die Schaltfläche „Mein Standort“ oben rechts und der blaue Punkt „Mein Standort“ in der Mitte der Karte zu sehen:
Wenn die Schaltfläche „Mein Standort“ nicht angezeigt werden soll, rufen Sie UiSettings.setMyLocationButtonEnabled(false)
auf.
Ihre App kann auf folgende Ereignisse reagieren:
- Wenn der Nutzer auf die Schaltfläche „Mein Standort“ klickt, erhält die App einen
onMyLocationButtonClick()
-Callback vomGoogleMap.OnMyLocationButtonClickListener
. - Klickt der Nutzer auf den blauen Punkt für „Mein Standort“, erhält die App einen
onMyLocationClick()
-Callback vomGoogleMap.OnMyLocationClickListener
.
Die Location API der Google Play-Dienste
Die Location API der Google Play-Dienste ist die bevorzugte Methode, um die Standorterkennung in eine Android-App einzubinden. Sie bietet folgende Funktionen:
- Bestimmen des Gerätestandorts
- Beobachten von Standortänderungen mit einem Listener
- Bestimmen des Verkehrsmittels, wenn das Gerät in Bewegung ist
- Erstellen und Beobachten vordefinierter Regionen, sogenannter Geofences
Mithilfe von Standort-APIs lassen sich ganz leicht energieeffiziente Apps mit Standorterkennung erstellen. Die Location API wird genau wie das Maps SDK for Android als Teil des Google Play Services SDK bereitgestellt. Weitere Informationen zur Location API finden Sie im Android-Schulungskurs zu Standort-APIs und in der Referenz zur Location API. Das Google Play Services SDK enthält auch Codebeispiele.