L'application se bloque lorsque j'essaie d'ouvrir un fichier. Cela fonctionne en dessous d'Android Nougat, mais sur Android Nougat, il se bloque. Il ne se bloque que lorsque j'essaie d'ouvrir un fichier à partir de la carte SD, pas à partir de la partition système. Un problème de permission?
Exemple de code:
File file = new File("/storage/emulated/0/test.txt");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "text/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // Crashes on this line
Journal:
android.os.FileUriExposedException: fichier: ///storage/emulated/0/test.txt exposé au-delà de l'application via Intent.getData ()
Éditer:
Lorsque vous ciblez Android Nougat, les file://
URI ne sont plus autorisés. Nous devrions content://
plutôt utiliser des URI. Cependant, mon application doit ouvrir des fichiers dans les répertoires racine. Des idées?
android
android-file
android-7.0-nougat
Thomas Vos
la source
la source
Réponses:
Si c'est le cas
targetSdkVersion >= 24
, nous devons utiliser laFileProvider
classe pour donner accès au fichier ou au dossier particulier pour les rendre accessibles à d'autres applications. Nous créons notre propre classe héritantFileProvider
afin de nous assurer que notre FileProvider n'entre pas en conflit avec les FileProviders déclarés dans les dépendances importées comme décrit ici .Étapes pour remplacer l'
file://
URI par l'content://
URI:Ajouter une classe s'étendant
FileProvider
Ajoutez une
<provider>
balise FileProvider dansAndroidManifest.xml
<application>
balise under . Spécifiez une autorité unique pour l'android:authorities
attribut afin d'éviter les conflits, les dépendances importées peuvent spécifier${applicationId}.provider
et d'autres autorités couramment utilisées.provider_paths.xml
fichier dansres/xml
dossier. Il peut être nécessaire de créer un dossier s'il n'existe pas. Le contenu du fichier est indiqué ci-dessous. Il décrit que nous aimerions partager l'accès au stockage externe au dossier racine(path=".")
avec le nom external_files .La dernière étape consiste à modifier la ligne de code ci-dessous dans
à
Éditer: si vous utilisez l'intention d'ouvrir le fichier au système, vous devrez peut-être ajouter la ligne de code suivante:
Veuillez vous référer, le code complet et la solution ont été expliqués ici.
la source
(Build.VERSION.SDK_INT > M)
condition est donc inutile.FileProvider
ne doit être étendu que si vous souhaitez remplacer l'un des comportements par défaut, sinon utilisezandroid:name="android.support.v4.content.FileProvider"
. Voir developer.android.com/reference/android/support/v4/content/…Outre la solution utilisant le
FileProvider
, il existe une autre façon de contourner ce problème . Tout simplementdans
Application.onCreate()
. De cette façon, la machine virtuelle ignore le fichierURI
exposition au .Méthode
active la vérification de l'exposition des fichiers, qui est également le comportement par défaut si nous ne configurons pas de VmPolicy.
J'ai rencontré un problème: si j'utilise un
content://
URI
pour envoyer quelque chose, certaines applications ne peuvent tout simplement pas le comprendre. Et déclasser letarget SDK
version n'est pas autorisé. Dans ce cas, ma solution est utile.Mise à jour:
Comme mentionné dans le commentaire, StrictMode est un outil de diagnostic et n'est pas censé être utilisé pour ce problème. Lorsque j'ai posté cette réponse il y a un an, de nombreuses applications ne peuvent recevoir que des uris de fichier. Ils ont juste planté lorsque j'ai essayé de leur envoyer un uri FileProvider. Cela est maintenant corrigé dans la plupart des applications, nous devons donc opter pour la solution FileProvider.
la source
VmPolicy
.StrictMode.enableDefaults();
, que j'exécute uniquement sur mes versions de développement, empêche cet incident de se produire - j'ai donc maintenant une application de production qui se bloque mais ne se bloque pas lors du développement. Donc, fondamentalement, l'activation d'un outil de diagnostic cache un problème grave. Merci @hqzxzwb de m'avoir aidé à démystifier cela.Si
targetSdkVersion
est supérieur à 24 , FileProvider est utilisé pour accorder l'accès.Créer un fichier xml (Chemin: res \ xml) provider_paths.xml
Ajouter un fournisseur dans AndroidManifest.xml
Si vous utilisez androidx , le chemin d'accès FileProvider doit être:
et remplacer
à
Modifier: lorsque vous incluez l'URI,
Intent
assurez-vous d'ajouter la ligne ci-dessous:et vous êtes prêt à partir. J'espère que cela aide.
la source
Si votre application cible l'API 24+ et que vous souhaitez / devez toujours utiliser file: // intents, vous pouvez utiliser une méthode hacky pour désactiver la vérification de l'exécution:
La méthode
StrictMode.disableDeathOnFileUriExposure
est masquée et documentée comme:Le problème est que mon application n'est pas boiteuse, mais ne veut pas être paralysée en utilisant du contenu: // des intentions qui ne sont pas comprises par de nombreuses applications. Par exemple, l'ouverture d'un fichier mp3 avec le schéma content: // offre beaucoup moins d'applications que lors de son ouverture sur le schéma file: //. Je ne veux pas payer pour les défauts de conception de Google en limitant les fonctionnalités de mon application.
Google souhaite que les développeurs utilisent le schéma de contenu, mais le système n'est pas préparé pour cela, pendant des années, les applications ont été conçues pour utiliser des fichiers et non du «contenu», les fichiers peuvent être modifiés et enregistrés, tandis que les fichiers diffusés via le schéma de contenu ne peuvent pas l'être (peut ils?).
la source
ContentResolver
a les deuxopenInputStream()
etopenOutputStream()
. Une façon moins compliquée de procéder consiste simplement à configurer vous - même les règles de la machine virtuelle et à ne pas activer lafile
Uri
règle.Si vous avez
targetSdkVersion
24 ans ou plus, vous ne pouvez pas utiliser defile:
Uri
valeurs dansIntents
sur les appareils Android 7.0+ .Vos choix sont:
Déposez votre
targetSdkVersion
à 23 ou moins, ouMettez votre contenu sur le stockage interne, puis utilisez-le
FileProvider
pour le rendre sélectivement disponible pour d'autres applicationsPar exemple:
(à partir de cet exemple de projet )
la source
/system
partition? Chaque application devrait pouvoir accéder à cette partition sans root./system
être lisible dans le monde. Cela étant dit, je suppose que vous obtiendrez toujours cette exception. Je soupçonne qu'ils vérifient simplement le schéma et n'essaient pas de déterminer si le fichier est vraiment lisible dans le monde. Cependant,FileProvider
cela ne vous aidera pas, car vous ne pouvez pas lui apprendre à servir/system
. Vous pouvez créer une stratégie personnalisée pour moiStreamProvider
ou lancer la vôtreContentProvider
pour surmonter le problème./data
,/system
), à cause de ce "bon changement".Vous devez d'abord ajouter un fournisseur à votre AndroidManifest
créez maintenant un fichier dans le dossier de ressources xml (si vous utilisez Android Studio, vous pouvez appuyer sur Alt + Entrée après avoir mis en surbrillance file_paths et sélectionnez créer une option de ressource xml)
Ensuite, dans le fichier file_paths, entrez
Cet exemple concerne le chemin externe que vous pouvez consulter ici pour plus d'options. Cela vous permettra de partager des fichiers qui se trouvent dans ce dossier et son sous-dossier.
Il ne reste plus qu'à créer l'intention comme suit:
EDIT : J'ai ajouté le dossier racine de la carte SD dans le file_paths. J'ai testé ce code et cela fonctionne.
la source
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
En outre, je recommande à quiconque cherche des réponses de lire d' abord FileProvider et de comprendre ce que vous traitez ici avec les autorisations de fichiers dans Android N et au-dessus. Il existe des options pour le stockage interne par rapport au stockage externe et également pour les chemins de fichiers standard contre les chemins de cache.java.lang.IllegalArgumentException: Failed to find configured root ...
et la seule chose qui a fonctionné était<files-path path="." name="files_root" />
sur le fichier xml au lieu de<external-path ...
. Mon fichier a été enregistré dans la mémoire interne.La réponse @palash k est correcte et a fonctionné pour les fichiers de stockage interne, mais dans mon cas, je souhaite également ouvrir des fichiers à partir d'un stockage externe, mon application s'est bloquée lors de l'ouverture d'un fichier à partir d'un stockage externe comme sdcard et usb, mais j'ai réussi à résoudre le problème en modifiant provider_paths.xml à partir de la réponse acceptée
changer le provider_paths.xml comme ci-dessous
et en classe java (pas de changement comme réponse acceptée juste une petite modification)
Cela m'aide à résoudre le plantage des fichiers provenant de stockages externes, j'espère que cela aidera quelqu'un ayant le même problème que le mien :)
la source
<root-path
s'il vous plaît? Ça marche.<external-path path="Android/data/${applicationId}/" name="files_root" />
n'a eu aucun effet pour les fichiers ouverts à partir du stockage externe.Android/data/${applicationId}/
dans SDcard.Ma solution était de «Uri.parse» le chemin du fichier en tant que chaîne, au lieu d'utiliser Uri.fromFile ().
Il semble que fromFile () utilise un pointeur de fichier, qui, je suppose, pourrait être peu sûr lorsque les adresses mémoire sont exposées à toutes les applications. Mais une chaîne de chemin de fichier n'a jamais blessé personne, donc cela fonctionne sans lancer FileUriExposedException.
Testé sur les niveaux d'API 9 à 27! Ouvre correctement le fichier texte pour le modifier dans une autre application. Ne nécessite pas FileProvider, ni la bibliothèque de support Android.
la source
Collez simplement le code ci-dessous dans l'activité onCreate ()
Il ignorera l'exposition URI
la source
Collez simplement le code ci-dessous dans l'activité
onCreate()
.Il ignorera l'exposition URI.
Bon codage :-)
la source
L'utilisation de fileProvider est la solution. Mais vous pouvez utiliser cette solution de contournement simple:
remplacer:
par
la source
J'ai utilisé la réponse de Palash donnée ci-dessus mais elle était quelque peu incomplète, j'ai dû fournir une autorisation comme celle-ci
la source
Collez simplement le code ci-dessous dans l'activité onCreate ()
Il ignorera l'exposition URI
la source
ajoutez ces deux lignes dans onCreate
Méthode de partage
la source
Voici ma solution:
dans Manifest.xml
dans res / xml / provider_paths.xml
dans mon fragment j'ai le code suivant:
C'est tout ce dont vous avez besoin.
Aussi pas besoin de créer
Je teste sur Android 5.0, 6.0 et Android 9.0 et c'est un succès.
la source
Pour télécharger le pdf depuis le serveur, ajoutez le code ci-dessous dans votre classe de service. J'espère que cela vous sera utile.
Et oui, n'oubliez pas d'ajouter des autorisations et un fournisseur dans votre manifeste.
la source
@xml/provider_paths
?Je ne sais pas pourquoi, j'ai fait tout exactement la même chose que Pkosta ( https://stackoverflow.com/a/38858040 ) mais j'ai continué à recevoir des erreurs:
java.lang.SecurityException: Permission Denial: opening provider redacted from ProcessRecord{redacted} (redacted) that is not exported from uid redacted
J'ai perdu des heures sur cette question. Le coupable? Kotlin.
intent
était en train de définirgetIntent().addFlags
au lieu de fonctionner sur mon playIntent nouvellement déclaré.la source
J'ai mis cette méthode pour que le chemin imageuri pénètre facilement dans le contenu.
la source
Il y a 3 étapes principales ici comme mentionné ci-dessous
Étape 1: entrée du manifeste
Étape 2: créer un fichier XML res / xml / provider_paths.xml
Étape 3: changements de code
la source
Je sais que c'est une question assez ancienne mais cette réponse s'adresse aux futurs téléspectateurs. J'ai donc rencontré un problème similaire et après des recherches, j'ai trouvé une alternative à cette approche.
Votre intention ici, par exemple: pour afficher votre image à partir de votre chemin dans Kotlin
Fonction principale ci-dessous
De même, au lieu d'une image, vous pouvez utiliser n'importe quel autre format de fichier comme pdf et dans mon cas, cela a très bien fonctionné
la source
J'ai passé presque une journée à essayer de comprendre pourquoi je recevais cette exception. Après beaucoup de lutte, cette configuration a parfaitement fonctionné ( Kotlin ):
AndroidManifest.xml
file_paths.xml
Intention elle-même
J'explique tout le processus ici .
la source
https://stackoverflow.com/a/38858040/395097 cette réponse est complète.
Cette réponse est pour - vous avez déjà une application qui ciblait en dessous de 24, et maintenant vous passez à targetSDKVersion> = 24.
Dans Android N, seul l'uri du fichier exposé à une application tierce est modifié. (Pas la façon dont nous l'utilisions auparavant). Modifiez donc uniquement les endroits où vous partagez le chemin avec une application tierce (appareil photo dans mon cas)
Dans notre application, nous envoyions l'URI à l'application Appareil photo, à cet endroit, nous nous attendons à ce que l'application Appareil photo stocke l'image capturée.
Maintenant, nous avons 2 uri différents pour le même fichier. # 1 est partagé avec l'application Appareil photo. Si l'objectif de la caméra est réussi, nous pouvons accéder à l'image à partir du # 2.
J'espère que cela t'aides.
la source
Xamarin.Android
Remarque: Le chemin xml / provider_paths.xml (.axml) n'a pas pu être résolu, même après avoir créé le dossier xml sous Resources (il peut peut-être être placé dans un emplacement existant comme Values , n'a pas essayé), j'ai donc recours à ce qui fonctionne pour l'instant. Les tests ont montré qu'il ne doit être appelé qu'une fois par exécution d'application (ce qui est logique étant qu'il modifie l'état de fonctionnement de la machine virtuelle hôte).
Remarque: xml doit être en majuscule, donc Resources / Xml / provider_paths.xml
la source
La réponse de @Pkosta est une façon de procéder.
Outre l'utilisation
FileProvider
, vous pouvez également insérer le fichierMediaStore
(en particulier pour les fichiers image et vidéo), car les fichiers de MediaStore sont accessibles à toutes les applications:Par exemple, vous pouvez insérer un fichier vidéo dans MediaStore comme ceci:
contentUri
est commecontent://media/external/video/media/183473
, qui peut être passé directement àIntent.putExtra
:Cela fonctionne pour moi et évite les tracas de l'utilisation
FileProvider
.la source
Laissez-le simplement ignorer l'exposition URI ... Ajoutez-le après la création
la source
Essayez cette solution
METTEZ CES AUTORISATIONS DANS LE MANIFESTE
INTENTION DE CAPTURER L'IMAGE
OBTENEZ UNE IMAGE CAPTURÉE DANS ONACTIVITYRESULT
PROCÉDÉ POUR OBTENIR UN URI D'IMAGE
la source
Dans mon cas, je me suis débarrassé de l'exception en remplaçant
SetDataAndType
par justeSetData
.la source