android.os.FileUriExposedException: file:///... exposed beyond app through Intent.getData() signifie que l’application a transmis un URI file:// hors de son processus au moyen d’un Intent ou d’un flux interapplications similaire. Android lève cette exception de diagnostic pour les applications ciblant Android N, niveau d’API 24, ou une version ultérieure. La première mesure la plus sûre consiste à examiner les données de l’Intent, EXTRA_STREAM, ClipData et tout URI de sortie de l’appareil photo afin de trouver la valeur file:// restante avant de modifier la configuration du fournisseur.
Signification de android.os.FileUriExposedException
Cette exception concerne l’exposition de fichiers entre applications, et non tous les échecs d’accès aux fichiers sous Android. Elle apparaît fréquemment dans les flux utilisant ACTION_VIEW, ACTION_SEND, ACTION_SEND_MULTIPLE, la capture avec l’appareil photo, les pièces jointes, l’impression et la feuille de partage.
L’exception a été ajoutée au niveau d’API 24 et est levée pour les applications ciblant Android N ou une version ultérieure. La version d’Android installée sur l’appareil et le targetSdkVersion de l’application sont deux conditions liées, mais elles ne sont pas interchangeables. La documentation Android de FileUriExposedException indique que la solution prise en charge consiste à utiliser un URI content:// accompagné d’un accès temporaire pour l’application destinataire.
L’absence de cette exception avec une autre configuration du SDK ne rend pas le partage par URI file:// sûr. Android décrit cette exception comme un diagnostic, et non comme un mécanisme de sécurité à part entière.
Repérer l’URI file:// qui quitte l’application
Quand cette vérification s’applique : effectuez-la avant de configurer FileProvider, y compris lorsque le message se termine par Intent.getData() ou ClipData.Item.getUri().
Prérequis : le texte de l’exception et le code source du flux qui crée l’Intent sortant.
- Examinez l’URI affiché dans l’exception et vérifiez que son schéma est
file. - Examinez les entrées de la pile d’appels appartenant à l’application qui précèdent immédiatement l’exception afin de repérer l’endroit où l’URI sortant est créé ou joint.
- Recherchez les appels à
Uri.fromFile()et l’analyse de valeurs commençant parfile://. - Examinez séparément les données de l’Intent,
EXTRA_STREAM, chaque élément deClipDataet tout URI de sortie de l’appareil photo. - Notez la source et l’emplacement réel du fichier. Ces informations déterminent s’il convient d’utiliser un URI déjà autorisé ou FileProvider.
Résultat attendu : vous repérez tous les URI file:// présents dans le flux défaillant ainsi que l’endroit où chacun d’eux est ajouté à l’Intent.
Risque et avertissement : cette étape de diagnostic est en lecture seule. Ne supposez pas qu’il suffit de modifier les données de l’Intent si un autre champ contenant un URI subsiste. La présence éventuelle de ClipData doit être confirmée en examinant l’Intent réel.
Choisir la source appropriée pour l’URI content://
Quand cette correction s’applique : utilisez cette méthode lorsque la source fournit déjà un URI content:// autorisé, par exemple pour un document sélectionné par l’utilisateur ou un élément multimédia partagé.
Prérequis : vérifiez que l’URI existant reste autorisé pour l’opération prévue.
- Conservez l’URI
content://existant au lieu de le convertir en chemin de système de fichiers. - Utilisez le framework d’accès au stockage, ou Storage Access Framework, pour les documents sélectionnés par l’utilisateur.
- Utilisez un URI MediaStore approprié pour les contenus multimédias partagés.
- Placez cet URI autorisé dans le champ requis de l’Intent, puis effectuez les vérifications d’autorisations temporaires décrites plus bas.
Résultat attendu : le flux interapplications conserve un URI content:// autorisé sans introduire un nouveau FileProvider.
Risque et retour en arrière : le risque est faible. Si la source ne peut pas fournir d’URI autorisé adapté à l’opération, utilisez FileProvider uniquement lorsque l’application possède le fichier. Ne faites pas passer systématiquement tous les chemins par FileProvider.
Configurer AndroidX FileProvider dans le fichier manifeste
Quand cette correction s’applique : utilisez AndroidX FileProvider lorsque l’application possède un fichier et doit le rendre accessible à une autre application.
Prérequis : AndroidX FileProvider doit être disponible, vous devez pouvoir modifier le fichier manifeste et créer une ressource XML définissant les chemins du fournisseur. L’autorité exacte dépend de l’application.
- Déclarez un fournisseur dont l’attribut
android:namedésigne FileProvider ou la sous-classe FileProvider de l’application. - Définissez
android:authoritiessur une autorité propre à l’application. - Définissez
android:exported="false". - Définissez
android:grantUriPermissions="true". - Ajoutez l’entrée de métadonnées FileProvider qui référence la ressource XML définissant les chemins du fournisseur.
- Vérifiez que l’autorité utilisée ensuite pour générer l’URI correspond exactement à celle déclarée dans le fichier manifeste.
La documentation d’AndroidX FileProvider décrit ce modèle de fournisseur et ses autorisations temporaires d’accès aux URI.
Résultat attendu : l’application dispose d’un fournisseur non exporté capable de générer des URI content:// autorisés pour les fichiers configurés.
Risque et retour en arrière : le risque est faible. Supprimez le fournisseur et ses métadonnées si la fonctionnalité de partage est retirée. Ne publiez pas et ne réutilisez pas une valeur d’autorité universelle, car elle doit correspondre à la configuration de l’application.
Limiter le fichier XML file_paths aux fichiers à partager
Quand cette correction s’applique : effectuez cette étape chaque fois que FileProvider est utilisé.
Prérequis : vous devez connaître le répertoire exact contenant le fichier à partager.
- Définissez uniquement le ou les répertoires nécessaires à la fonctionnalité de partage.
- Choisissez le répertoire le plus restreint qui contient encore le fichier prévu.
- Évitez les racines trop larges incluant des fichiers sans rapport appartenant à l’application ou au stockage partagé.
- Avant de générer son URI de contenu, vérifiez que le fichier se trouve bien dans l’une des racines configurées.
L’entrée XML exacte ne peut pas être universelle, car elle dépend de l’emplacement où l’application stocke le fichier. La page Android consacrée aux changements liés à l’exposition des URI de fichiers dans Android 7.0 recommande la migration vers FileProvider plutôt que le maintien de l’exposition des URI de fichiers.
Résultat attendu : FileProvider peut résoudre le fichier prévu, tandis que les emplacements sans rapport restent en dehors de la portée configurée du fournisseur.
Risque et retour en arrière : le risque est moyen, car une racine trop large peut exposer davantage de fichiers que prévu. Restreignez le fichier XML des chemins si l’examen ou les tests révèlent une portée excessive. Ne l’élargissez pas uniquement pour contourner un échec lié à une racine configurée.
Remplacer file:// et n’accorder que l’accès temporaire nécessaire
Créer et joindre l’URI content:// de FileProvider
Quand cette correction s’applique : utilisez-la après avoir configuré l’autorité dans le fichier manifeste et défini des chemins de fournisseur restreints pour un fichier appartenant à l’application.
Prérequis : le fichier doit se trouver dans une racine autorisée du fournisseur, et l’autorité utilisée pour générer l’URI doit correspondre à celle du fichier manifeste.
- Créez l’URI avec FileProvider au lieu d’utiliser
Uri.fromFile()ou une valeurfile://construite manuellement. - Placez l’URI
content://obtenu dans les données de l’Intent,EXTRA_STREAMou le champ de sortie de l’appareil photo requis par le flux existant. - Pour plusieurs fichiers, remplacez chaque URI exposé, et pas seulement le premier élément.
- Examinez
ClipDataet tout autre champ susceptible de contenir un URI afin que l’ancien URI de fichier ne subsiste nulle part.
Résultat attendu : l’Intent sortant transporte des URI content:// de FileProvider au lieu d’URI file://.
Risque et retour en arrière : le risque est faible et cette opération ne supprime pas le fichier. Ne rétablissez pas le partage interapplications par URI file:// en production. L’ancienne source d’URI ne convient qu’à un débogage local isolé qui n’expose pas l’URI.
Accorder des autorisations temporaires sur l’URI
Quand cette correction s’applique : utilisez des autorisations temporaires lorsque l’application destinataire doit lire ou modifier le contenu référencé par l’Intent.
Prérequis : l’Intent doit transporter un URI content:// valide, et le niveau d’accès nécessaire au destinataire doit être connu.
- Ajoutez
FLAG_GRANT_READ_URI_PERMISSIONlorsque le destinataire doit lire le fichier. - Ajoutez
FLAG_GRANT_WRITE_URI_PERMISSIONuniquement lorsque le destinataire doit modifier le fichier. - Joignez l’URI au moyen de
ClipDatalorsque cela est nécessaire à la propagation de l’autorisation dans le flux pris en charge. - N’ajoutez pas d’autorisations plus étendues sur le système de fichiers ni d’accès en écriture sans rapport avec l’opération.
Résultat attendu : le destinataire obtient l’accès temporaire minimal nécessaire tandis que le fournisseur reste non exporté.
Risque et retour en arrière : le risque est faible lorsque l’accès reste limité. Retirez les indicateurs d’autorisation de lecture ou d’écriture lorsque le destinataire n’a plus besoin de cette capacité. La propagation au moyen de ClipData dépend du flux et doit être testée sur les versions d’Android prises en charge.
Vérifier que l’application destinataire peut accéder à l’URI content://
Quand cette vérification s’applique : testez l’ensemble du flux après avoir remplacé l’URI et accordé les autorisations temporaires.
Prérequis : le composant destinataire prévu doit être disponible pour les tests.
- Vérifiez que chaque URI sortant utilise le schéma
content. - Vérifiez que l’autorité de l’URI généré correspond exactement à l’autorité du fournisseur déclarée dans le fichier manifeste.
- Vérifiez que le fichier se trouve dans une racine configurée du fournisseur.
- Contrôlez de nouveau les données de l’Intent,
EXTRA_STREAM,ClipDataet les URI de sortie afin de repérer toute valeurfile://restante. - Testez l’application destinataire réelle avec l’autorisation de lecture et n’ajoutez l’autorisation d’écriture que si une modification est nécessaire.
- Vérifiez que le destinataire peut effectuer l’opération prévue sans élargir la racine du fournisseur ni les autorisations.
Résultat attendu : le flux sortant n’expose plus d’URI de fichier et le composant destinataire peut accéder à l’URI de contenu autorisé avec l’autorisation minimale requise. Ce résultat doit être confirmé par des tests : modifier uniquement le schéma ne garantit pas l’accès du destinataire.
Risque et avertissement : la vérification présente un faible risque. Si l’exception d’origine a disparu mais que l’accès échoue encore, contrôlez manuellement l’autorité, les métadonnées du fournisseur, les chemins configurés, les autorisations sur l’URI et l’emplacement réel du fichier. Ne désactivez pas la détection avec StrictMode.VmPolicy, ne réduisez pas le targetSdkVersion, n’exposez pas de racines trop larges et n’accordez pas l’accès en écriture par défaut. Ces mesures masquent ou affaiblissent le problème au lieu de corriger la conception du partage interapplications.

