Una delle caratteristiche uniche delle applicazioni mobile è il rilevamento della posizione. Gli utenti di dispositivi mobili portano con sé i propri dispositivi ovunque e l'aggiunta della consapevolezza della posizione alla tua app offre agli utenti un'esperienza più contestuale.
Esempi di codice
Il repository ApiDemos su GitHub include esempi che mostrano l'uso della posizione su una mappa:
Kotlin
- MyLocationDemoActivity: utilizzo del livello La mia posizione, incluse le autorizzazioni di runtime
- LocationSourceDemoActivity: utilizzo di una
LocationSource
personalizzata - CurrentPlaceDetailsOnMap: consente di trovare la posizione attuale di un dispositivo Android e di visualizzare i dettagli del luogo (attività commerciale o altro punto d'interesse) in quella posizione. Guarda il tutorial su come mostrare i dettagli di un luogo attuale su una mappa.
Java
- MyLocationDemoActivity: utilizzo del livello La mia posizione, incluse le autorizzazioni di runtime
- LocationSourceDemoActivity: utilizzo di una
LocationSource
personalizzata - CurrentPlaceDetailsOnMap: consente di trovare la posizione attuale di un dispositivo Android e di visualizzare i dettagli del luogo (attività commerciale o altro punto d'interesse) in quella posizione. Guarda il tutorial su come mostrare i dettagli di un luogo attuale su una mappa.
Usare 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, nonché se il dispositivo si è spostato oltre un confine geografico o recinto virtuale predefinito. A seconda delle esigenze della tua applicazione, puoi scegliere tra diversi modi di lavorare con i dati sulla posizione:
- Il livello La mia posizione offre un modo semplice per visualizzare la posizione di un dispositivo sulla mappa. Non fornisce dati.
- L'API Location Services di Google Play è consigliata per tutte le richieste di pubblicità programmatica per i dati sulla posizione.
- L'interfaccia di
LocationSource
consente di fornire un fornitore di posizione personalizzato.
Autorizzazioni di accesso alla posizione
Se la tua app ha bisogno di accedere alla posizione dell'utente, devi richiedere l'autorizzazione aggiungendo all'app le autorizzazioni di accesso alla posizione Android pertinenti.
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 in base ai servizi di geolocalizzazione, come descritto nella documentazione sull'accuratezza della posizione approssimativa.android.permission.ACCESS_FINE_LOCATION
– Consente all'API di determinare la posizione più precisa possibile dai fornitori di servizi di geolocalizzazione disponibili, tra cui il sistema GPS, il Wi-Fi e i dati cellulare.
Aggiungi le autorizzazioni al manifest dell'app
Se è necessaria solo la posizione approssimativa per il funzionamento dell'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 della tua 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 quando 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 l'app o esegue l'upgrade dell'app. L'app deve verificare se dispone dell'autorizzazione necessaria in fase di runtime e richiederla, se non l'ha. Il sistema mostra all'utente una finestra di dialogo che chiede 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 è con una schermata di benvenuto o una procedura guidata che spieghi agli utenti perché è necessaria 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 agevolmente il caso in cui l'utente non concede l'autorizzazione. Ad esempio, se l'autorizzazione è necessaria per una funzionalità specifica, l'app può disabilitare quella funzionalità. Se l'autorizzazione è essenziale per il funzionamento dell'app, l'app può disabilitarne tutte le funzionalità e informare l'utente che deve concederla.
Il seguente esempio di codice verifica l'autorizzazione utilizzando la libreria AndroidX prima di abilitare il livello La mia posizione. Gestisce quindi il risultato della richiesta di autorizzazione implementando ActivityCompat.OnRequestPermissionsResultCallback
dalla libreria dell'assistenza:
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"); } }
Il livello La mia posizione
Puoi utilizzare il livello La mia posizione e il pulsante La mia posizione per mostrare
all'utente la sua posizione attuale sulla mappa. Chiama mMap.setMyLocationEnabled()
per attivare il livello La mia posizione sulla mappa.
Il seguente esempio illustra un semplice utilizzo del livello La mia posizione:
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; } }
Quando il livello La mia posizione è attivato, nell'angolo in alto a destra della mappa viene visualizzato il pulsante La mia posizione. 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 un gallone se il dispositivo è in movimento.
Il seguente screenshot mostra il pulsante La mia posizione in alto a destra e il punto blu La mia posizione al centro della mappa:
Puoi impedire che il pulsante La mia posizione venga visualizzato 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 La mia posizione, la tua app riceve un callback
onMyLocationClick()
daGoogleMap.OnMyLocationClickListener
.
API Google Play Services Location
L'API Location di Google Play Services è il metodo preferito per aggiungere la consapevolezza della posizione alla tua app per Android. Include funzionalità che ti consentono di:
- Determina la posizione del dispositivo.
- Ascoltare i cambiamenti di posizione.
- Determinare la modalità di trasporto se il dispositivo è in movimento.
- Creare e monitorare aree geografiche predefinite, note come recinti virtuali.
Le API di geolocalizzazione semplificano la creazione di applicazioni a risparmio energetico e sensibili alla posizione. Come l'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 Android Making Your App Location Aware (Rendere la tua app Location Aware) o il Location API Reference. Gli esempi di codice sono inclusi nell'SDK Google Play Services.