Atelier de programmation sur la confidentialité sur Android

1. Intro

Points abordés

  • Pourquoi la confidentialité est de plus en plus importante pour les utilisateurs
  • Les bonnes pratiques concernant la confidentialité disponibles sur les dernières versions d'Android
  • Comment intégrer les bonnes pratiques liées à la confidentialité dans des applications existantes pour les rendre plus respectueuses de la vie privée

Objectifs de l'atelier

Dans cet atelier de programmation, vous allez commencer avec un exemple d'application permettant aux utilisateurs d'enregistrer leurs souvenirs photo.

L'atelier débute avec les écrans suivants :

  • Écran d'autorisation : écran qui demande à l'utilisateur d'accorder toutes les autorisations avant de passer à l'écran d'accueil.
  • Écran d'accueil : écran qui affiche tous les journaux photo de l'utilisateur et qui lui permet d'ajouter de nouveaux journaux photo.
  • Écran d'ajout de journal : écran qui permet à l'utilisateur de créer un nouveau journal photo. Les utilisateurs peuvent y parcourir les photos existantes de leur bibliothèque, en prendre une à l'aide de l'appareil photo et ajouter leur ville actuelle au journal.
  • Écran d'appareil photo : écran qui permet à l'utilisateur de prendre une photo et de l'enregistrer dans le journal photo.

L'application fonctionne, mais elle comporte de nombreuses erreurs liées à la confidentialité que nous allons améliorer ensemble.

À mesure que vous progresserez dans l'atelier de programmation, vous allez découvrir ce qui suit :

  • L'importance de la confidentialité pour vos applications
  • Les principales fonctionnalités de confidentialité et bonnes pratiques Android
  • Comment mettre en œuvre ces bonnes pratiques dans une application existante :
  • Demander des autorisations en contexte
  • Limiter l'accès à la position de l'utilisateur
  • Utiliser le sélecteur de photos et d'autres améliorations de l'espace de stockage
  • Utiliser les API d'audit d'accès aux données

Lorsque vous aurez terminé, vous disposerez d'une application qui :

  • met en œuvre les bonnes pratiques de confidentialité répertoriées ci-dessus ;
  • préserve la confidentialité et protège les utilisateurs en traitant leurs données privées avec soin, ce qui améliore l'expérience utilisateur.

Ce dont vous avez besoin

Souhaitable

2. Pourquoi la confidentialité est-elle importante ?

Des études montrent que les utilisateurs se soucient de leur vie privée. Une enquête menée par le Pew Research Institute a révélé que 84 % des Américains estiment qu'ils ont peu ou pas de contrôle sur les données collectées par les entreprises et les applications. Leur principal sujet d'inquiétude est de ne pas savoir ce qu'il advient de leurs données au-delà de leur utilisation directe. Par exemple, ils craignent que ces données ne soient utilisées à d'autres fins, par exemple afin de créer des profils pour la publicité ciblée, ou même qu'elles soient vendues à d'autres parties. Et une fois les données dans la nature, il semble n'y avoir aucun moyen de les supprimer.

Ce problème de confidentialité affecte déjà de manière significative les décisions des utilisateurs concernant les services ou applications qu'ils utilisent. D'ailleurs, cette même étude du Pew Research Institute a révélé que plus de la moitié des adultes américains (52 %) ont décidé de ne pas utiliser un produit ou service pour des raisons de confidentialité. Par exemple, ils sont inquiets de voir autant de données les concernant être collectées.

Par conséquent, il est essentiel d'améliorer et de démontrer la confidentialité de votre application pour améliorer l'expérience de vos utilisateurs. Des études montrent que cela peut également vous aider à développer votre base d'utilisateurs.

Un grand nombre des fonctionnalités et des bonnes pratiques que nous allons étudier dans cet atelier de programmation sont directement liées à la réduction de la quantité de données auxquelles votre application accède ou à l'amélioration du sentiment de contrôle des utilisateurs sur leurs données privées. Ces deux améliorations répondent directement aux préoccupations des utilisateurs lors des études que nous avons vues précédemment.

3. Configurer votre environnement

Pour vous aider à démarrer le plus rapidement possible, nous avons préparé un projet de démarrage. Au cours de cette étape, vous allez télécharger le code de l'intégralité de l'atelier de programmation, y compris le projet de démarrage, puis exécuter l'application de démarrage sur votre émulateur ou votre appareil.

