Blog technique sur mes expériences de développeur.
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.
Cet article est déprécié !
Vous pouvez consulter cette série de sept articles sur mon blog intitulé “Intégrer et utiliser une carte Google dans une application Android”
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.
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 :
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.).
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"/>
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.
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.
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.
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 :
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.
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.
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));
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 :
Pour ceux qui en auraient besoin, voici le code complet :
<?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>
<?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" />
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) { }
}