Ludovic ROLAND

Blog technique sur mes expériences de développeur.

Android : La géolocalisation et l’API Google Maps Android v2

2 février 2013

Il y a peu de temps, je vous ai proposé un petit tutoriel pour mettre en place la géolocalisation dans vos applications Windows Phone 7. Je vous propose aujourd’hui d’adapter ce tutoriel à Android.

Ce que nous allons faire

Comme pour le tutoriel Windows Phone, nous allons afficher dans un premier temps les coordonnées GPS de l’utilisateur, avant de placer sa position sur une carte en utilisant l’API Google Maps v2.

Première étape : la géolocalisation et l’affichage des coordonnées

Pour faire les choses simplement, je vous propose d’afficher les coordonnées GPS dans un message Toast. Ça nous évitera de faire du XML.

Pour géolocaliser notre téléphone, notre Activité doit implémenter l’interface LocationListener. Nous utiliserons ensuite l’objet LocationManager pour gérer notre abonnement aux mises à jour des coordonnées GPS du téléphone.

Puisque notre Activité implémente l’interface LocationListener, 4 méthodes sont à surcharger :

  • onProviderEnabled : cette méthode est appelée quand une source de localisation est activée ;
  • onProviderDisabled : cette méthode est appelée quand une source de localisation est désactivée ;
  • onStatusChanged : cette méthode est appelée quand le status d’une source change ;
  • onLocationChanged : cette méthode est appelée quand les coordonnées GPS du téléphone changent ;

Pour ne pas consommer trop de data et économiser de la batterie, il convient de s’abonner à la localisation GPS de l’utilisateur uniquement quand l’application est active.

A noter que dans l’exemple suivant, je vais localiser le téléphone uniquement via le GPS, mais sachez qu’il est également de possible de faire une géolocalisation approximative grâce aux réseaux (Wifi, 3G, etc.).

Dans le fichier AndroidManifest.xml

Il convient d’ajouter une autorisation nous permettant de détecter les coordonnées GPS de l’utilisateur. Pour ce faire, ajoutez la ligne suivante à votre fichier AndroidManifest.xml :

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Dans le fichier MainActivity.java

Voici donc ce à quoi doit ressembler votre fichier MainActivity.java :

public class MainActivity extends Activity implements LocationListener {
	private LocationManager locationManager;

	@Override
	protected void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
	@Override
	public void onResume() {
		super.onResume();

		//Obtention de la référence du service
		locationManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);

		//Si le GPS est disponible, on s'y abonne
		if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			abonnementGPS();
		}
	}
	@Override
	public void onPause() {
		super.onPause();

		//On appelle la méthode pour se désabonner
		desabonnementGPS();
	}

	/**
	 * Méthode permettant de s'abonner à la localisation par GPS.
	 */
	public void abonnementGPS() {
		//On s'abonne
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, this);
	}

	/**
	 * Méthode permettant de se désabonner de la localisation par GPS.
	 */
	public void desabonnementGPS() {
		//Si le GPS est disponible, on s'y abonne
		locationManager.removeUpdates(this);
	}

	@Override
	public void onLocationChanged(final Location location) {
		//On affiche dans un Toat la nouvelle Localisation
		final StringBuilder msg = new StringBuilder("lat : ");
		msg.append(location.getLatitude());
		msg.append( "; lng : ");
		msg.append(location.getLongitude());

		Toast.makeText(this, msg.toString(), Toast.LENGTH_SHORT).show();		
	}

	@Override
	public void onProviderDisabled(final String provider) {
		//Si le GPS est désactivé on se désabonne
		if("gps".equals(provider)) {
			desabonnementGPS();
		}		
	}

	@Override
	public void onProviderEnabled(final String provider) {
		//Si le GPS est activé on s'abonne
		if("gps".equals(provider)) {
			abonnementGPS();
		}
	}

	@Override
	public void onStatusChanged(final String provider, final int status, final Bundle extras) { }
}

Vous pouvez ensuite jouer avec la fonction GPS de l’émulateur pour vérifier qu’un message Toast s’affiche bien lorsque les coordonnées GPS changent.

