C'est le 15e anniversaire de Google Maps Platform. Découvrez les dernières actualités et annonces.

Sélectionner le lieu actuel et afficher les détails sur une carte

Ce tutoriel vous montre comment trouver la position actuelle d'un appareil Android et afficher les informations relatives à ce lieu (établissement ou autre point d'intérêt). Suivez ce tutoriel pour créer une application Android à l'aide du Maps SDK pour Android, du SDK Places pour Android et du Fused Location Provider dans les API de localisation des services Google Play.

Obtenir le code

Clonez ou téléchargez le référentiel d'exemples Google Maps Android API v2 à partir de GitHub.

Configurer votre projet de développement

Suivez les étapes ci-dessous pour créer le projet du tutoriel dans Android Studio.

  1. Téléchargez et installez Android Studio.
  2. Ajoutez le package de services Google Play à Android Studio.
  3. Clonez ou téléchargez le référentiel d'exemples Google Maps Android API v2 si vous ne l'avez pas déjà fait au début de ce tutoriel.
  4. Importez le projet du tutoriel :

    • Dans Android Studio, sélectionnez File > New > Import Project.
    • Accédez à l'emplacement où vous avez enregistré le référentiel d'exemples Google Maps Android API v2 après l'avoir téléchargé.
    • Localisez le projet CurrentPlaceDetailsOnMap à l'adresse suivante :
      PATH-TO-SAVED-REPO/android-samples/tutorials/CurrentPlaceDetailsOnMap
    • Sélectionnez le répertoire du projet, puis cliquez sur OK. Android Studio crée à présent votre projet à l'aide de l'outil de compilation Gradle.

Obtenir une clé API et activer les API nécessaires

Pour suivre ce tutoriel, vous devez disposer d'une clé API Google autorisée à utiliser le SDK Maps pour Android et le SDK Places pour Android.

Cliquez sur le bouton ci-dessous pour obtenir une clé et activer les API.

Commencer

Pour plus d'informations, consultez le guide complet qui explique comment obtenir une clé API.

Ajouter la clé API à votre application

  1. Modifiez le fichier gradle.properties de votre projet.
  2. Collez votre clé API dans la valeur de la propriété GOOGLE_MAPS_API_KEY :

    GOOGLE_MAPS_API_KEY=PASTE-YOUR-API-KEY-HERE

    Lorsque vous compilez l'application, Gradle copie la clé API dans le fichier manifeste Android de l'application. Le fichier build.gradle de l'application contient la ligne suivante, qui mappe la chaîne google_maps_key du fichier manifeste sur la propriété GOOGLE_MAPS_API_KEY de l'outil Gradle :

    resValue "string", "google_maps_key",
            (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
    

Compiler et exécuter votre application

  1. Connectez un appareil Android à votre ordinateur. Suivez les instructions pour activer les options pour les développeurs sur votre appareil Android et configurer votre système afin qu'il détecte l'appareil. Vous pouvez également utiliser l'outil AVD (Android Virtual Device) Manager pour configurer un appareil virtuel. Lorsque vous choisissez un émulateur, assurez-vous de sélectionner une image qui inclut les API Google. Pour plus d'informations, consultez le guide de démarrage.
  2. Dans Android Studio, cliquez sur l'option de menu Run (ou sur l'icône du bouton de lecture). Choisissez un appareil lorsque vous y êtes invité.

Android Studio invoque Gradle pour créer l'application, puis l'exécute sur l'appareil ou sur l'émulateur. Vous devriez voir une carte avec un certain nombre de repères centrés autour de votre position actuelle, comme dans l'image de cette page.

