Una delle funzionalità univoche delle applicazioni mobile è il riconoscimento della posizione. Gli utenti di dispositivi mobili portano i loro 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'utilizzo della posizione su una mappa:
Kotlin
- MyLocationDemoActivity: utilizzo del livello La mia posizione, incluse le autorizzazioni di runtime
- LocationSourceDemoActivity: utilizzo di un
LocationSource
personalizzato - CurrentPlaceDetailsOnMap: trova la posizione attuale di un dispositivo Android e mostra i dettagli del luogo (attività o altro punto d'interesse) in quella posizione. Consulta il tutorial su come mostrare i dettagli del luogo attuale su una mappa.
Java
- MyLocationDemoActivity: utilizzo del livello La mia posizione, incluse le autorizzazioni di runtime
- LocationSourceDemoActivity: utilizzo di un
LocationSource
personalizzato - CurrentPlaceDetailsOnMap: trova la posizione attuale di un dispositivo Android e mostra i dettagli del luogo (attività o altro punto d'interesse) in quella posizione. Consulta il tutorial su come mostrare i dettagli del luogo attuale su una mappa.
Utilizzo dei dati sulla posizione
I dati sulla posizione disponibili per un dispositivo Android includono la posizione attuale del dispositivo, individuata utilizzando una combinazione di tecnologie, la direzione e il metodo di movimento e se il dispositivo ha attraversato un confine geografico predefinito o un recinto virtuale. A seconda delle esigenze della tua applicazione, puoi scegliere tra diversi modi per 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 di Google Play Services è consigliata per tutte le richieste programmatiche relative ai dati sulla posizione.
- L'interfaccia
LocationSource
ti consente di fornire un provider di posizione personalizzato.
Autorizzazioni di accesso alla posizione
Se la tua app deve accedere alla posizione dell'utente, devi richiedere l'autorizzazione aggiungendo le autorizzazioni di accesso alla posizione di Android pertinenti alla tua app.
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 della posizione approssimativa.android.permission.ACCESS_FINE_LOCATION
: consente all'API di determinare una posizione il più precisa possibile dai fornitori di servizi di geolocalizzazione disponibili, tra cui il Global Positioning System (GPS), nonché i dati Wi-Fi e di telefonia mobile.
Aggiungi le autorizzazioni al file manifest dell'app
Se la posizione approssimativa è necessaria solo 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 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>
Richiedere le autorizzazioni di runtime
Android 6.0 (Marshmallow) introduce un nuovo modello per la gestione delle autorizzazioni, che semplifica la procedura per gli utenti quando installano e 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 sul dispositivo è installato Android 6.0 (Marshmallow) o versioni successive, l'utente non deve concedere alcuna autorizzazione durante l'installazione o l'upgrade dell'app. L'app deve verificare se dispone dell'autorizzazione necessaria in fase di esecuzione e richiederla se non la possiede. Il sistema mostra all'utente una finestra di dialogo che richiede 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é l'autorizzazione è obbligatoria.
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 in modo corretto 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, l'app può disattivare tutte le sue funzionalità e informare l'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 il metodo
ActivityCompat.OnRequestPermissionsResultCallback
della libreria di 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.
L'esempio seguente mostra 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 è attivo, il pulsante La mia posizione viene visualizzato nell'angolo in alto a destra della mappa. Quando un utente fa clic sul pulsante, la fotocamera centra la mappa sulla posizione attuale del dispositivo, se nota. La posizione è indicata sulla mappa da un piccolo punto blu se il dispositivo è fermo o da un a capo se il dispositivo è in movimento.
Lo screenshot seguente mostra il pulsante La mia posizione in alto a destra e il punto blu La mia posizione al centro della mappa:
Puoi impedire la visualizzazione del pulsante La mia posizione chiamando
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
.
L'API Location di Google Play Services
L'API Location di Google Play Services è il metodo preferito per aggiungere la consapevolezza della posizione alla tua applicazione Android. Include funzionalità che ti consentono di:
- Determinare la posizione del dispositivo.
- Rilevamento delle modifiche alla posizione.
- Determina il mezzo di trasporto, se il dispositivo è in movimento.
- Crea e monitora regioni geografiche predefinite, note come recinti virtuali.
Le API di geolocalizzazione ti consentono di creare facilmente applicazioni efficienti e consapevoli della posizione. Come l'SDK Maps per Android, l'API Location viene distribuita nell'ambito dell'SDK Google Play Services. Per ulteriori informazioni sull'API Location, consulta il corso di formazione Android Creare app con conoscenza della posizione o la documentazione di riferimento dell'API Location. Gli esempi di codice sono inclusi nell'SDK di Google Play Services.