Implémentation du package Geolocator
Pour pouvoir géolocaliser un utilisateur, vous aurez besoin du package Geolocator de Flutter. La première étape va donc être de le mettre en place.
À quoi sert le package Geolocator ?
Le package Geolocator vous permet de récupérer des informations importantes liées à la géolocalisation des utilisateurs dans une application Flutter. Parmi les fonctionnalités qu’il supporte on trouve :
- La récupération de la position actuelle de l’utilisateur.
- Le suivi de ses déplacements en temps réel.
- La récupération de sa dernière localisation connue.
- La vérification de l’état des services de localisation sur l’appareil.
- Le calcul de la distance entre deux points géographiques et la direction entre eux.
Installation et configuration
Pour ajouter Geolocator à votre application Flutter, commencez par vous rendre dans le fichier pubspec.yaml
de votre projet Flutter et ajoutez-y la dépendance suivante :
dependencies:
geolocator: ^13.0.2
Ensuite, exécutez la commande flutter pub get
pour télécharger et installer le package.
Configuration pour Android
Pour que Geolocator puisse fonctionner sur Android, suivez ces étapes :
1. Le plugin Geolocator nécessite que votre projet Android utilise les bibliothèques AndroidX. Assurez-vous donc que votre projet est configuré en ajoutant les lignes suivantes dans le fichier android>gradle.properties
:
android.useAndroidX=true
android.enableJetifier=true
2. Ajoutez ensuite les permissions nécessaires pour accéder à la localisation dans le fichier AndroidManifest.xml
sous android/app/src/main/
:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
Enfin, n’oubliez pas de vérifier que votre application supporte les API Android 12 et versions supérieures. Mettez également à jour la version de compileSdkVersion soit à 34 dans votre fichier build.gradle
, soit sous la forme suivante :
android {
namespace "com.monapp.app"
compileSdkVersion flutter.compileSdkVersion
ndkVersion = "26.1.10909125"
Configuration pour IOS
Pour que Geolocator puisse fonctionner sur IOS, suivez ces étapes :
1. Pour commencer, configurez votre application pour demander l’autorisation d’utiliser la géolocalisation. Ajoutez les clés suivantes dans votre fichier Info.plist
(sous ios/Runner/
).
<key>NSLocationUsageDescription</key>
<string>This app needs access to location.</string>
Ce bloc permettra d’afficher un message à l’utilisateur pour expliquer pourquoi votre application a besoin de la localisation.
2. (Facultatif) Si vous ne souhaitez pas recevoir de mises à jour de localisation lorsque l’application fonctionne en arrière-plan, vous pouvez éviter d’avoir à demander une permission supplémentaire, en configurant un flag de préprocesseur dans votre projet Xcode. Pour ce faire :
- Ouvrez votre projet dans Xcode.
- Dans la section Pods, sélectionnez la cible
geolocator_apple
. - Allez dans les Paramètres de Build.
- Dans la barre de recherche, recherchez
Preprocessor Macros
et ajoutez la ligne suivante :
BYPASS_PERMISSION_LOCATION_ALWAYS=1
Cela désactive la demande de permission pour l’accès à la localisation en arrière-plan et empêche Apple de poser des questions supplémentaires lors de la soumission de votre application.
3. Au contraire, si vous avez besoin de continuer à recevoir des mises à jour de localisation en arrière-plan (par exemple, pour des applications de suivi en temps réel), vous devez ajouter des capacités de fond dans Xcode :
- Allez dans votre projet Xcode.
- Sélectionnez Project > Signing and Capabilities.
- Cliquez sur le bouton + Capability et ajoutez Location Updates.
- Vous devrez fournir une explication détaillée lors de la soumission de l’application sur l’App Store pour justifier l’utilisation de cette fonctionnalité. Si Apple n’est pas convaincu, votre application pourrait être rejetée.
4. Ensuite, vous devez ajouter une autre entrée dans le fichier Info.plist
pour spécifier l’autorisation d’accès à la localisation en arrière-plan :
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Your app needs location access even when in the background.</string> //Remplacer par votre explication
Si vous ciblez des versions d’iOS antérieures à la version 11.0, utilisez la clé suivante à la place :
<key>NSLocationAlwaysUsageDescription</key>
<string>Your app needs location access even when in the background.</string>
5. Enfin, si votre application nécessite un accès temporaire à la localisation précise de l’utilisateur (par exemple, pour une recherche d’adresse ou un calcul d’itinéraire), vous devez également configurer une entrée NSLocationTemporaryUsageDescriptionDictionary dans le fichier Info.plist
. Cela permet d’informer l’utilisateur que l’application demande l’accès à sa localisation précise pour une période limitée :
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>YourPurposeKey</key>
<string>The example app requires temporary access to the device's precise location.</string>
</dict>
L’YourPurposeKey doit correspondre à la valeur de la clé purposeKey
passée dans la méthode requestTemporaryFullAccuracy()
du package Geolocator.
Configuration pour MacOS
Pour la plateforme macOS, l’approche est similaire à iOS. Vous devrez ajouter les clés suivantes dans votre fichier Info.plist
:
<key>NSLocationUsageDescription</key>
<string>This app needs access to location.</string>
Puis, pour permettre l’accès temporaire à une localisation précise, ajoutez également :
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>YourPurposeKey</key>
<string>The example App requires temporary access to the device's precise location.</string>
</dict>
Configuration pour le Web
Le plugin Geolocator prend en charge le Web, mais uniquement dans des contexts sécurisés (HTTPS). En ajoutant le package geolocator dans votre fichier pubspec.yaml
, Flutter inclura automatiquement le package geolocator_web.
Les méthodes suivantes ne sont pas supportées sur le Web et entraîneront des erreurs :
getLastKnownPosition
openAppSettings
openLocationSettings
getServiceStatusStream
Récupérer la position d’un utilisateur
Maintenant que vous avez mis le package Geolocator en place, voici les fonctionnalités que vous pouvez utiliser :
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Geolocator Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LocationScreen(),
);
}
}
class LocationScreen extends StatefulWidget {
@override
_LocationScreenState createState() => _LocationScreenState();
}
class _LocationScreenState extends State<LocationScreen> {
String _locationMessage = 'Aucune donnée de localisation';
String _permissionMessage = 'Permission de localisation non vérifiée';
@override
void initState() {
super.initState();
// Demander les permissions de localisation au démarrage de l'application
checkAndRequestPermission();
}
// 1. Récupérer la localisation actuelle
Future<void> getCurrentLocation() async {
try {
final LocationSettings locationSettings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 100,
);
Position position = await Geolocator.getCurrentPosition(locationSettings: locationSettings);
setState(() {
_locationMessage = 'Latitude: ${position.latitude}, Longitude: ${position.longitude}';
});
} catch (e) {
setState(() {
_locationMessage = 'Erreur: $e';
});
}
}
// 2. Récupérer la dernière position connue
Future<void> getLastKnownLocation() async {
try {
Position? position = await Geolocator.getLastKnownPosition();
if (position != null) {
setState(() {
_locationMessage = 'Dernière position connue : Latitude: ${position.latitude}, Longitude: ${position.longitude}';
});
} else {
setState(() {
_locationMessage = 'Aucune position précédente disponible.';
});
}
} catch (e) {
setState(() {
_locationMessage = 'Erreur: $e';
});
}
}
// 3. Écouter les mises à jour de la localisation
Future<void> listenToLocationUpdates() async {
final LocationSettings locationSettings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 100,
);
StreamSubscription<Position> positionStream = Geolocator.getPositionStream(locationSettings: locationSettings).listen(
(Position? position) {
setState(() {
_locationMessage = position == null
? 'Inconnu'
: 'Latitude: ${position.latitude}, Longitude: ${position.longitude}';
});
},
);
}
// 4. Vérifier si les services de localisation sont activés
Future<void> checkLocationService() async {
bool isLocationServiceEnabled = await Geolocator.isLocationServiceEnabled();
setState(() {
_locationMessage = isLocationServiceEnabled
? 'Les services de localisation sont activés.'
: 'Les services de localisation sont désactivés.';
});
}
// 5. Vérifier et demander des permissions de localisation
Future<void> checkAndRequestPermission() async {
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
setState(() {
_permissionMessage = 'Permission de localisation refusée. Demande de permission...';
});
permission = await Geolocator.requestPermission();
}
setState(() {
if (permission == LocationPermission.whileInUse || permission == LocationPermission.always) {
_permissionMessage = 'Permission de localisation accordée.';
} else {
_permissionMessage = 'Permission de localisation refusée de façon permanente.';
}
});
}
// 6. Calculer la distance entre deux points
Future<void> calculateDistance() async {
double distanceInMeters = Geolocator.distanceBetween(
52.2165157, 6.9437819, 52.3546274, 4.8285838,
);
setState(() {
_locationMessage = 'Distance calculée : $distanceInMeters mètres';
});
}
// 7. Ouvrir les paramètres de l'application ou de localisation
Future<void> openSettings() async {
await Geolocator.openAppSettings();
await Geolocator.openLocationSettings();
}
// 8. Vérifier la précision de la localisation
Future<void> checkLocationAccuracy() async {
var accuracy = await Geolocator.getLocationAccuracy();
setState(() {
_locationMessage = 'Précision de la localisation : $accuracy';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Geolocator Example'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(_permissionMessage),
SizedBox(height: 20),
Text(_locationMessage),
SizedBox(height: 20),
ElevatedButton(
onPressed: getCurrentLocation,
child: Text('Obtenir la localisation actuelle'),
),
ElevatedButton(
onPressed: getLastKnownLocation,
child: Text('Obtenir la dernière position connue'),
),
ElevatedButton(
onPressed: listenToLocationUpdates,
child: Text('Écouter les mises à jour de localisation'),
),
ElevatedButton(
onPressed: checkLocationService,
child: Text('Vérifier si les services de localisation sont activés'),
),
ElevatedButton(
onPressed: checkAndRequestPermission,
child: Text('Vérifier et demander des permissions'),
),
ElevatedButton(
onPressed: calculateDistance,
child: Text('Calculer la distance entre deux points'),
),
ElevatedButton(
onPressed: openSettings,
child: Text('Ouvrir les paramètres'),
),
ElevatedButton(
onPressed: checkLocationAccuracy,
child: Text('Vérifier la précision de la localisation'),
),
],
),
),
);
}
}
Voici plus en détails comment ce code fonctionne.
Demander des permissions à l’utilisateur
Avant de pouvoir géolocaliser l’utilisateur, il va falloir lui demander la permission de le faire. Voici les différentes fonctions mises à disposition par Geolocator, pour cela.
Vérifier si les services de localisation sont activés
La fonction checkLocationService()
permet de vérifier si les services de localisation de l’appareil sont activés, sans quoi il est impossible d’accéder à la position de l’utilisateur.
bool isLocationServiceEnabled = await Geolocator.isLocationServiceEnabled();
setState(() {
_locationMessage = isLocationServiceEnabled
? 'Les services de localisation sont activés.'
: 'Les services de localisation sont désactivés.';
});
}
bool isLocationServiceEnabled = await Geolocator.isLocationServiceEnabled()
vérifie si l’utilisateur a activé les services de localisation sur son appareil. Un message différent est affiché selon le résultat.
Vérifier et demander des permissions
La fonction checkAndRequestPermission()
permet de vérifier si l’application a la permission d’accéder à la localisation de l’utilisateur. Si ce n’est pas le cas, elle demande la permission.
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
setState(() {
_permissionMessage = 'Permission de localisation refusée. Demande de permission...';
});
permission = await Geolocator.requestPermission();
}
setState(() {
if (permission == LocationPermission.whileInUse || permission == LocationPermission.always) {
_permissionMessage = 'Permission de localisation accordée.';
} else {
_permissionMessage = 'Permission de localisation refusée de façon permanente.';
}
});
}
- La fonction
Geolocator.checkPermission()
vérifie si l’application a déjà la permission d’utiliser la localisation de l’utilisateur. - Si la permission est refusée
(permission == LocationPermission.denied)
, le code va essayer de la demander avecGeolocator.requestPermission()
. - Après avoir vérifié ou demandé la permission, un message est affiché pour indiquer si la permission a été accordée, refusée, ou refusée de manière permanente.
Ouvrir les paramètres de l’application ou de localisation
La fonction openSettings()
permet d’ouvrir les paramètres de l’application ou les paramètres de localisation de l’appareil, pour permettre à l’utilisateur de modifier les paramètres si nécessaire.
Future<void> openSettings() async {
await Geolocator.openAppSettings();
await Geolocator.openLocationSettings();
}
await Geolocator.openAppSettings()
: Ouvre les paramètres de l’application pour que l’utilisateur puisse modifier les permissions.await Geolocator.openLocationSettings()
: Ouvre les paramètres de localisation pour que l’utilisateur puisse activer ou désactiver les services de localisation.
Récupérer une position
Maintenant que nous disposons de la permission de l’utilisateur, nous pouvons passer à la partie qui nous intéresse : Récupérer sa position.
Récupérer la localisation actuelle
La fonction getCurrentLocation()
permet de récupérer la position actuelle de l’utilisateur.
Future<void> getCurrentLocation() async {
try {
final LocationSettings locationSettings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 100,
);
Position position = await Geolocator.getCurrentPosition(locationSettings: locationSettings);
setState(() {
_locationMessage = 'Latitude: ${position.latitude}, Longitude: ${position.longitude}';
});
} catch (e) {
setState(() {
_locationMessage = 'Erreur: $e';
});
}
}
final LocationSettings locationSettings
permet de définir les paramètres de la localisation. Par exemple, ici je choisis une précision élevée (LocationAccuracy.high
) et je spécifie que je veux une mise à jour de la localisation tous les 100 mètres (distanceFilter: 100
).Position position = await Geolocator.getCurrentPosition(locationSettings: locationSettings)
permet de récupèrer la position actuelle de l’utilisateur en fonction des paramètres définis.setState()
met à jour l’interface avec les informations de la position. Si la position est récupérée avec succès, on affiche la latitude et la longitude. Si une erreur se produit, un message d’erreur s’affiche à la place.
Récupérer la dernière position connue
La fonction getLastKnownLocation()
permet de récupérer la dernière position enregistrée sur l’appareil.
Future<void> getLastKnownLocation() async {
try {
Position? position = await Geolocator.getLastKnownPosition();
if (position != null) {
setState(() {
_locationMessage = 'Dernière position connue : Latitude: ${position.latitude}, Longitude: ${position.longitude}';
});
} else {
setState(() {
_locationMessage = 'Aucune position précédente disponible.';
});
}
} catch (e) {
setState(() {
_locationMessage = 'Erreur: $e';
});
}
}
Position? position = await Geolocator.getLastKnownPosition()
tente de récupérer la dernière position connue. Cette position est généralement stockée lorsque l’application obtient la localisation, mais elle peut être nulle si l’appareil n’a jamais récupéré de position avant.- Si une position est trouvée, elle est affichée avec la latitude et la longitude grâce à
setState()
. En revanche, si la position est nulle, un message indiquant qu’aucune position n’est disponible est affiché à la place.
Écouter les mises à jour de localisation
La fonction listenToLocationUpdates()
permet de suivre en temps réel les changements de position de l’utilisateur.
Future<void> listenToLocationUpdates() async {
final LocationSettings locationSettings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 100,
);
StreamSubscription<Position> positionStream = Geolocator.getPositionStream(locationSettings: locationSettings).listen(
(Position? position) {
setState(() {
_locationMessage = position == null
? 'Inconnu'
: 'Latitude: ${position.latitude}, Longitude: ${position.longitude}';
});
},
);
}
StreamSubscription<Position> positionStream = Geolocator.getPositionStream(locationSettings: locationSettings).listen(...)
permet de créer un flux qui va écouter les mises à jour de la position de l’utilisateur. À chaque fois que la position change, la fonction spécifiée dans listen()
est exécutée.
Calculer la distance entre deux points
Enfin, la fonction calculateDistance()
permet de calculer la distance entre deux coordonnées géographiques.
Future<void> calculateDistance() async {
double distanceInMeters = Geolocator.distanceBetween(
52.2165157, 6.9437819, 52.3546274, 4.8285838,
);
setState(() {
_locationMessage = 'Distance calculée : $distanceInMeters mètres';
});
}
distanceInMeters
prend quatre paramètres : la latitude et la longitude de deux points géographiques. Elle retourne la distance en mètres entre ces deux points.