Antes de KitKat (o antes de la nueva Galería) el Intent.ACTION_GET_CONTENT
devolvió un URI como este
contenido: // media / external / images / media / 3951.
Utilizando la ContentResolver
y quering
MediaStore.Images.Media.DATA
devolvió la URL del archivo.
Sin embargo, en KitKat, la Galería devuelve un URI (a través de "Último") como este:
contenido: //com.android.providers.media.documents/document/image: 3951
¿Cómo manejo esto?
android
android-intent
android-gallery
android-contentresolver
Michael Greifeneder
fuente
fuente
Uri
debería poder abrirse como una transmisión víaContentResolver
. Durante mucho tiempo he estado nervioso por las aplicaciones que suponen que uncontent://
Uri
que representa un archivo siempre se puede convertir en unFile
.InputStream
enContentResolver
un lugar previamente designado para que tenga un nombre de archivo conocido. Sin embargo, esto me suena un desperdicio. ¿Cualquier otra sugerencia?InputStream
JNI? Desafortunadamente, no hay tantas opciones para ti.InputStream
archivo en lugar de un archivo (lo cual es genial). Solo la lectura de etiquetas EXIF es un poco complicada y requiere la biblioteca de Drew Noakes . Muchas gracias por tus comentarios.Respuestas:
Prueba esto:
Probablemente necesito
para
fuente
Esto no requiere permisos especiales y funciona con Storage Access Framework, así como con los no oficiales
ContentProvider
patrón (ruta del archivo en el_data
campo).Vea una versión actualizada de este método aquí .
fuente
Authority: com.google.android.apps.docs.storage
ySegments: [document, acc=1;doc=667]
. No estoy seguro, pero suponga que eldoc
valor es elUri
ID con el que puede consultar. Probablemente necesitará permisos para configurarlo como se detalla en "Autorice su aplicación en Android" aquí: developers.google.com/drive/integrate-android-ui . Actualice aquí si lo resuelve._data
no iba a funcionar cuando ContentProvider no lo soporta. Se recomienda seguir las instrucciones de @CommonsWare y no usar la ruta completa del archivo, ya que podría ser un archivo en la nube de Dropbox en lugar de un archivo real.Tuve el mismo problema, probé la solución anterior, pero aunque funcionó en general, por alguna razón estaba recibiendo la denegación de permiso en el proveedor de contenido de Uri para algunas imágenes, aunque tenía el
android.permission.MANAGE_DOCUMENTS
permiso agregado correctamente.De todos modos encontró otra solución que es forzar la apertura de la galería de imágenes en lugar de la vista de documentos KITKAT con:
y luego cargue la imagen:
EDITAR
ACTION_OPEN_DOCUMENT
podría requerir que usted mantenga marcas de permisos, etc. y, en general, a menudo genera Excepciones de seguridad ...Otra solución es utilizar el
ACTION_GET_CONTENT
combinado con elc.getContentResolver().openInputStream(selectedImageURI)
que funcionará tanto en pre-KK como en KK. Kitkat usará una nueva vista de documentos y esta solución funcionará con todas las aplicaciones como Fotos, Galería, Explorador de archivos, Dropbox, Google Drive, etc.) pero recuerde que cuando use esta solución, debe crear una imagen en suonActivityResult()
y almacenarla en Tarjeta SD por ejemplo. La recreación de esta imagen desde la uri guardada en el próximo lanzamiento de la aplicación arrojaría una excepción de seguridad en la resolución de contenido incluso cuando agrega marcas de permiso como se describe en los documentos de la API de Google (eso es lo que sucedió cuando hice algunas pruebas)Además, las pautas de la API para desarrolladores de Android sugieren:
fuente
Intent.ACTION_GET_CONTENT
. De todos modos, mantuve elIntent.createChooser()
contenedor en el nuevoIntent
, para permitir al usuario elegir la aplicación para navegar, y funcionó como se esperaba. ¿Alguien puede ver los inconvenientes de esta solución?Tal como mencionó Commonsware, no debe suponer que la transmisión que obtiene
ContentResolver
es convertible en un archivo.Lo que realmente debe hacer es abrir
InputStream
desdeContentProvider
, luego crear un mapa de bits a partir de él. Y también funciona en 4.4 y versiones anteriores, sin necesidad de reflexión.Por supuesto, si maneja imágenes grandes, debe cargarlas con la información adecuada
inSampleSize
: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html . Pero ese es otro tema.fuente
Creo que las respuestas ya publicadas deberían hacer que las personas avancen en la dirección correcta. Sin embargo, esto es lo que hice que tenía sentido para el código heredado que estaba actualizando. El código heredado estaba usando el URI de la galería para cambiar y luego guardar las imágenes.
Antes de 4.4 (y Google Drive), los URI se verían así: content: // media / external / images / media / 41
Como se indicó en la pregunta, con mayor frecuencia se ven así: content: //com.android.providers.media.documents/document/image: 3951
Como necesitaba la capacidad de guardar imágenes y no alterar el código ya existente, simplemente copié el URI de la galería en la carpeta de datos de la aplicación. Luego originó un nuevo URI del archivo de imagen guardado en la carpeta de datos.
Aquí está la idea:
Nota: copyAndClose () solo hace E / S de archivo para copiar InputStream en un FileOutputStream. El código no está publicado.
fuente
Solo quería decir que esta respuesta es brillante y la estoy usando durante mucho tiempo sin problemas. Pero hace algún tiempo me topé con un problema de que DownloadsProvider devuelve los URI en formato
content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf
y, por lo tanto, la aplicación se bloqueaNumberFormatException
ya que es imposible analizar sus segmentos uri por tanto tiempo. Pero elraw:
segmento contiene uri directa que se puede usar para recuperar un archivo referenciado. Así que lo arreglé reemplazando elisDownloadsDocument(uri)
if
contenido con lo siguiente:fuente
Combiné múltiples respuestas en una solución de trabajo que resulta con la ruta del archivo
El tipo Mime es irrelevante para el propósito del ejemplo.
Resultado de manejo
FilePickUtils
fuente
Pregunta
Cómo obtener una ruta de archivo real desde un URI
Responder
Que yo sepa, no necesitamos obtener la ruta del archivo desde un URI porque para la mayoría de los casos podemos usar directamente el URI para hacer nuestro trabajo (como 1. obtener un mapa de bits 2. Enviar un archivo al servidor, etc. .)
1. Envío al servidor
Podemos enviar directamente el archivo al servidor utilizando solo el URI.
Usando el URI podemos obtener InputStream, que podemos enviar directamente al servidor usando MultiPartEntity.
Ejemplo
2. Obtener un BitMap de un URI
Si el URI apunta a la imagen, obtendremos un mapa de bits, de lo contrario, será nulo:
Comentarios
Referencia
fuente
Esta biblioteca de Android maneja los cambios de mayúsculas y minúsculas en KitKat (incluidas las versiones anteriores - 2.1+):
https://github.com/iPaulPro/aFileChooser
Use el
String path = FileUtils.getPath(context, uri)
para convertir el Uri devuelto a una cadena de ruta utilizable en todas las versiones del sistema operativo. Vea más sobre esto aquí: https://stackoverflow.com/a/20559175/860488fuente
Para aquellos que todavía usan el código de @Paul Burke con Android SDK versión 23 y superior, si su proyecto encontró el error que indica que falta EXTERNAL_PERMISSION, y está muy seguro de que ya ha agregado el permiso de usuario en su archivo AndroidManifest.xml. Esto se debe a que es posible que en Android API 23 o superior y Google haga necesario garantizar el permiso nuevamente mientras realiza la acción para acceder al archivo en tiempo de ejecución.
Eso significa: si su versión de SDK es 23 o superior, se le solicitará permiso de LECTURA Y ESCRITURA mientras selecciona el archivo de imagen y desea conocer su URI.
Y el siguiente es mi código, además de la solución de Paul Burke. Agrego estos códigos y mi proyecto comienza a funcionar bien.
Y en su actividad y fragmento donde solicita el URI:
En mi caso, CompatUtils.java es donde defino el método generateStoragePermissions (como tipo estático para poder llamarlo dentro de otra actividad).
También debería tener más sentido si primero hace un estado if para ver si la versión actual del SDK es superior a 23 o no antes de llamar al método allowStoragePermissions.
fuente
Esta respuesta es de m3n0R en la pregunta de Android para obtener un camino real por Uri.getPath () y no reclamo ningún crédito. Solo pensé que las personas que aún no han resuelto este problema podrían usarlo.
fuente
cursor.getString(idx);
Intente evitar usar el método takePersistableUriPermission porque generó una excepción de tiempo de ejecución para mí. / ** * Seleccionar de la galería. * /
OnActivity para obtener resultados para manejar los datos de la imagen:
@Override protected void onActivityResult (int requestCode, int resultCode, Intent data) {
fuente
Si alguien está interesado, hice una versión funcional de Kotlin para
ACTION_GET_CONTENT
:fuente
He intentado varias de las respuestas aquí, y creo que tengo una solución que funcionará siempre y que también gestiona los permisos.
Se basa en la solución inteligente de LEO. Esta publicación debe contener todo el código que necesita para que esto funcione, y debe funcionar en cualquier teléfono y versión de Android;)
Para poder elegir un archivo de una tarjeta SD, necesitará esto en su manifiesto:
Constantes:
Verifique el permiso y ejecute ImagePick si es posible
Respuesta de permiso
Administrar respuesta de permiso
Lanzar selección de imagen
Administrar respuesta de selección de imagen
Eso es todo amigos; Esto funciona para mí en todos los teléfonos que tengo.
fuente
Este es un truco total, pero esto es lo que hice ...
Entonces, mientras jugaba con la configuración de un DocumentsProvider , noté que el código de muestra (en
getDocIdForFile
, alrededor de la línea 450) genera una identificación única para un documento seleccionado en función de la ruta (única) del archivo en relación con la raíz especificada que le das (es decir, lo que configurómBaseDir
en la línea 96).Entonces, el URI termina pareciéndose a:
content://com.example.provider/document/root:path/to/the/file
Como dicen los documentos, está asumiendo solo una raíz (en mi caso, eso es,
Environment.getExternalStorageDirectory()
pero puede usar en otro lugar ... luego toma la ruta del archivo, comenzando en la raíz, y lo convierte en la ID única, precediendo "root:
". Entonces puede determinar la ruta eliminando la"/document/root:
"parte de uri.getPath (), creando una ruta de archivo real haciendo algo como esto:Lo sé. Es vergonzoso, pero funcionó. Nuevamente, esto depende de que usted use su propio proveedor de documentos en su aplicación para generar la identificación del documento.
(Además, hay una mejor manera de construir la ruta que no asume que "/" es el separador de ruta, etc. Pero se entiende la idea).
fuente
file://
intenciones desde un selector de archivos externo, también puede verificar la autoridad, como en el ejemplo anterior, para asegurarse de que sea de su proveedor personalizado, y si es así, podría también use la ruta para "forjar" una nuevafile://
intención usando la ruta que extrajo, luego,StartActivity()
y deje que su aplicación la tome. Lo sé terrible.Esto funcionó bien para mi:
fuente
A partir de la respuesta de Paul Burke, enfrenté muchos problemas para resolver la ruta URI de la tarjeta SD externa ya que la mayoría de las funciones "incorporadas" sugeridas devuelven rutas que no se resuelven en los archivos.
Sin embargo, este es mi enfoque de su // TODO manejar volúmenes no primarios .
Tenga en cuenta que depende de la jerarquía, que puede ser diferente en cada fabricante de teléfonos: no los he probado todos (hasta ahora funcionó bien en Xperia Z3 API 23 y Samsung Galaxy A3 API 23).
Confirme si no funciona bien en otro lugar.
fuente
La respuesta de @paul burke funciona bien tanto para la cámara como para las imágenes de la galería para el nivel API 19 y superior, pero no funciona si el SDK mínimo de su proyecto de Android está configurado por debajo de 19, y algunas respuestas que se refieren arriba no funcionan para la galería y cámara. Bueno, he modificado el código de @paul burke que funciona para el nivel API por debajo de 19. A continuación se muestra el código.
fuente
La respuesta a su pregunta es que necesita tener permisos. Escriba el siguiente código en su archivo manifest.xml:
A mí me funcionó ...
fuente