Si git est installé, vous pouvez simplement exécuter la commande ci-dessous. Pour vérifier si git est installé, saisissez git –version dans le terminal ou la ligne de commande, et vérifiez qu'il s'exécute correctement.

git clone https://github.com/android/privacy-codelab

Si vous n'avez pas git, cliquez sur le lien ci-dessous pour télécharger l'ensemble du code de cet atelier de programmation :

Pour configurer l'atelier de programmation :

  1. Ouvrez le projet dans le répertoire PhotoLog_Start d'Android Studio.
  2. Exécutez la configuration d'exécution PhotoLog_Start sur un appareil ou un émulateur exécutant Android 12 (S) ou une version ultérieure.

d98ce953b749b2be.png

Vous devriez voir un écran vous demandant d'accorder des autorisations pour exécuter l'application. Cela signifie que vous avez correctement configuré l'environnement.

4. Bonne pratique : demandez des autorisations en contexte

Beaucoup d'entre vous savent que les autorisations d'exécution sont essentielles pour déverrouiller de nombreuses fonctionnalités clés qui sont nécessaires pour une expérience utilisateur de qualité. Mais saviez-vous que le moment et la façon dont votre application demande ces autorisations peut impacter l'expérience utilisateur ?

Voyons comment l'application PhotoLog_Start demande les autorisations, pour vous montrer pourquoi elle ne dispose pas d'un modèle d'autorisations optimal :

  1. Juste après le lancement, l'utilisateur reçoit immédiatement des invites lui demandant d'accorder plusieurs autorisations. Cela peut le dérouter et lui faire perdre sa confiance dans notre application, voire l'inciter à la désinstaller dans le pire des cas.
  2. L'application ne permet pas à l'utilisateur de continuer tant que toutes les autorisations ne sont pas accordées. Le problème, c'est que l'utilisateur ne fait peut-être pas encore suffisamment confiance à notre application dès son lancement pour accorder l'accès à toutes ces informations sensibles.

Comme vous l'avez probablement deviné, la liste ci-dessus représente les améliorations que nous allons apporter ensemble pour optimiser le processus de demande d'autorisations de l'application. Entrons à présent dans le vif du sujet.

Les bonnes pratiques recommandées par Android indiquent qu'il faut demander des autorisations en contexte la première fois que les utilisateurs interagissent avec une fonctionnalité. En effet, si une application demande l'autorisation d'activer une fonctionnalité avec laquelle l'utilisateur interagit déjà, cette demande n'est pas surprenante. Cela améliore l'expérience utilisateur. Dans l'application PhotoLog, nous devons attendre la première fois que les utilisateurs cliquent sur l'appareil photo ou sur les boutons de localisation avant de demander des autorisations.

Commençons par supprimer l'écran des autorisations qui oblige les utilisateurs à approuver toutes les autorisations avant d'accéder à la page d'accueil. Cette logique est actuellement définie dans MainActivity.kt. Voyons donc comment procéder :

val startNavigation =
   if (permissionManager.hasAllPermissions) {
       Screens.Home.route
   } else {
       Screens.Permissions.route
   }

L'application vérifie si l'utilisateur a accordé toutes les autorisations avant de lui permettre de passer à la page d'accueil. Comme indiqué précédemment, cette pratique ne respecte pas nos bonnes pratiques en matière d'expérience utilisateur. Implémentons à présent le code suivant, qui permet aux utilisateurs d'interagir avec notre application sans accorder toutes les autorisations :

val startNavigation = Screens.Home.route

Comme nous n'avons plus besoin de l'écran des autorisations, nous pouvons également supprimer cette ligne de NavHost :

composable(Screens.Permissions.route) { PermissionScreen(navController) }

Supprimez ensuite cette ligne de la classe Screens :

object Permissions : Screens("permissions")

Enfin, nous pouvons également supprimer le fichier PermissionsScreen.kt.

Maintenant, supprimez et réinstallez votre application, ce qui permet de réinitialiser les autorisations précédemment accordées. Vous devriez être en mesure d'accéder immédiatement à l'écran d'accueil, mais lorsque vous appuyez sur les boutons de la caméra ou de localisation sur l'écran d'ajout de journal, rien ne se passe, car l'application ne dispose plus de la logique pour demander des autorisations à l'utilisateur. Nous allons résoudre ce problème.

