Android 10 et 11 leur permettent de mieux contrôler l'accès à la position de leur appareil.
Lorsqu'une application exécutée sous Android 11 demande l'accès à la position, les utilisateurs disposent de quatre options:
- Toujours autoriser
- Autoriser si appli utilisée dans Android 10
- À usage unique (Android 11)
- Refuser
Android 10
Android 11
Dans cet atelier de programmation, vous découvrirez comment recevoir des mises à jour de la position et prendre en charge la localisation sur n'importe quelle version d'Android, en particulier Android 10 et 11. À la fin de l'atelier de programmation, vous vous attendreez à avoir une application qui respecte les bonnes pratiques actuelles en matière de récupération des mises à jour de position.
Conditions préalables
- Bonne connaissance du développement Android
- Bonne connaissance des activités, des services et des autorisations
Objectifs de l'atelier
- Suivez les bonnes pratiques concernant la localisation sur Android.
- Gérer les autorisations d'accéder au premier plan (lorsque l'utilisateur demande que votre application accède à la position de l'appareil pendant que votre application est utilisée)
- Modifiez une application existante pour permettre les demandes d'accès à la position en ajoutant du code pour les abonner et les désabonner.
- Ajoutez la compatibilité avec l'application pour Android 10 et 11 en ajoutant une logique pour accéder à la position au premier plan ou en cours d'utilisation.
Prérequis
- Android Studio version 3.4 ou ultérieure, pour exécuter le code
- Un appareil/un émulateur exécutant un aperçu développeur d'Android 10 et 11
Cloner les éléments du projet de démarrage
Pour démarrer le plus rapidement possible, vous pouvez vous appuyer sur ce projet de démarrage. Si Git est installé, vous pouvez simplement exécuter la commande suivante:
git clone https://github.com/googlecodelabs/while-in-use-location
N'hésitez pas à consulter directement la page GitHub.
Si vous n'avez pas Git, vous pouvez obtenir le projet au format ZIP:
Importer le projet
Ouvrez Android Studio, sélectionnez Open an existing Android Studio project (Ouvrir un projet Android Studio existant), puis ouvrez le répertoire du projet.
Une fois le projet chargé, une alerte peut apparaître, indiquant que Git ne suit pas toutes les modifications locales. Vous pouvez cliquer sur Ignorer. (Vous n'envoyez aucune modification dans le dépôt Git.)
En haut à gauche de la fenêtre du projet, vous devriez voir l'image ci-dessous si vous êtes dans la vue Android. Si vous êtes dans la vue Projet, vous devez développer le projet pour voir la même chose.
Il existe deux dossiers (base
et complete
). Ils sont tous appelés "module".
Notez qu'Android Studio peut mettre plusieurs secondes à compiler le projet en arrière-plan pour la première fois. Pendant ce temps, le message suivant s'affiche dans la barre d'état en bas d'Android Studio:
Attendez qu'Android Studio ait fini d'indexer et de créer le projet avant de modifier le code. Android Studio pourra alors extraire tous les composants nécessaires.
Si le message Actualiser pour changer la langue prend effet ? s'affiche, sélectionnez Oui.
Comprendre le projet de démarrage
Vous êtes prêt à demander des informations de localisation dans l'application. Utilisez le module base
comme point de départ. À chaque étape, ajoutez du code au module base
. À la fin de cet atelier de programmation, le code du module base
doit correspondre au contenu du module complete
. Vous pouvez utiliser le module complete
pour vérifier votre travail ou vous y reporter en cas de problèmes.
Les principaux composants sont les suivants:
MainActivity
: interface utilisateur permettant à l'application d'accéder à la position de l'appareilLocationService
: service qui s'abonne et se désabonne des modifications de lieu, et qui se présente comme un service de premier plan (avec notification) si l'utilisateur quitte l'activité de l'appli. Vous ajoutez le code de zone géographique ici.Util
: ajoute des fonctions d'extension pour la classeLocation
et enregistre l'emplacement dansSharedPreferences
(couche de données simplifiée).
Configuration de l'émulateur
Pour savoir comment configurer un émulateur Android, consultez Exécuter sur un émulateur.
Exécuter le projet de démarrage
Exécutez votre application.
- Connectez votre appareil Android à votre ordinateur ou démarrez un émulateur. (Vérifiez que l'appareil utilise Android 10 ou une version ultérieure.)
- Dans la barre d'outils, sélectionnez la configuration
base
dans le menu déroulant, puis cliquez sur Run (Exécuter) :
- L'application suivante s'affiche sur votre appareil:
Notez que l'écran de sortie n'affiche aucune information de géolocalisation. C'est parce que vous n'avez pas encore ajouté le code de zone géographique.
concepts
Le but de cet atelier de programmation est de vous montrer comment recevoir des mises à jour de votre position. Cet outil est compatible avec Android 10 et Android 11.
Toutefois, avant de commencer à coder, il est judicieux de revoir les principes de base.
Types d'accès à la position
Vous vous souvenez peut-être des quatre options d'accès aux données de localisation présentées au début de l'atelier de programmation. Découvrez leur signification:
- Autoriser seulement si l'appli est en cours d'utilisation
- Cette option est recommandée pour la plupart des applications. Également appelée "pendant l'utilisation", cette option a été ajoutée dans Android 10 et permet aux développeurs de récupérer la position uniquement lorsque l'application est en cours d'utilisation. Une application est considérée comme active si l'une des conditions se vérifie:
- Une activité est visible.
- Un service de premier plan est en cours d'exécution avec une notification en cours.
- Une seule fois
- Dans Android 11, cette option est identique à la règle Autoriser uniquement si l'application est utilisée, mais pour une durée limitée. Pour plus d'informations, consultez Autorisations ponctuelles.
- Refuser
- Cette option empêche l'accès aux informations de géolocalisation.
- Toujours autoriser
- Cette option autorise l'accès à la position en permanence, mais nécessite une autorisation supplémentaire pour Android 10 ou version ultérieure. Vous devez également vous assurer que vous disposez d'un cas d'utilisation valide et que vous respectez les règles relatives à la localisation. Vous n'allez pas aborder cette option dans cet atelier de programmation, car il s'agit d'un cas d'utilisation plus rare. Cependant, si vous disposez d'un cas d'utilisation valide et que vous souhaitez comprendre comment gérer correctement la position permanente, y compris l'accès aux données de localisation en arrière-plan, consultez l'exemple LocationUpdatesBackgroundKotlin.
Services, services de premier plan et liaisons
Pour assurer une compatibilité totale avec les mises à jour de la position Autoriser uniquement si vous utilisez l'application, vous devez tenir compte des moments où l'utilisateur quitte votre application. Si vous souhaitez continuer à recevoir des mises à jour dans ce cas, vous devez créer un Service
au premier plan et l'associer à un Notification
.
En outre, si vous souhaitez utiliser le même Service
pour demander la mise à jour de la position lorsque votre application est visible et que l'utilisateur quitte votre application, vous devez lier ou dissocier ce Service
à l'élément d'UI.
Comme cet atelier de programmation se concentre uniquement sur l'obtention des mises à jour de position, vous pouvez trouver tout le code dont vous avez besoin dans la classe ForegroundOnlyLocationService.kt
. Vous pouvez parcourir cette classe et la MainActivity.kt
pour voir comment elles fonctionnent ensemble.
Pour en savoir plus, consultez Présentation des services et Présentation des services liés.
Autorisations
Pour recevoir les mises à jour de position depuis un NETWORK_PROVIDER
ou un GPS_PROVIDER
, vous devez demander l'autorisation de l'utilisateur en déclarant l'autorisation ACCESS_COARSE_LOCATION
ou ACCESS_FINE_LOCATION
, respectivement, dans votre fichier manifeste Android. Sans ces autorisations, votre appli ne pourra pas demander l'accès à la localisation au moment de l'exécution.
Ces autorisations concernent les cas Une seule fois et Autoriser uniquement si l'application est utilisée lorsque vous utilisez cette dernière sur un appareil équipé d'Android 10 ou version ultérieure.
Emplacement
Votre application peut accéder à l'ensemble des services de localisation compatibles via des classes dans le package com.google.android.gms.location
.
Examinez les classes principales:
FusedLocationProviderClient
- Il s'agit du composant central du framework de localisation. Une fois créé, vous pouvez l'utiliser pour demander des modifications de position et obtenir la dernière position connue.
LocationRequest
- Il s'agit d'un objet de données qui contient des paramètres de qualité de service pour les requêtes (intervalles pour les mises à jour, les priorités et la justesse). Cet identifiant est transmis à
FusedLocationProviderClient
lorsque vous demandez la mise à jour de vos établissements. LocationCallback
- Elle est utilisée pour recevoir des notifications lorsque l'emplacement de l'appareil a changé ou ne peut plus être déterminé. Cette valeur est transmise à un
LocationResult
où vous pouvez obtenir l'Location
à enregistrer dans votre base de données.
Maintenant que vous savez ce que vous faites, commencez avec le code !
Cet atelier de programmation porte sur l'option de localisation la plus courante Autoriser seulement si l'appli est en cours d'utilisation.
Pour recevoir des mises à jour de position, votre application doit comporter une activité visible ou un service exécuté au premier plan (avec une notification).
Autorisations
Le but de cet atelier de programmation est de vous montrer comment recevoir des mises à jour de la position, et non comment demander des autorisations d'accéder à la position. Le code basé sur les autorisations est donc déjà rédigé. N'hésitez pas à l'ignorer si vous le comprenez déjà.
Voici les principaux points forts de l'autorisation (aucune action n'est requise pour cette partie):
- Déclarez l'autorisation utilisée dans
AndroidManifest.xml
. - Avant d'essayer d'accéder aux informations de localisation, vérifiez si l'utilisateur a autorisé votre application à le faire. Si ce n'est pas le cas, demandez l'accès.
- Gérez le choix de l'autorisation utilisateur. Ce code est disponible sur la page
MainActivity.kt
.
Si vous recherchez TODO: Step 1.0, Review Permissions
dans AndroidManifest.xml
ou MainActivity.kt
, tout le code écrit pour les autorisations s'affiche.
Pour en savoir plus, consultez Présentation des autorisations.
À présent, commencez à écrire un code de localisation.
Consulter les variables clés nécessaires à la mise à jour des établissements
Dans le module base
, recherchez TODO: Step 1.1, Review variables
:
Fichier ForegroundOnlyLocationService.kt
.
Aucune action n'est requise pour cette étape. Pour comprendre les classes et les variables clés que vous utilisez pour recevoir des notifications sur les établissements, il vous suffit de consulter le bloc de code suivant et les commentaires associés.
// TODO: Step 1.1, Review variables (no changes).
// FusedLocationProviderClient - Main class for receiving location updates.
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
// LocationRequest - Requirements for the location updates, i.e., how often you
// should receive updates, the priority, etc.
private lateinit var locationRequest: LocationRequest
// LocationCallback - Called when FusedLocationProviderClient has a new Location.
private lateinit var locationCallback: LocationCallback
// Used only for local storage of the last known location. Usually, this would be saved to your
// database, but because this is a simplified sample without a full database, we only need the
// last location to create a Notification if the user navigates away from the app.
private var currentLocation: Location? = null
Vérifier l'initialisation de FusedLocationProviderClient
Dans le module base
, recherchez TODO: Step 1.2, Review the FusedLocationProviderClient
dans le fichier ForegroundOnlyLocationService.kt
. Le code doit se présenter comme suit:
// TODO: Step 1.2, Review the FusedLocationProviderClient.
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
Comme indiqué dans les commentaires précédents, il s'agit de la classe principale pour recevoir les mises à jour de position. La variable est déjà initialisée, mais il est important de vous familiariser avec son code pour l'initialiser. Vous ajouterez un code ici plus tard pour demander des mises à jour de la position.
Initialiser la LocationRequest
- Dans le module
base
, recherchezTODO: Step 1.3, Create a LocationRequest
dans le fichierForegroundOnlyLocationService.kt
. - Ajoutez le code suivant après le commentaire.
Le code d'initialisation LocationRequest
ajoute la qualité supplémentaire des paramètres de service dont vous avez besoin pour votre requête (intervalles, temps d'attente maximal et priorité).
// TODO: Step 1.3, Create a LocationRequest.
locationRequest = LocationRequest().apply {
// Sets the desired interval for active location updates. This interval is inexact. You
// may not receive updates at all if no location sources are available, or you may
// receive them less frequently than requested. You may also receive updates more
// frequently than requested if other applications are requesting location at a more
// frequent interval.
//
// IMPORTANT NOTE: Apps running on Android 8.0 and higher devices (regardless of
// targetSdkVersion) may receive updates less frequently than this interval when the app
// is no longer in the foreground.
interval = TimeUnit.SECONDS.toMillis(60)
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates more frequently than this value.
fastestInterval = TimeUnit.SECONDS.toMillis(30)
// Sets the maximum time when batched location updates are delivered. Updates may be
// delivered sooner than this interval.
maxWaitTime = TimeUnit.MINUTES.toMillis(2)
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
- Lisez attentivement les commentaires pour en comprendre le fonctionnement.
Initialiser le LocationCallback
- Dans le module
base
, recherchezTODO: Step 1.4, Initialize the LocationCallback
dans le fichierForegroundOnlyLocationService.kt
. - Ajoutez le code suivant après le commentaire.
// TODO: Step 1.4, Initialize the LocationCallback.
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
super.onLocationResult(locationResult)
if (locationResult?.lastLocation != null) {
// Normally, you want to save a new location to a database. We are simplifying
// things a bit and just saving it as a local variable, as we only need it again
// if a Notification is created (when user navigates away from app).
currentLocation = locationResult.lastLocation
// Notify our Activity that a new location was added. Again, if this was a
// production app, the Activity would be listening for changes to a database
// with new locations, but we are simplifying things a bit to focus on just
// learning the location side of things.
val intent = Intent(ACTION_FOREGROUND_ONLY_LOCATION_BROADCAST)
intent.putExtra(EXTRA_LOCATION, currentLocation)
LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(intent)
// Updates notification content if this service is running as a foreground
// service.
if (serviceRunningInForeground) {
notificationManager.notify(
NOTIFICATION_ID,
generateNotification(currentLocation))
}
} else {
Log.d(TAG, "Location information isn't available.")
}
}
}
Le LocationCallback
que vous créez ici est le rappel que FusedLocationProviderClient
appellera lorsqu'une nouvelle mise à jour de la position sera disponible.
Dans votre rappel, vous obtenez d'abord la dernière position à l'aide d'un objet LocationResult
. Ensuite, vous avertirez Activity
de la nouvelle position à l'aide d'une diffusion locale (si elle est active) ou mettre à jour Notification
si ce service est exécuté en tant que premier plan Service
.
- Lisez attentivement les commentaires pour en comprendre le rôle.
S'abonner aux modifications de localisation
Maintenant que tout est initialisé, vous devez indiquer à FusedLocationProviderClient
que vous souhaitez recevoir des mises à jour.
- Dans le module
base
, recherchezStep 1.5, Subscribe to location changes
dans le fichierForegroundOnlyLocationService.kt
. - Ajoutez le code suivant après le commentaire.
// TODO: Step 1.5, Subscribe to location changes.
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())
L'appel requestLocationUpdates()
informe FusedLocationProviderClient
que vous souhaitez recevoir des mises à jour de position.
Vous reconnaissez probablement que les champs LocationRequest
et LocationCallback
que vous avez définis précédemment. Ces valeurs permettent au FusedLocationProviderClient
de connaître les paramètres de qualité de service de votre requête et le nom à appeler lors de la mise à jour. Enfin, l'objet Looper
spécifie le thread pour le rappel.
Notez également que ce code figure dans une instruction try/catch
. Cette méthode nécessite un tel blocage, car un SecurityException
se produit lorsque votre appli n'est pas autorisée à accéder aux informations de géolocalisation.
Se désabonner des modifications apportées aux établissements
Lorsque l'application n'a plus besoin d'accéder aux informations de localisation, il est important de se désabonner des mises à jour de position.
- Dans le module
base
, recherchezTODO: Step 1.6, Unsubscribe to location changes
dans le fichierForegroundOnlyLocationService.kt
. - Ajoutez le code suivant après le commentaire.
// TODO: Step 1.6, Unsubscribe to location changes.
val removeTask = fusedLocationProviderClient.removeLocationUpdates(locationCallback)
removeTask.addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d(TAG, "Location Callback removed.")
stopSelf()
} else {
Log.d(TAG, "Failed to remove Location Callback.")
}
}
La méthode removeLocationUpdates()
configure une tâche pour indiquer à FusedLocationProviderClient
que vous ne souhaitez plus recevoir de mises à jour de position pour votre LocationCallback
. Le addOnCompleteListener()
attribue le rappel à la fin et exécute le Task
.
Comme à l'étape précédente, vous avez peut-être remarqué que ce code se trouve dans une instruction try/catch
. Cette méthode nécessite un tel blocage, car un SecurityException
se produit lorsque votre appli n'est pas autorisée à accéder aux informations de localisation
Vous vous demandez peut-être à quel moment les méthodes qui contiennent ce code sont appelées. Ils sont déclenchés dans la classe principale lorsque l'utilisateur appuie sur le bouton. Si vous voulez le voir, consultez la classe MainActivity.kt
.
Exécuter l'application
Exécutez votre application depuis Android Studio et essayez le bouton de localisation.
Les informations de localisation doivent s'afficher dans l'écran de sortie. Cette application est totalement fonctionnelle pour Android 9.
Dans cette section, vous trouverez la compatibilité avec Android 10.
Votre application est déjà abonnée aux modifications de lieu. Vous n'avez donc pas beaucoup de travail à effectuer.
En fait, il vous suffit de spécifier que votre service de premier plan est utilisé à des fins de géolocalisation.
SDK 29 cible
- Dans le module
base
, recherchezTODO: Step 2.1, Target SDK 10
dans le fichierbuild.gradle
. - Apportez les modifications suivantes:
- Définissez
compileSdkVersion
sur29
. - Définissez
buildToolsVersion
sur"29.0.3"
. - Définissez
targetSdkVersion
sur29
.
Le code doit se présenter comme suit:
android {
// TODO: Step 2.1, Target Android 10.
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.example.android.whileinuselocation"
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
...
}
Vous serez ensuite invité à synchroniser votre projet. Cliquez sur Synchroniser.
Après cela, votre application sera presque prête pour Android 10.
Ajouter un type de service au premier plan
Dans Android 10, vous devez inclure le type de service de votre premier plan si vous avez besoin d'un accès à la position pendant l'utilisation. Dans votre cas, elle est utilisée pour obtenir des informations sur les établissements.
Dans le module base
, recherchez TODO: 2.2, Add foreground service type
dans AndroidManifest.xml
et ajoutez le code suivant à l'élément <service>
:
android:foregroundServiceType="location"
Le code doit se présenter comme suit:
<application>
...
<!-- Foreground services in Android 10+ require type. -->
<!-- TODO: 2.2, Add foreground service type. -->
<service
android:name="com.example.android.whileinuselocation.ForegroundOnlyLocationService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="location" />
</application>
Et voilà ! Votre application est compatible avec la localisation Android 10 pendant son utilisation en suivant les bonnes pratiques liées à la localisation sur Android.
Exécuter l'application
Exécutez votre application depuis Android Studio et essayez le bouton de localisation.
Tout devrait fonctionner comme avant, mais elle est désormais compatible avec Android 10. Si vous n'avez pas accepté les autorisations auparavant associées aux emplacements, l'écran dédié aux autorisations devrait désormais s'afficher.
Dans cette section, vous ciblez Android 11.
Bonne nouvelle, vous n'avez pas besoin de modifier les fichiers, sauf le fichier build.gradle
!
SDK R cible
- Dans le module
base
, recherchezTODO: Step 2.1, Target SDK
dans le fichierbuild.gradle
. - Apportez les modifications suivantes:
- De
compileSdkVersion
à"android-R"
- De
targetSdkVersion
à"R"
Le code doit se présenter comme suit:
android {
// TODO: Step 2.1, Target Android 10.
compileSdkVersion "android-R"
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.android.whileinuselocation"
minSdkVersion 26
targetSdkVersion "R"
versionCode 1
versionName "1.0"
}
...
}
Vous serez ensuite invité à synchroniser votre projet. Cliquez sur Synchroniser.
Votre application sera ensuite prête pour Android 11 !
Exécuter l'application
Exécutez votre application à partir d'Android Studio, puis cliquez sur le bouton.
Tout devrait fonctionner comme avant, mais elle est désormais compatible avec Android 11. Si vous n'avez pas accepté les autorisations auparavant associées aux emplacements, l'écran dédié aux autorisations devrait désormais s'afficher.
En vérifiant et en demandant les autorisations d'accéder à la position comme indiqué dans cet atelier de programmation, votre application peut effectuer le suivi de son niveau d'accès à la position de l'appareil.
Cette page liste quelques bonnes pratiques clés liées aux autorisations d'accéder à la position. Pour savoir comment protéger les données de vos utilisateurs, consultez Bonnes pratiques concernant les autorisations des applications.
Demandez uniquement les autorisations dont vous avez besoin.
Ne demandez des autorisations que si nécessaire. Exemple :
- Ne demandez pas l'autorisation d'accéder à la position au démarrage de l'appli, sauf en cas d'absolue nécessité.
- Si votre application cible Android 10 ou une version ultérieure et que vous disposez d'un service de premier plan, déclarez une valeur
foregroundServiceType
de"location"
dans le fichier manifeste. - Ne demandez pas d'autorisations d'accéder à la position en arrière-plan, sauf si vous disposez d'un cas d'utilisation valide tel que décrit dans la section Un accès plus sécurisé et plus transparent à la position de l'utilisateur.
Permettre une dégradation élégante si l'autorisation n'est pas accordée
Pour offrir une expérience utilisateur de qualité, concevez votre application de sorte qu'elle puisse gérer correctement les situations suivantes:
- Votre appli n'a pas accès aux informations de localisation.
- Votre appli n'a pas accès aux données de localisation en arrière-plan.
Vous avez appris à recevoir des mises à jour de votre position sur Android en tenant compte des bonnes pratiques.
En savoir plus
- Exemple complet d'utilisation des données de localisation en arrière-plan si vous disposez d'un cas d'utilisation valide
- Demander des mises à jour de la position