Résolution des erreurs :

  • Si aucune carte ne s'affiche, vérifiez que vous avez bien obtenu une clé API et que vous l'avez ajoutée à l'application, comme décrit ci-dessus. Consultez le journal Android Monitor d'Android Studio pour vérifier s'il contient des messages d'erreur concernant la clé API.
  • Si la carte affiche un seul repère situé sur le Harbour Bridge de Sydney (position par défaut spécifiée dans l'application), vérifiez que vous avez octroyé l'autorisation de géolocalisation à l'application. L'application demande cette autorisation au moment de son exécution, selon le modèle décrit dans le guide des autorisations Android. Notez que vous pouvez également définir les autorisations directement sur l'appareil en sélectionnant Paramètres > Applications > nom de l'application > Autorisations > Localisation. Pour plus de détails sur la gestion des autorisations dans le code, consultez le guide ci-dessous. Il explique comment demander l'autorisation de géolocalisation dans votre application.
  • Utilisez les outils de débogage d'Android Studio pour afficher les journaux et déboguer l'application.

Comprendre le code

Cette partie du tutoriel explique les parties les plus importantes de l'application CurrentPlaceDetailsOnMap, pour vous aider à comprendre comment créer une application similaire.

Instancier les clients API Places

Les interfaces suivantes constituent les principaux points d'accès au SDK Places pour Android :

  • L'interface GeoDataClient vous permet d'accéder à la base de données Google contenant des informations sur les lieux et les établissements locaux.
  • L'interface PlaceDetectionClient fournit rapidement la position actuelle de l'appareil et permet de géolocaliser l'appareil à un endroit précis.

L'interface LocationServices est le principal point d'accès aux services de localisation Android.

Pour utiliser les API, instanciez GeoDataClient, PlaceDetectionClient et FusedLocationProviderClient dans la méthode onCreate() de votre fragment ou de l'activité, comme illustré dans l'exemple de code suivant :

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Construct a GeoDataClient.
    mGeoDataClient = Places.getGeoDataClient(this, null);

    // Construct a PlaceDetectionClient.
    mPlaceDetectionClient = Places.getPlaceDetectionClient(this, null);

    // Construct a FusedLocationProviderClient.
    mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
}

Demander l'autorisation de géolocalisation

Votre application doit demander une autorisation de géolocalisation pour déterminer la position de l'appareil et permettre à l'utilisateur d'appuyer sur le bouton Ma position sur la carte.

Ce tutoriel fournit le code nécessaire pour demander une autorisation de géolocalisation précise. Pour plus d'informations, consultez le guide relatif aux autorisations Android.

  1. Ajoutez l'autorisation en tant qu'enfant de l'élément <manifest> dans votre fichier manifeste Android :

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.currentplacedetailsonmap">
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    </manifest>
    
  2. Demandez les autorisations d'exécution dans votre application, en donnant à l'utilisateur la possibilité d'octroyer ou de refuser l'autorisation de géolocalisation. Le code suivant vérifie si l'utilisateur a accordé une autorisation de géolocalisation précise. Si ce n'est pas le cas, il demande l'autorisation :

    private void getLocationPermission() {
        /*
         * Request location permission, so that we can get the location of the
         * device. The result of the permission request is handled by a callback,
         * onRequestPermissionsResult.
         */
        if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mLocationPermissionGranted = true;
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }
    }
    
  3. Ignorez le rappel onRequestPermissionsResult() pour traiter le résultat de la demande d'autorisation :

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        mLocationPermissionGranted = false;
        switch (requestCode) {
            case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mLocationPermissionGranted = true;
                }
            }
        }
        updateLocationUI();
    }
    

    Une section ultérieure de ce tutoriel décrit la méthode updateLocationUI().

Ajouter une carte