Ajouter une logique pour demander l'autorisation d'accéder à l'appareil photo

Commençons par l'autorisation d'accès à l'appareil photo. En nous basant sur les exemples de code figurant dans la documentation sur les demandes d'autorisation, nous devons d'abord enregistrer le rappel d'autorisations pour utiliser le contrat RequestPermission().

Évaluons la logique dont nous avons besoin :

  • Si l'utilisateur accepte l'autorisation, nous devons enregistrer l'autorisation dans l'architecture ViewModel. Nous allons également accéder à l'écran de l'appareil photo si l'utilisateur n'a pas encore atteint le nombre maximal de photos pouvant être ajoutées.
  • Si l'utilisateur refuse l'autorisation, nous pouvons l'informer que cette fonctionnalité n'est pas disponible, car l'autorisation a été refusée.

Pour exécuter cette logique, nous pouvons ajouter ce bloc de code à : // TODO: Step 1. Register ActivityResult to request Camera permission

val requestCameraPermission =
   rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
       if (isGranted) {
           viewModel.onPermissionChange(CAMERA, isGranted)
           canAddPhoto {
               navController.navigate(Screens.Camera.route)
           }
       }
       else {
           coroutineScope.launch {
               snackbarHostState.showSnackbar("Camera currently disabled due to denied permission.")
           }
       }
   }

Nous devons maintenant vérifier que l'application dispose de l'autorisation d'accès à l'appareil photo avant d'accéder à l'écran de l'appareil photo, puis demander cette autorisation si l'utilisateur ne l'a pas encore accordée. Pour implémenter cette logique, nous pouvons ajouter le bloc de code suivant à : // TODO: Step 2. Check & request for Camera permission before navigating to the camera screen

canAddPhoto {
   when {
       state.hasCameraAccess -> navController.navigate(Screens.Camera.route)
       // TODO: Step 4. Trigger rationale screen for Camera if needed
       else -> requestCameraPermission.launch(CAMERA)
   }
}

Essayez à nouveau d'exécuter l'application, puis cliquez sur l'icône en forme de caméra de l'écran d'ajout de journal. Une boîte de dialogue doit s'afficher pour demander l'autorisation d'accéder à la caméra. Félicitations ! C'est bien mieux que de demander aux utilisateurs d'approuver toutes les autorisations avant même d'avoir essayé l'application, n'est-ce pas ?

Mais peut-on faire mieux ? Absolument. Nous pouvons vérifier si le système recommande une justification pour expliquer pourquoi notre application a besoin d'accéder à l'appareil photo. Cela permet d'augmenter potentiellement les taux d'activation pour l'autorisation et de préserver la capacité de vos applications à redemander l'autorisation à un moment plus opportun.

Pour cela, nous allons créer un écran expliquant pourquoi notre application a besoin d'accéder à l'appareil photo de l'utilisateur. Pour ce faire, ajoutez le bloc de code suivant à : // TODO: Step 3. Add explanation dialog for Camera permission

var showExplanationDialogForCameraPermission by remember { mutableStateOf(false) }
if (showExplanationDialogForCameraPermission) {
   CameraExplanationDialog(
       onConfirm = {
           requestCameraPermission.launch(CAMERA)
           showExplanationDialogForCameraPermission = false
       },
       onDismiss = { showExplanationDialogForCameraPermission = false },
   )
}

Maintenant que nous disposons de la boîte de dialogue, nous devons vérifier s'il est pertinent d'afficher la justification avant de demander l'autorisation d'accéder à l'appareil photo. Pour ce faire, nous appelons l'API shouldShowRequestPermissionRationale() de ActivityCompat. Si la valeur est "true", nous devons aussi définir showExplanationDialogForCameraPermission sur "true" pour afficher la boîte de dialogue d'explication.

Ajoutons le bloc de code suivant entre le cas state.hasCameraAccess et le cas else, ou à l'endroit où le TODO suivant a été précédemment ajouté dans les instructions : // TODO: Step 4. Add explanation dialog for Camera permission

ActivityCompat.shouldShowRequestPermissionRationale(context.getActivity(),
           CAMERA) -> showExplanationDialogForCameraPermission = true

La logique complète du bouton de l'appareil photo devrait maintenant ressembler à :