Ajouter une carte

Nous allons maintenant ajouter une carte qui se centrera sur l’endroit où le téléphone nous géolocalise. Pour ce faire, nous allons utiliser l’API Google Maps Android v2.

Installation et configuration des services Google Play

La première étape consiste à télécharger les services Google Play pour pouvoir les intégrer par la suite à notre projet Android en tant que librairie.

Pour les télécharger, rendez-vous dans le SDK Manager puis dans la catégorie Extra, cochez le service Google Play.

Une fois le service installé, importez le comme «Existing Android Code Into Workspace» dans votre espace de travail. Chez moi, il est situé dans «C:\Program Files\Android\android-sdk\extras\google\google_play_services\libproject\google-play-services_lib».

Nous Allons maintenant ajouter le service Google Play comme une bibliothèque de notre projet. Pour ce faire, allez dans les propriétés du projet Android, puis dans l’onglet Android et tout en bas, ajoutez le projet google-play-services_lib comme bibliothèque.

Obtention d’une clef et activation du service

Nous allons maintenant obtenir une clef qui va nous permettre d’utiliser l’API de Google. Pour ce faire, rendez-vous dans la console Google.

Dans la liste des service, commencez par activer le service Google Maps Android API v2 comme dans la capture d’écran ci-dessous.

Rendez-vous ensuite dans l’onglet API Access pour créer une nouvelle clef Android (Create new Android Key…).

La fenêtre suivante s’ouvre alors, vous demandant l’empreinte SHA1 de votre certificat de développeur.

Comme indiqué, nous allons utiliser la commande keytool -list -v -keystore mystore.keystore pour visualiser notre empreinte SHA1. Dans notre

Dans notre cas, nous allons utiliser la clef par défaut grâce au fichier debug.keystore qui se trouve chez moi dans C:\Users\Ludovic.android

L’outils keytool se trouve quant à lui dans le dossier d’installation de mon JDK.

A noter que si un mot de passe est demandé, il suffit de saisir «android».

De retour dans la console Google, vous pouvez maintenant saisir l’empreinte SHa1 trouvé, y ajouter un «;» et saisir le nom du package de votre application afin de créer la clef.

Dans mon cas, voici ce que j’ai saisi : F8:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:*:B9;fr.rolandl.blog_gps

Votre clef est donc maintenant générée :

Modification du manifest

Nous allons maintenant modifier notre fichier AndroidManifest.xml. Tout d’abord, nous allons indiquer que notre application nécessite OpenGL ES version 2 :

<uses-feature 
    android:glEsVersion="0x00020000"
    android:required="true"/>

Nous allons maintenant y ajouter les informations relatives à l’API et notre clef :

<meta-data
    android:name="com.google.android.maps.v2.API_KEY"
    android:value="ma_clef"/>

Toujours dans le fichier AndroidManifest.xml, nous devons préciser la version des Google Play Services que nous utilisons :

<meta-data
    android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />

Finalement, nous devons mettre à jour la liste des permissions :

<permission
    android:name="fr.rolandl.blog_gps.permission.MAPS_RECEIVE"
    android:protectionLevel="signature"/>

<uses-permission android:name="fr.rolandl.blog_gps.permission.MAPS_RECEIVE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>

Pour ceux qui aurez du mal à placer correctement les informations, vous pouvez retrouver le fichier AndroidManifest.xml complet à la fin de cet article.

Le layout

Nous allons maintenant modifier le layout de Activité pour y ajouter la carte Google :

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.google.android.gms.maps.MapFragment" />

Vous pouvez dès maintenant compiler l’application et vérifier qu’une carte Google s’affiche bien. A noter qu’il semble falloir faire de nombreuses manipulations pour tester cette API sur un émulateur, je vous conseille donc de tester directement sur votre téléphone !

Pour ceux qui voudraient quand même tester sur l’émulateur, une solution est proposée ici.

L’activité

Nous allons maintenant modifier notre activité pour pouvoir centrer la carte Google sur la position de l’utilisateur.