Affichez une carte à l'aide du SDK Maps pour Android.

  1. Ajoutez un élément <fragment> au fichier de mise en page de votre activité, activity_maps.xml. Cet élément définit un fragment SupportMapFragment pour servir de conteneur à la carte et donner accès à l'objet GoogleMap. Ce tutoriel utilise la version du fragment de carte issue de la bibliothèque Android Support afin de garantir sa rétrocompatibilité avec les versions précédentes du framework Android.

    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.currentplacedetailsonmap.MapsActivityCurrentPlace" />
    
    
  2. Dans la méthode onCreate() de votre activité, définissez le fichier de mise en page en tant que vue de contenu :

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
    }
    
  3. Ajoutez l'interface OnMapReadyCallback et ignorez la méthode onMapReady() pour configurer la carte lorsque l'objet GoogleMap est disponible :

    public void onMapReady(GoogleMap map) {
        mMap = map;
    
        // Do other setup activities here too, as described elsewhere in this tutorial.
    
        // Turn on the My Location layer and the related control on the map.
        updateLocationUI();
    
        // Get the current location of the device and set the position of the map.
        getDeviceLocation();
    }
    
  4. Dans la méthode onCreate() de votre activité, obtenez un handle vers le fragment de carte en appelant FragmentManager.findFragmentById(). Ensuite, utilisez getMapAsync() pour vous inscrire au rappel de la carte :

    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    
  5. Écrivez une méthode updateLocationUI() pour définir les commandes de position sur la carte. Si l'utilisateur a octroyé l'autorisation de géolocalisation, activez le calque et la commande Ma position sur la carte. Dans le cas contraire, désactivez-les et définissez la position actuelle sur la valeur null :

    private void updateLocationUI() {
        if (mMap == null) {
            return;
        }
        try {
            if (mLocationPermissionGranted) {
                mMap.setMyLocationEnabled(true);
                mMap.getUiSettings().setMyLocationButtonEnabled(true);
            } else {
                mMap.setMyLocationEnabled(false);
                mMap.getUiSettings().setMyLocationButtonEnabled(false);
                mLastKnownLocation = null;
                getLocationPermission();
            }
        } catch (SecurityException e)  {
            Log.e("Exception: %s", e.getMessage());
        }
    }
    

Obtenir la position de l'appareil Android et positionner la carte

À l'aide de Fused Location Provider, identifiez la dernière position connue de l'appareil et utilisez-la pour positionner la carte. Ce tutoriel fournit tout le code nécessaire. Pour plus d'informations sur la localisation de l'appareil, consultez le guide dédié à Fused Location Provider dans les API de localisation des services Google Play.