canAddPhoto {
   when {
       state.hasCameraAccess -> navController.navigate(Screens.Camera.route)
       ActivityCompat.shouldShowRequestPermissionRationale(context.getActivity(),
           CAMERA) -> showExplanationDialogForCameraPermission = true
       else -> requestCameraPermission.launch(CAMERA)
   }
}

Félicitations ! Nous avons terminé de gérer l'autorisation d'accès à l'appareil photo, conformément à toutes les bonnes pratiques Android. Supprimez l'application, puis réinstallez-la. Essayez d'appuyer sur le bouton de l'appareil photo depuis la page d'ajout de journal. Si vous refusez l'autorisation, l'application ne vous empêche pas d'utiliser les autres fonctionnalités telles que l'ouverture de l'album photo.

Toutefois, la prochaine fois que vous cliquerez sur l'icône en forme de caméra après avoir refusé l'autorisation, vous devriez voir l'invite d'explication que nous venons d'ajouter. Notez que l'invite d'autorisation du système ne s'affiche que lorsque l'utilisateur clique sur "Continuer" dans l'invite d'explication. Si l'utilisateur clique sur "Pas maintenant", nous l'autorisons à utiliser l'application sans interruption supplémentaire. Cela permet à l'application d'éviter les refus supplémentaires de l'utilisateur et de préserver notre capacité à redemander l'autorisation à un autre moment, lorsque l'utilisateur est plus susceptible de l'accorder.

  • Remarque : Le comportement exact de l'API shouldShowRequestPermissionRationale() est un détail d'implémentation interne qui est susceptible de changer.

Ajouter une logique pour demander l'autorisation d'accéder à la position

Faisons de même pour la localisation. Nous pouvons commencer par enregistrer ActivityResult pour les autorisations d'accéder à la position en ajoutant le bloc de code suivant à : // TODO: Step 5. Register ActivityResult to request Location permissions

val requestLocationPermissions =
   rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
       if (isGranted) {
           viewModel.onPermissionChange(ACCESS_COARSE_LOCATION, isGranted)
           viewModel.onPermissionChange(ACCESS_FINE_LOCATION, isGranted)
           viewModel.fetchLocation()
       }
       else {
           coroutineScope.launch {
               snackbarHostState.showSnackbar("Location currently disabled due to denied permission.")
           }
       }
   }

Nous pouvons ensuite ajouter la boîte de dialogue d'explication sur les autorisations d'accéder à la position en ajoutant le bloc de code suivant à : // TODO: Step 6. Add explanation dialog for Location permissions

var showExplanationDialogForLocationPermission by remember { mutableStateOf(false) }
if (showExplanationDialogForLocationPermission) {
   LocationExplanationDialog(
       onConfirm = {
           // TODO: Step 10. Change location request to only request COARSE location.
           requestLocationPermissions.launch(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION))
           showExplanationDialogForLocationPermission = false
       },
       onDismiss = { showExplanationDialogForLocationPermission = false },
   )
}

Vérifions à présent la procédure, expliquons (si nécessaire) et demandons les autorisations d'accéder à la position. Si l'autorisation est accordée, nous pouvons récupérer le lieu et remplir le journal de photos. Ajoutons à présent le bloc de code suivant à : // TODO: Step 7. Check, request, and explain Location permissions

when {
   state.hasLocationAccess -> viewModel.fetchLocation()
   ActivityCompat.shouldShowRequestPermissionRationale(context.getActivity(),
       ACCESS_COARSE_LOCATION) ||
   ActivityCompat.shouldShowRequestPermissionRationale(
       context.getActivity(), ACCESS_FINE_LOCATION) ->
       showExplanationDialogForLocationPermission = true
   else -> requestLocationPermissions.launch(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION))
}

La section "Autorisations" de cet atelier de programmation est terminée. Essayez de réinitialiser votre application pour voir les résultats.

Résumé des améliorations que nous avons apportées à l'expérience utilisateur et les avantages pour votre application :

  • Demande des autorisations en contexte (lorsque les utilisateurs interagissent avec la fonctionnalité) plutôt qu'immédiatement après le lancement de l'application → Réduit la confusion et l'abandon des utilisateurs.
  • Création d'écrans d'explication pour justifier aux utilisateurs pourquoi notre application a besoin d'autorisations → Améliore la transparence pour les utilisateurs.
  • Utilisation de l'API shouldShowRequestPermissionRationale() pour déterminer quand le système estime que votre application doit afficher un écran d'explication → Augmente les taux d'acceptation des autorisations et réduit le risque de refus d'autorisation permanent.

