Una delle caratteristiche uniche delle applicazioni mobile è il rilevamento della posizione. Gli utenti di dispositivi mobili portano sempre con sé i propri dispositivi e l'aggiunta della funzionalità di rilevamento della posizione alla tua app offre agli utenti un'esperienza più contestuale.
Esempi di codice
Il repository ApiDemos su GitHub include esempi che dimostrano l'uso della posizione su una mappa:
Java
- MyLocationDemoActivity: utilizzo del livello La mia posizione, incluse le autorizzazioni di runtime
- LocationSourceDemoActivity: utilizzo di un elemento
LocationSource
personalizzato - CurrentPlaceDetailsOnMap: ricerca della posizione attuale di un dispositivo Android e visualizzazione dei dettagli del luogo (attività commerciale o altro punto d'interesse) in quella posizione. Guarda il tutorial su come mostrare i dettagli del luogo attuale sulla mappa.
Kotlin
- MyLocationDemoActivity: utilizzo del livello La mia posizione, incluse le autorizzazioni di runtime
- LocationSourceDemoActivity: utilizzo di un elemento
LocationSource
personalizzato - CurrentPlaceDetailsOnMap: ricerca della posizione attuale di un dispositivo Android e visualizzazione dei dettagli del luogo (attività commerciale o altro punto d'interesse) in quella posizione. Guarda il tutorial su come mostrare i dettagli del luogo attuale sulla mappa.
Utilizzare i dati sulla posizione
I dati sulla posizione disponibili per un dispositivo Android includono la posizione attuale del dispositivo, individuata mediante una combinazione di tecnologie, la direzione e il metodo di spostamento e se il dispositivo si è spostato attraverso un confine geografico predefinito o un recinto virtuale. A seconda delle esigenze della tua applicazione, puoi scegliere tra diversi modi di utilizzare i dati sulla posizione:
- Il livello La mia posizione consente di visualizzare facilmente la posizione di un dispositivo sulla mappa. Non fornisce dati.
- L'API Google Play Services Location è consigliata per tutte le richieste di pubblicità programmatica per i dati sulla posizione.
- L'interfaccia di
LocationSource
ti consente di fornire un provider di località personalizzato.
Autorizzazioni di accesso alla posizione
Se la tua app deve accedere alla posizione dell'utente, devi richiedere l'autorizzazione aggiungendo all'app le autorizzazioni di accesso alla posizione pertinenti per Android.
Android offre due autorizzazioni di accesso alla posizione: ACCESS_COARSE_LOCATION
e ACCESS_FINE_LOCATION
. L'autorizzazione scelta determina l'accuratezza della posizione restituita dall'API.
android.permission.ACCESS_COARSE_LOCATION
- Consente all'API di restituire la posizione approssimativa del dispositivo. L'autorizzazione fornisce una stima della posizione del dispositivo dai servizi di geolocalizzazione, come descritto nella documentazione sulla precisione approssimativa della posizione.android.permission.ACCESS_FINE_LOCATION
– Consente all'API di determinare una posizione il più precisa possibile in base ai fornitori di servizi di localizzazione disponibili, tra cui il sistema GPS e il Wi-Fi e i dati cellulare.
Aggiungi le autorizzazioni al file manifest dell'app
Se è necessaria solo la posizione approssimativa per il funzionamento della tua app, aggiungi l'autorizzazione ACCESS_COARSE_LOCATION
al file manifest dell'app:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp" > ... <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> ... </manifest>
Tuttavia, se è necessaria la posizione esatta, aggiungi entrambe le autorizzazioni ACCESS_COARSE_LOCATION
e ACCESS_FINE_LOCATION
al file manifest dell'app:
<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>
Richiedi autorizzazioni di runtime
Android 6.0 (Marshmallow) introduce un nuovo modello per la gestione delle autorizzazioni, che semplifica il processo per gli utenti che installano ed eseguono l'upgrade delle app. Se la tua app ha come target il livello API 23 o versioni successive, puoi utilizzare il nuovo modello di autorizzazioni.
Se la tua app supporta il nuovo modello di autorizzazioni e il dispositivo esegue Android 6.0 (Marshmallow) o versioni successive, l'utente non deve concedere alcuna autorizzazione quando installa o esegue l'upgrade dell'app. L'app deve verificare se dispone dell'autorizzazione necessaria in runtime e richiederla, se non l'ha. Il sistema mostra all'utente una finestra di dialogo per richiedere l'autorizzazione.
Per un'esperienza utente ottimale, è importante richiedere l'autorizzazione nel contesto. Se la posizione è essenziale per il funzionamento della tua app, devi richiedere l'autorizzazione di accesso alla posizione all'avvio dell'app. Un buon modo per farlo è utilizzare una schermata di benvenuto o una procedura guidata che spieghi agli utenti perché è richiesta l'autorizzazione.
Se l'app richiede l'autorizzazione solo per una parte della sua funzionalità, devi richiedere l'autorizzazione di accesso alla posizione nel momento in cui l'app esegue l'azione che richiede l'autorizzazione.
L'app deve gestire correttamente il caso in cui l'utente non concede l'autorizzazione. Ad esempio, se l'autorizzazione è necessaria per una funzionalità specifica, l'app può disattivarla. Se l'autorizzazione è essenziale per il funzionamento dell'app, quest'ultima può disattivarne tutte le funzionalità e comunicare all'utente che deve concedere l'autorizzazione.
Il seguente esempio di codice verifica l'autorizzazione utilizzando la libreria AndroidX prima di attivare il livello La mia posizione. Gestisce quindi il risultato della richiesta di autorizzazione implementando ActivityCompat.OnRequestPermissionsResultCallback
dalla libreria di assistenza:
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"); } }
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 } }
Il livello La mia posizione
Puoi utilizzare i livelli La mia posizione e La mia posizione per mostrare all'utente la sua posizione corrente sulla mappa. Richiama mMap.setMyLocationEnabled()
per attivare il livello La mia posizione sulla mappa.
Il seguente esempio illustra un semplice utilizzo del livello La mia posizione:
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; } }
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 } }
Quando il livello La mia posizione è attivato, viene visualizzato il pulsante La mia posizione nell'angolo in alto a destra della mappa. Quando un utente fa clic sul pulsante, la fotocamera centra la mappa sulla posizione corrente del dispositivo, se nota. La posizione è indicata sulla mappa da un piccolo punto blu se il dispositivo è fermo o da una freccia se il dispositivo è in movimento.
Il seguente screenshot mostra il pulsante La mia posizione in alto a destra e il pallino blu di La mia posizione al centro della mappa:
Puoi impedire la visualizzazione del pulsante La mia posizione chiamando il numero UiSettings.setMyLocationButtonEnabled(false)
.
La tua app può rispondere ai seguenti eventi:
- Se l'utente fa clic sul pulsante La mia posizione, la tua app riceve un callback
onMyLocationButtonClick()
daGoogleMap.OnMyLocationButtonClickListener
. - Se l'utente fa clic sul punto blu di La mia posizione, la tua app riceve un callback
onMyLocationClick()
daGoogleMap.OnMyLocationClickListener
.
API Google Play Services Location
L'API di geolocalizzazione di Google Play Services è il metodo preferito per aggiungere alla tua app Android la funzionalità di rilevamento della posizione. Include funzionalità che ti consentono di:
- Determinare la posizione del dispositivo.
- Ascolta le modifiche di posizione.
- Determinare la modalità di trasporto, se il dispositivo è in movimento.
- Crea e monitora aree geografiche predefinite, note come recinti virtuali.
Le API di geolocalizzazione semplificano la creazione di applicazioni efficienti dal punto di vista della posizione e ad alta efficienza energetica. Analogamente all'SDK Maps for Android, l'API Location è distribuita come parte dell'SDK Google Play Services. Per ulteriori informazioni sull'API Location, consulta il corso di formazione su Android Rendere l'app sensibile alla posizione o il Riferimento API Location. Gli esempi di codice sono inclusi nell'SDK di Google Play Services.