private void getDeviceLocation() {
    /*
     * Get the best and most recent location of the device, which may be null in rare
     * cases when a location is not available.
     */
    try {
        if (mLocationPermissionGranted) {
            Task locationResult = mFusedLocationProviderClient.getLastLocation();
            locationResult.addOnCompleteListener(this, new OnCompleteListener() {
                @Override
                public void onComplete(@NonNull Task task) {
                    if (task.isSuccessful()) {
                        // Set the map's camera position to the current location of the device.
                        mLastKnownLocation = task.getResult();
                        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                                new LatLng(mLastKnownLocation.getLatitude(),
                                        mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
                    } else {
                        Log.d(TAG, "Current location is null. Using defaults.");
                        Log.e(TAG, "Exception: %s", task.getException());
                        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
                        mMap.getUiSettings().setMyLocationButtonEnabled(false);
                    }
                }
            });
        }
    } catch(SecurityException e)  {
        Log.e("Exception: %s", e.getMessage());
    }
}

Obtenir le lieu actuel

Utilisez le SDK Places pour Android pour obtenir la liste des lieux susceptibles d'être trouvés à l'emplacement actuel de l'appareil. Dans ce contexte, un lieu est un établissement ou un autre point d'intérêt.

Ce tutoriel récupère le lieu actuel lorsque l'internaute clique sur le bouton Obtenir le lieu. Il propose à l'utilisateur une liste des lieux susceptibles d'être sélectionnés, puis ajoute un repère sur la carte à l'emplacement du lieu sélectionné. Le tutoriel fournit le code dont vous avez besoin pour interagir avec le SDK Places pour Android. Pour plus d'informations, consultez le guide sur l'obtention du lieu actuel.

  1. Créez un fichier de mise en page (current_place_menu.xml) pour le menu d'options et ignorez la méthode onCreateOptionsMenu() pour configurer le menu d'options. Consultez l'exemple d'application fourni avec le code.
  2. Ignorez la méthode onOptionsItemSelected() pour obtenir le lieu actuel lorsque l'utilisateur clique sur l'option Obtenir le lieu :
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.option_get_place) {
            showCurrentPlace();
        }
        return true;
    }
    
  3. Créez une méthode showCurrentPlace() pour obtenir la liste des lieux probables à l'emplacement actuel de l'appareil :

    private void showCurrentPlace() {
        if (mMap == null) {
            return;
        }
    
        if (mLocationPermissionGranted) {
            // Use fields to define the data types to return.
            List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS,
                    Place.Field.LAT_LNG);
    
            // Use the builder to create a FindCurrentPlaceRequest.
            FindCurrentPlaceRequest request =
                    FindCurrentPlaceRequest.newInstance(placeFields);
    
            // Get the likely places - that is, the businesses and other points of interest that
            // are the best match for the device's current location.
            @SuppressWarnings("MissingPermission") final
            Task<FindCurrentPlaceResponse> placeResult =
                    mPlacesClient.findCurrentPlace(request);
            placeResult.addOnCompleteListener (new OnCompleteListener<FindCurrentPlaceResponse>() {
                @Override
                public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
                    if (task.isSuccessful() && task.getResult() != null) {
                        FindCurrentPlaceResponse likelyPlaces = task.getResult();
    
                        // Set the count, handling cases where less than 5 entries are returned.
                        int count;
                        if (likelyPlaces.getPlaceLikelihoods().size() < M_MAX_ENTRIES) {
                            count = likelyPlaces.getPlaceLikelihoods().size();
                        } else {
                            count = M_MAX_ENTRIES;
                        }
    
                        int i = 0;
                        mLikelyPlaceNames = new String[count];
                        mLikelyPlaceAddresses = new String[count];
                        mLikelyPlaceAttributions = new List[count];
                        mLikelyPlaceLatLngs = new LatLng[count];
    
                        for (PlaceLikelihood placeLikelihood : likelyPlaces.getPlaceLikelihoods()) {
                            // Build a list of likely places to show the user.
                            mLikelyPlaceNames[i] = placeLikelihood.getPlace().getName();
                            mLikelyPlaceAddresses[i] = placeLikelihood.getPlace().getAddress();
                            mLikelyPlaceAttributions[i] = placeLikelihood.getPlace()
                                    .getAttributions();
                            mLikelyPlaceLatLngs[i] = placeLikelihood.getPlace().getLatLng();
    
                            i++;
                            if (i > (count - 1)) {
                                break;
                            }
                        }
    
                        // Show a dialog offering the user the list of likely places, and add a
                        // marker at the selected place.
                        MapsActivityCurrentPlace.this.openPlacesDialog();
                    }
                    else {
                        Log.e(TAG, "Exception: %s", task.getException());
                    }
                }
            });
        } else {
            // The user has not granted permission.
            Log.i(TAG, "The user did not grant location permission.");
    
            // Add a default marker, because the user hasn't selected a place.
            mMap.addMarker(new MarkerOptions()
                    .title(getString(R.string.default_info_title))
                    .position(mDefaultLocation)
                    .snippet(getString(R.string.default_info_snippet)));
    
            // Prompt the user for permission.
            getLocationPermission();
        }
    }
    
  4. Créez une méthode openPlacesDialog() pour afficher un formulaire permettant à l'utilisateur de sélectionner un lieu à partir d'une liste de lieux probables. Ajoutez un repère sur la carte pour le lieu sélectionné. Le repère contient entre autres le nom et l'adresse du lieu, ainsi que les attributions fournies par l'API :

    private void openPlacesDialog() {
        // Ask the user to choose the place where they are now.
        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // The "which" argument contains the position of the selected item.
                LatLng markerLatLng = mLikelyPlaceLatLngs[which];
                String markerSnippet = mLikelyPlaceAddresses[which];
                if (mLikelyPlaceAttributions[which] != null) {
                    markerSnippet = markerSnippet + "\n" + mLikelyPlaceAttributions[which];
                }
    
                // Add a marker for the selected place, with an info window
                // showing information about that place.
                mMap.addMarker(new MarkerOptions()
                        .title(mLikelyPlaceNames[which])
                        .position(markerLatLng)
                        .snippet(markerSnippet));
    
                // Position the map's camera at the location of the marker.
                mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(markerLatLng,
                        DEFAULT_ZOOM));
            }
        };
    
        // Display the dialog.
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setTitle(R.string.pick_place)
                .setItems(mLikelyPlaceNames, listener)
                .show();
    }
    
  5. Créez une mise en page personnalisée pour le contenu de la fenêtre d'informations. Cela permet d'afficher plusieurs lignes de contenu dans la fenêtre d'informations. Tout d'abord, ajoutez un fichier XML de mise en page custom_info_contents.xml, contenant un premier affichage de texte pour le titre de la fenêtre d'informations et un second pour l'extrait de code (le contenu textuel de la fenêtre) :

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layoutDirection="locale"
        android:orientation="vertical">
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textColor="#ff000000"
            android:textStyle="bold" />
    
        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#ff7f7f7f" />
    </LinearLayout>
    
    
  6. Ajoutez l'interface InfoWindowAdapter pour gonfler la mise en page et charger le contenu de la fenêtre d'informations :

    @Override
    public void onMapReady(GoogleMap map) {
        // Do other setup activities here too, as described elsewhere in this tutorial.
        mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
    
        @Override
        // Return null here, so that getInfoContents() is called next.
        public View getInfoWindow(Marker arg0) {
            return null;
        }
    
        @Override
        public View getInfoContents(Marker marker) {
            // Inflate the layouts for the info window, title and snippet.
            View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_contents, null);
    
            TextView title = ((TextView) infoWindow.findViewById(R.id.title));
            title.setText(marker.getTitle());
    
            TextView snippet = ((TextView) infoWindow.findViewById(R.id.snippet));
            snippet.setText(marker.getSnippet());
    
            return infoWindow;
          }
        });
    }
    