5. Bonne pratique : réduisez l'accès de votre application à la position

La localisation est l'une des autorisations les plus sensibles. C'est pourquoi Android l'inclut dans le Tableau de bord Confidentialité.

Pour résumer, dans Android 12, nous avons fourni aux utilisateurs des commandes de localisation supplémentaires. Les utilisateurs ont désormais la possibilité de partager avec les applications des données de localisation moins précises en sélectionnant position approximative au lieu de position exacte lorsqu'une application demande à accéder à sa position.

La position approximative fournit à l'application une estimation de la position de l'utilisateur dans un rayon de trois kilomètres carrés, ce qui devrait être suffisant pour bon nombre des fonctionnalités de votre application. Nous encourageons tous les développeurs dont les applications ont besoin d'accéder aux données de localisation d'examiner leur cas d'utilisation et de ne demander ACCESS_FINE_LOCATION que si l'utilisateur interagit activement avec une fonctionnalité qui nécessite sa position exacte.

ea5cc51fce3f219e.png

Graphique permettant de visualiser une estimation approximative de la position, centrée sur le centre-ville de Los Angeles, en Californie.

L'accès approximatif à la position suffit pour notre application PhotoLog. En effet, nous n'avons besoin que de la ville de l'utilisateur pour lui rappeler l'origine du "souvenir". Toutefois, l'application demande actuellement à l'utilisateur les autorisations ACCESS_COARSE_LOCATION et ACCESS_FINE_LOCATION. Il est temps de changer cela.

Tout d'abord, nous devons modifier le résultat d'activité pour la position et fournir la fonction ActivityResultContracts.RequestPermission() en tant que paramètre au lieu de ActivityResultContracts.RequestMultiplePermissions(), afin de refléter le fait que nous ne demanderons que ACCESS_COARSE_LOCATION.

Remplaçons l'objet requestLocationsPermissions actuel (indiqué par // TODO: Step 8. Change activity result to only request Coarse Location) par le bloc de code suivant :

val requestLocationPermissions =
   rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
       if (isGranted) {
           viewModel.onPermissionChange(ACCESS_COARSE_LOCATION, isGranted)
       }
   }

Ensuite, nous allons modifier les méthodes launch() pour ne demander que ACCESS_COARSE_LOCATION au lieu des deux autorisations d'accéder à la position.

Remplaçons :

requestLocationPermissions.launch(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION))

Avec :

requestLocationPermissions.launch(ACCESS_COARSE_LOCATION)

Deux instances de la méthode launch() dans PhotoLog doivent être modifiées. L'une d'elles se trouve dans la logique onConfirm() dans le LocationExplanationDialog, désignée par // TODO: Step 9. Change location request to only request COARSE location, l'autre se trouve dans l'élément de liste "Location" signalé par // TODO: Step 10. Change location request to only request COARSE location

Enfin, maintenant que nous ne demandons plus l'autorisation ACCESS_FINE_LOCATION pour PhotoLog, nous allons supprimer cette section de la méthode onPermissionChange() dans AddLogViewModel.kt :

Manifest.permission.ACCESS_FINE_LOCATION -> {
   uiState = uiState.copy(hasLocationAccess = isGranted)
}

N'oubliez pas de supprimer également ACCESS_FINE_LOCATION du fichier manifeste de l'application :

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

La section "Position" de l'atelier de programmation est terminée. Désinstallez, puis réinstallez votre application pour voir les résultats.

6. Bonne pratique : limitez l'utilisation des autorisations de stockage

Il est courant que les applications fonctionnent avec les photos stockées sur un appareil. Pour permettre aux utilisateurs de choisir les images et les vidéos souhaitées, ces applications implémentent souvent leurs propres sélecteurs de fichier, ce qui nécessite de demander l'autorisation d'accéder à un espace de stockage étendu. Les utilisateurs n'aiment pas autoriser l'accès à toutes leurs photos et les développeurs n'aiment pas avoir à maintenir un outil de sélection de fichiers indépendant.