Commencez par ajouter un attribut de la classe GoogleMap à votre activité :

private GoogleMap gMap;

Dans la méthode onCreate de votre activité, récupérez alors la référence de votre carte :

gMap = ((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap();

Finalement, dans la méthode onLocationChanged, nous allons centrer la carte sur les coordonnées GPS trouvées :

gMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), 15));

Ajout d’un marqueur

Nous allons maintenant ajouter un marqueur à notre carte pour indiquer plus précisément où nous sommes.

Commencez par ajouter un attribut de la classe Marker à votre activité :

private Marker marker;

Dans la méthode onCreate de votre activité, définissez alors quelques paramètres puis ajoutez le à votre carte :

marker = gMap.addMarker(new MarkerOptions().title("Vous êtes ici").position(new LatLng(0, 0)));

Finalement, dans la méthode onLocationChanged, il ne bous reste plus qu’à indiquer les coordonnées GPS de notre marqueur :

marker.setPosition(new LatLng(location.getLatitude(), location.getLongitude()));

En cliquant sur le marker, une info bulle s’affiche avec le texte «Vous êtes ici» comme dans la capture d’écran ci-dessous :

Le code complet

Pour ceux qui en auraient besoin, voici le code complet :

Le fichier AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="fr.rolandl.blog_gps"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="17" />

    <uses-feature 
        android:glEsVersion="0x00020000"
        android:required="true"/>

    <permission
    	android:name="fr.rolandl.blog_gps.permission.MAPS_RECEIVE"
    	android:protectionLevel="signature"/>

	  <uses-permission android:name="fr.rolandl.blog_gps.permission.MAPS_RECEIVE"/>
	  <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
	  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
	  <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <meta-data 
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="AI..."/>

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <activity
            android:name="fr.rolandl.blog_gps.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Le layout activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.google.android.gms.maps.MapFragment" />

L’activité

package fr.rolandl.blog_gps;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import android.app.Activity;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.Toast;

/**
 * MainActivity.
 * @author Ludovic
 *
 */
public class MainActivity extends Activity implements LocationListener {
	/*******************************************************/
	/** ATTRIBUTS.
	/*******************************************************/
	private LocationManager locationManager;
	private GoogleMap gMap;
	private Marker marker;

	/*******************************************************/
	/** METHODES / FONCTIONS.
	/*******************************************************/
	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onCreate(final Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		gMap = ((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap();
		marker = gMap.addMarker(new MarkerOptions().title("Vous êtes ici").position(new LatLng(0, 0)));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onResume() {
		super.onResume();

		//Obtention de la référence du service
		locationManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);

		//Si le GPS est disponible, on s'y abonne
		if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			abonnementGPS();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onPause() {
		super.onPause();

		//On appelle la méthode pour se désabonner
		desabonnementGPS();
	}

	/**
	 * Méthode permettant de s'abonner à la localisation par GPS.
	 */
	public void abonnementGPS() {
		//On s'abonne
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, this);
	}

	/**
	 * Méthode permettant de se désabonner de la localisation par GPS.
	 */
	public void desabonnementGPS() {
		//Si le GPS est disponible, on s'y abonne
		locationManager.removeUpdates(this);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onLocationChanged(final Location location) {
		//On affiche dans un Toat la nouvelle Localisation
		final StringBuilder msg = new StringBuilder("lat : ");
		msg.append(location.getLatitude());
		msg.append( "; lng : ");
		msg.append(location.getLongitude());

		Toast.makeText(this, msg.toString(), Toast.LENGTH_SHORT).show();

		//Mise à jour des coordonnées
		final LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());		
		gMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
		marker.setPosition(latLng);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onProviderDisabled(final String provider) {
		//Si le GPS est désactivé on se désabonne
		if("gps".equals(provider)) {
			desabonnementGPS();
		}		
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onProviderEnabled(final String provider) {
		//Si le GPS est activé on s'abonne
		if("gps".equals(provider)) {
			abonnementGPS();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onStatusChanged(final String provider, final int status, final Bundle extras) { }
}

Commentaires