Enregistrer l'état de la carte

Enregistrez la position de la caméra de la carte, ainsi que la localisation de l'appareil. Lorsqu'un utilisateur fait pivoter un appareil Android ou modifie sa configuration, le framework Android détruit et reconstruit l'activité de la carte. Pour optimiser l'expérience utilisateur, il est recommandé de stocker les états d'application pertinents et de les restaurer en cas de besoin.

Ce tutoriel fournit tout le code nécessaire pour enregistrer l'état de la carte. Pour plus d'informations, consultez le guide du bundle savedInstanceState.

  1. Dans votre activité de carte, configurez des valeurs clé pour stocker l'état de l'activité :

    private static final String KEY_CAMERA_POSITION = "camera_position";
    private static final String KEY_LOCATION = "location";
    
  2. Intégrez le rappel onSaveInstanceState() pour enregistrer l'état en cas d'interruption de l'activité :

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (mMap != null) {
            outState.putParcelable(KEY_CAMERA_POSITION, mMap.getCameraPosition());
            outState.putParcelable(KEY_LOCATION, mLastKnownLocation);
            super.onSaveInstanceState(outState);
        }
    }
    
  3. Dans la méthode onCreate() de votre activité, récupérez la localisation de l'appareil et la position de la caméra de la carte si vous les avez enregistrés précédemment :

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            mCurrentLocation = savedInstanceState.getParcelable(KEY_LOCATION);
            mCameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
        }
        ...
    }