Android 13 introduit le sélecteur de photos, un outil qui permet à l'utilisateur de sélectionner des fichiers multimédias sans qu'il soit nécessaire d'autoriser une application à accéder à l'ensemble de sa bibliothèque multimédia. Elle est également rétroportée vers Android 11 et 12 à l'aide des mises à jour du système Google Play.

Pour cette fonctionnalité dans notre application PhotoLog, nous allons utiliser l'élément ActivityResultContract PickMultipleVisualMedia. Il utilise l'outil de sélection de photos Android lorsqu'il est installé sur l'appareil et s'appuie sur l'intent ACTION_OPEN_DOCUMENT sur les anciens appareils.

Enregistrez d'abord notre ActivityResultContrat dans le fichier AddLogScreen. Pour ce faire, ajoutez le bloc de code suivant après cette ligne : // TODO: Step 11. Register ActivityResult to launch the Photo Picker

val pickImage = rememberLauncherForActivityResult(
   PickMultipleVisualMedia(MAX_LOG_PHOTOS_LIMIT),
    viewModel::onPhotoPickerSelect
)

Remarque : MAX_LOG_PHOTOS_LIMIT représente ici la limite maximale de photos que nous avons choisies pour l'ajout à un journal (ici, 3).

Nous devons maintenant remplacer le sélecteur interne intégré à l'application par l'outil de sélection de photos Android. Ajoutez le code suivant après le bloc : // TODO: Step 12. Replace the below line showing our internal UI by launching the Android Photo Picker instead

pickImage.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))

En ajoutant ces deux lignes de code, nous disposons d'un moyen sans autorisation d'accéder aux photos de l'appareil, qui offre une expérience utilisateur plus agréable et ne nécessite pas de maintenance du code.

Étant donné que PhotoLog n'a plus besoin de l'ancienne grille de photos et des autorisations de stockage pour accéder aux photos, nous devons maintenant supprimer tout le code contenant notre ancienne grille de photos. Cela inclut l'autorisation d'accès au stockage dans le fichier manifeste et la logique qui se trouve derrière, car ce n'est plus nécessaire dans notre application.

7. Recommandation : utiliser les API d'audit d'accès aux données dans les versions de débogage

Disposez-vous d'une grande application offrant de nombreuses fonctionnalités et collaborateurs (ou avez-vous prévu d'en créer une dans le futur ?), rendant difficile de savoir à quel type de données utilisateur l'application accède ? Saviez-vous que même si les accès aux données proviennent d'API ou de SDK qui étaient utilisés autrefois, mais qui ne jouent désormais plus aucun rôle dans votre application, celle-ci sera toujours responsable de l'accès aux données ?

Nous comprenons qu'il est difficile de suivre tous les endroits où vos applications accèdent à des données privées, y compris tous les SDK inclus et d'autres dépendances. Par conséquent, pour vous aider à fournir une meilleure transparence vis-à-vis de la manière dont votre application et ses dépendances accèdent aux données privées des utilisateurs, Android 11 propose un audit de l'accès aux données. Cette API permet aux développeurs d'effectuer des actions spécifiques, telles que l'impression dans un fichier journal, chaque fois que l'un des événements suivants se produit :

  • Le code de votre application accède à des données privées.
  • Le code d'une bibliothèque ou d'un SDK dépendants accède à des données privées.

Commençons par revoir les principes de base de l'API d'audit des accès aux données sur Android. Pour adopter l'audit des accès aux données, nous allons enregistrer une instance de AppOpsManager.OnOpNotedCallback (Android 11 ou version ultérieure).

Nous devons également ignorer les trois méthodes du rappel, qui sont appelées par le système lorsque l'application accède aux données utilisateur de différentes manières. Ce sont les méthodes suivantes :

  • onNoted() : appelée lorsqu'une application appelle des API synchrones (réciproques) qui accèdent aux données utilisateur. Il s'agit généralement d'appels d'API qui ne nécessitent pas de rappel.
  • onAsyncNoted() : appelée lorsqu'une application appelle des API asynchrones (à sens unique) qui accèdent aux données utilisateur. Il s'agit généralement d'appels d'API nécessitant des rappels, et l'accès aux données a lieu lorsque le rappel est appelé.
  • onSelfNoted() : assez improbable, ce qui se produit lorsqu'une application transmet son propre UID à noteOp(), par exemple.

