Avant KitKat (ou avant la nouvelle galerie) le Intent.ACTION_GET_CONTENT
retourne un URI comme celui-ci
contenu: // média / externe / images / média / 3951.
L'utilisation de ContentResolver
et la requête pour ont
MediaStore.Images.Media.DATA
renvoyé l'URL du fichier.
Dans KitKat, cependant, la galerie renvoie un URI (via "Last") comme ceci:
content: //com.android.providers.media.documents/document/image: 3951
Comment dois-je gérer cela?
android
android-intent
android-gallery
android-contentresolver
Michael Greifeneder
la source
la source
Uri
devrait être ouvrable en tant que flux viaContentResolver
. Cela fait longtemps que je suis nerveux à propos des applications qui supposent qu'uncontent://
Uri
fichier qui représente un fichier peut toujours être converti en un fichierFile
.InputStream
surContentResolver
un vers un emplacement prédéterminé afin qu'il ait un nom de fichier connu. Cependant, cela me semble inutile. D'autres suggestions?InputStream
over JNI? Il n'y a malheureusement pas beaucoup d'options pour vous.InputStream
au lieu d'un fichier (ce qui est génial). Seule la lecture des balises EXIF est légèrement délicate et nécessite la bibliothèque de Drew Noakes . Merci beaucoup pour vos commentaires.Réponses:
Essaye ça:
Besoin probablement
pour
la source
Cela ne nécessite aucune autorisation spéciale et fonctionne avec Storage Access Framework, ainsi qu'avec le
ContentProvider
modèle non officiel (chemin de fichier dans_data
champ).Voir une version à jour de cette méthode ici .
la source
Authority: com.google.android.apps.docs.storage
etSegments: [document, acc=1;doc=667]
. Je ne suis pas sûr, mais supposez que ladoc
valeur est l'Uri
ID que vous pouvez interroger. Vous aurez probablement besoin d'autorisations pour la configuration, comme indiqué dans "Autoriser votre application sur Android" ici: developers.google.com/drive/integrate-android-ui . Veuillez mettre à jour ici si vous le comprenez._data
ne fonctionnerait pas quand ContentProvider ne le supporte pas. Il est recommandé de suivre les instructions @CommonsWare et de ne plus utiliser le chemin d'accès complet au fichier, car il pourrait s'agir d'un fichier dans le cloud Dropbox au lieu d'un vrai fichier.J'ai eu le même problème, j'ai essayé la solution ci-dessus, mais bien que cela fonctionne généralement, pour une raison quelconque, j'obtenais un refus d'autorisation sur le fournisseur de contenu Uri pour certaines images bien que la
android.permission.MANAGE_DOCUMENTS
permission ait été ajoutée correctement.Quoi qu'il en soit, j'ai trouvé une autre solution qui consiste à forcer l'ouverture de la galerie d'images au lieu de la vue des documents KITKAT avec:
puis chargez l'image:
ÉDITER
ACTION_OPEN_DOCUMENT
peut nécessiter que vous persistiez les indicateurs d'autorisations, etc. et entraîne généralement des exceptions de sécurité ...Une autre solution consiste à utiliser le
ACTION_GET_CONTENT
combiné avecc.getContentResolver().openInputStream(selectedImageURI)
lequel fonctionnera à la fois sur pré-KK et KK. Kitkat utilisera alors la nouvelle vue des documents et cette solution fonctionnera avec toutes les applications comme Photos, Galerie, Explorateur de fichiers, Dropbox, Google Drive, etc.) mais n'oubliez pas que lorsque vous utilisez cette solution, vous devez créer une image dans votreonActivityResult()
et la stocker sur Carte SD par exemple. La recréation de cette image à partir de l'URI enregistré lors du prochain lancement de l'application lèverait une exception de sécurité sur le résolveur de contenu même lorsque vous ajoutez des indicateurs d'autorisation comme décrit dans les documents de l'API Google (c'est ce qui s'est produit lorsque j'ai fait des tests)De plus, les consignes relatives aux API pour développeurs Android suggèrent:
la source
Intent.ACTION_GET_CONTENT
. Quoi qu'il en soit, j'ai gardé leIntent.createChooser()
wrapper sur le nouveauIntent
, pour permettre à l'utilisateur de choisir l'application pour la navigation, et j'ai travaillé comme prévu. Quelqu'un peut-il voir les inconvénients de cette solution?Tout comme Commonsware l'a mentionné, vous ne devez pas supposer que le flux via lequel vous obtenez
ContentResolver
est convertible en fichier.Ce que vous devez vraiment faire est d'ouvrir le
InputStream
depuis leContentProvider
, puis de créer un bitmap à partir de celui-ci. Et cela fonctionne aussi sur les versions 4.4 et antérieures, pas besoin de réflexion.Bien sûr, si vous manipulez de grandes images, vous devez les charger avec les fichiers appropriés
inSampleSize
: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html . Mais c'est un autre sujet.la source
Je pense que les réponses déjà publiées devraient amener les gens dans la bonne direction. Cependant, voici ce que j'ai fait pour le code hérité que je mettais à jour. Le code hérité utilisait l'URI de la galerie pour modifier puis enregistrer les images.
Avant 4.4 (et google drive), les URI ressemblaient à ceci: content: // media / external / images / media / 41
Comme indiqué dans la question, ils ressemblent plus souvent à ceci: content: //com.android.providers.media.documents/document/image: 3951
Comme j'avais besoin de pouvoir enregistrer des images et ne pas perturber le code déjà existant, je viens de copier l'URI de la galerie dans le dossier de données de l'application. Puis a créé un nouvel URI à partir du fichier image enregistré dans le dossier de données.
Voici l'idée:
Remarque - copyAndClose () ne fait que des E / S de fichier pour copier InputStream dans un FileOutputStream. Le code n'est pas affiché.
la source
Je voulais juste dire que cette réponse est brillante et que je l'utilise depuis longtemps sans problème. Mais il y a quelque temps, je suis tombé sur un problème avec lequel DownloadsProvider renvoie les URI au format
content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf
et donc l'application est bloquéeNumberFormatException
car il est impossible d'analyser ses segments d' URI aussi longtemps. Mais leraw:
segment contient un uri direct qui peut être utilisé pour récupérer un fichier référencé. Je l'ai donc corrigé en remplaçant leisDownloadsDocument(uri)
if
contenu par ce qui suit:la source
J'ai combiné plusieurs réponses en une seule solution de travail qui résulte du chemin du fichier
Le type MIME n'est pas pertinent pour l'exemple.
Résultat de la manipulation
FilePickUtils
la source
Question
Comment obtenir un chemin de fichier réel à partir d'un URI
Répondre
À ma connaissance, nous n'avons pas besoin d'obtenir le chemin du fichier à partir d'un URI parce que dans la plupart des cas, nous pouvons directement utiliser l'URI pour faire notre travail (comme 1. obtenir le bitmap 2. Envoyer un fichier au serveur, etc. .)
1. Envoi au serveur
Nous pouvons envoyer directement le fichier au serveur en utilisant uniquement l'URI.
En utilisant l'URI, nous pouvons obtenir InputStream, que nous pouvons envoyer directement au serveur à l'aide de MultiPartEntity.
Exemple
2. Obtenir un BitMap à partir d'un URI
Si l'URI pointe vers l'image, nous obtiendrons un bitmap, sinon null:
commentaires
Référence
la source
Cette bibliothèque Android gère les changements de cas dans KitKat (y compris les versions anciennes - 2.1+):
https://github.com/iPaulPro/aFileChooser
Utilisez le
String path = FileUtils.getPath(context, uri)
pour convertir l'URI retourné en une chaîne de chemin utilisable sur toutes les versions de système d'exploitation. Voir plus à ce sujet ici: https://stackoverflow.com/a/20559175/860488la source
Pour ceux qui utilisent toujours le code de @Paul Burke avec Android SDK version 23 et supérieure, si votre projet a rencontré l'erreur en disant qu'il vous manque EXTERNAL_PERMISSION, et vous êtes très sûr que vous avez déjà ajouté l'autorisation utilisateur dans votre fichier AndroidManifest.xml. C'est parce que vous pouvez dans Android API 23 ou supérieur et Google rendre nécessaire de garantir à nouveau l'autorisation pendant que vous effectuez l'action pour accéder au fichier lors de l'exécution.
Cela signifie: si votre version du SDK est de 23 ou plus, vous êtes invité à autoriser la lecture et l'écriture pendant que vous sélectionnez le fichier image et que vous souhaitez en connaître l'URI.
Et voici mon code, en plus de la solution de Paul Burke. J'ajoute ces codes et mon projet commence à bien fonctionner.
Et dans votre activité et fragment où vous demandez l'URI:
Dans mon cas, CompatUtils.java est l'endroit où je définis la méthode verifyStoragePermissions (comme type statique pour que je puisse l'appeler dans une autre activité).
De plus, il devrait être plus judicieux de créer d'abord un état if pour voir si la version actuelle du SDK est supérieure à 23 ou non avant d'appeler la méthode verifyStoragePermissions.
la source
Cette réponse est de m3n0R à la question android get real path par Uri.getPath () et je ne revendique aucun crédit. Je pensais juste que les gens qui n'avaient pas encore résolu ce problème pouvaient l'utiliser.
la source
cursor.getString(idx);
Veuillez éviter d'utiliser la méthode takePersistableUriPermission car elle a déclenché une exception d'exécution pour moi. / ** * Sélectionnez dans la galerie. * /
OnActivity pour que le résultat gère les données d'image:
@Override protected void onActivityResult (int requestCode, int resultCode, Intent data) {
la source
Si quelqu'un est intéressé, j'ai fait une version Kotlin fonctionnelle pour
ACTION_GET_CONTENT
:la source
J'ai essayé plusieurs des réponses ici, et je pense avoir une solution qui fonctionnera à chaque fois et gère également les autorisations.
Il est basé sur la solution intelligente de LEO. Cet article devrait contenir tout le code dont vous avez besoin pour que cela fonctionne, et il devrait fonctionner sur n'importe quel téléphone et version Android;)
Afin d'avoir la possibilité de choisir un fichier sur une carte SD, vous en aurez besoin dans votre manifeste:
Constantes:
Vérifiez l'autorisation et lancezImagePick si possible
Réponse d'autorisation
Gérer la réponse d'autorisation
Lancer la sélection d'image
Gérer la réponse de sélection d'image
C'est tout le monde; cela fonctionne pour moi sur tous les téléphones que j'ai.
la source
C'est un hack total, mais voici ce que j'ai fait ...
Donc, tout en jouant avec la configuration d'un DocumentsProvider , j'ai remarqué que l' exemple de code (dans
getDocIdForFile
, autour de la ligne 450) génère un identifiant unique pour un document sélectionné en fonction du chemin d'accès (unique) du fichier par rapport à la racine spécifiée que vous lui donnez (c'est-à-dire, ce que vous définissezmBaseDir
à la ligne 96).L'URI finit donc par ressembler à quelque chose comme:
content://com.example.provider/document/root:path/to/the/file
Comme le disent les docs, cela suppose une seule racine (dans mon cas c'est
Environment.getExternalStorageDirectory()
mais vous pouvez utiliser ailleurs ... alors il prend le chemin du fichier, en commençant à la racine, et en fait l'ID unique, en préfixant "root:
". Donc je peut déterminer le chemin en éliminant la"/document/root:
"partie de uri.getPath (), créant un chemin de fichier réel en faisant quelque chose comme ceci:Je connais. C'est honteux, mais ça a marché. Encore une fois, cela dépend de vous en utilisant votre propre fournisseur de documents dans votre application pour générer l'ID du document.
(De plus, il existe une meilleure façon de construire le chemin qui ne suppose pas que "/" est le séparateur de chemin, etc. Mais vous avez l'idée.)
la source
file://
intentions d'un sélecteur de fichiers externe, vous pouvez également vérifier l'autorité, comme dans l'exemple ci-dessus pour vous assurer qu'elle provient de votre fournisseur personnalisé, et si c'est le cas, vous pourriez utilisez également le chemin pour "forger" une nouvellefile://
intention en utilisant le chemin que vous avez extrait, puisStartActivity()
laissez votre application la reprendre. Je sais, terrible.CA marchait bien pour moi:
la source
S'appuyer sur la réponse de Paul Burke j'ai rencontré de nombreux problèmes pour résoudre le chemin URI de la carte SD externe car la plupart des fonctions "intégrées" suggérées renvoient des chemins qui ne sont pas résolus dans les fichiers.
Cependant, c'est mon approche de son // TODO gérer les volumes non primaires .
Notez que cela dépend de la hiérarchie qui peut être différente pour chaque fabricant de téléphones - je ne les ai pas tous testés (cela fonctionnait bien jusqu'à présent sur Xperia Z3 API 23 et Samsung Galaxy A3 API 23).
Veuillez confirmer s'il ne fonctionne pas bien ailleurs.
la source
La réponse de @paul burke fonctionne bien pour les images de la caméra et de la galerie pour le niveau API 19 et supérieur, mais cela ne fonctionne pas si le SDK minimum de votre projet Android est inférieur à 19, et certaines réponses se référant ci-dessus ne fonctionnent pas pour la galerie et caméra. Eh bien, j'ai modifié le code de @paul burke qui fonctionne pour le niveau d'API inférieur à 19. Ci-dessous, le code.
la source
La réponse à votre question est que vous devez avoir des autorisations. Tapez le code suivant dans votre fichier manifest.xml:
Ça a marché pour moi ...
la source