Déterminons maintenant laquelle de ces méthodes s'applique aux accès aux données de l'application PhotoLog. PhotoLog accède principalement aux données de l'utilisateur à deux endroits : une fois lorsque nous activons la caméra et une autre fois quand nous accédons à la position de l'utilisateur. Il s'agit d'appels d'API asynchrones, car ils consomment tous deux des ressources relativement importantes. Nous nous attendons donc à ce que le système appelle onAsyncNoted() lorsque nous accédons aux données utilisateur correspondantes.

Voyons maintenant comment adopter les API d'audit des accès aux données pour PhotoLog.

Tout d'abord, nous devons créer une instance de AppOpsManager.OnOpNotedCallback() et remplacer les trois méthodes ci-dessus.

Pour les trois méthodes dans l'objet, passons directement à l'impression de l'opération spécifique qui a accédé aux données utilisateur privées. Cette opération nous donnera des informations supplémentaires sur le type de données utilisateur concerné. De plus, comme nous nous attendons à ce qu'onAsyncNoted() soit appelé lorsque notre application accède aux informations sur l'appareil photo et la localisation, nous allons faire quelque chose de spécial et imprimer un emoji de carte pour les accès à la position et un emoji d'appareil photo pour les accès à l'appareil photo. Pour ce faire, nous pouvons ajouter le bloc de code suivant à : // TODO: Step 1. Create Data Access Audit Listener Object

@RequiresApi(Build.VERSION_CODES.R)
object DataAccessAuditListener : AppOpsManager.OnOpNotedCallback() {
   // For the purposes of this codelab, we are just logging to console,
   // but you can also integrate other logging and reporting systems here to track
   // your app's private data access.
   override fun onNoted(op: SyncNotedAppOp) {
       Log.d("DataAccessAuditListener","Sync Private Data Accessed: ${op.op}")
   }

   override fun onSelfNoted(op: SyncNotedAppOp) {
       Log.d("DataAccessAuditListener","Self Private Data accessed: ${op.op}")
   }

   override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) {
       var emoji = when (asyncNotedAppOp.op) {
           OPSTR_COARSE_LOCATION -> "\uD83D\uDDFA"
           OPSTR_CAMERA -> "\uD83D\uDCF8"
           else -> "?"
       }

       Log.d("DataAccessAuditListener", "Async Private Data ($emoji) Accessed:
       ${asyncNotedAppOp.op}")
   }
}

Nous devrons ensuite implémenter la logique de rappel que nous venons de créer. Pour obtenir de meilleurs résultats, nous vous conseillons de procéder à cette opération le plus tôt possible, car le système commence à effectuer le suivi de l'accès aux données après l'enregistrement du rappel. Pour enregistrer le rappel, nous pouvons ajouter le bloc de code suivant à : // TODO: Step 2. Register Data Access Audit Callback.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
   val appOpsManager = getSystemService(AppOpsManager::class.java) as AppOpsManager
   appOpsManager.setOnOpNotedCallback(mainExecutor, DataAccessAuditListener)
}

8. Conclusion

Passons rapidement en revue les points abordés. Ce que nous avons découvert :

  • Pourquoi la confidentialité est importante pour vos applications.
  • Les fonctionnalités de confidentialité d'Android.
  • De nombreuses bonnes pratiques clés en matière de confidentialité pour les applications :
  • Demander des autorisations en contexte
  • Limiter l'accès à la position de l'utilisateur
  • Utiliser le sélecteur de photos et d'autres améliorations de l'espace de stockage
  • Utiliser les API d'audit d'accès aux données
  • Comment mettre en œuvre ces bonnes pratiques dans une application existante afin d'en renforcer la confidentialité.

Nous espérons que vous avez apprécié cet atelier d'amélioration de la confidentialité et de l'expérience utilisateur de PhotoLog, et que vous y avez appris de nombreux concepts.

Pour trouver notre code de référence (facultatif) :

Si vous ne l'avez pas déjà fait, vous pouvez consulter le code de la solution pour cet atelier de programmation dans le dossier PhotoLog_End. Si vous avez suivi attentivement les instructions de cet atelier de programmation, le code du dossier PhotoLog_Start doit être identique à celui du dossier PhotoLog_End.

En savoir plus

Et voilà ! Pour en savoir plus sur les bonnes pratiques décrites ci-dessus, consultez la page de destination des règles de confidentialité d'Android.