La aplicación se bloquea cuando intento abrir un archivo. Funciona debajo de Android Nougat, pero en Android Nougat se bloquea. Solo se bloquea cuando intento abrir un archivo desde la tarjeta SD, no desde la partición del sistema. Algún problema de permiso?
Código de muestra:
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
Iniciar sesión:
android.os.FileUriExposedException: archivo: ///storage/emulated/0/test.txt expuesto más allá de la aplicación a través de Intent.getData ()
Editar:
Al apuntar a Android Nougat, los file://
URI ya no están permitidos. Deberíamos usar content://
URI en su lugar. Sin embargo, mi aplicación necesita abrir archivos en directorios raíz. ¿Algunas ideas?
android
android-file
android-7.0-nougat
Thomas Vos
fuente
fuente
Respuestas:
Si es así
targetSdkVersion >= 24
, entonces tenemos que usar laFileProvider
clase para dar acceso al archivo o carpeta en particular para que sean accesibles para otras aplicaciones. Creamos nuestra propia clase heredandoFileProvider
para asegurarnos de que nuestro FileProvider no entre en conflicto con FileProviders declarado en dependencias importadas como se describe aquí .Pasos para reemplazar
file://
URI concontent://
URI:Agregar una clase que se extienda
FileProvider
Agregue una
<provider>
etiqueta FileProviderAndroidManifest.xml
debajo de la<application>
etiqueta. Especifique una autoridad única para elandroid:authorities
atributo para evitar conflictos, las dependencias importadas pueden especificar${applicationId}.provider
y otras autoridades de uso común.provider_paths.xml
archivo en lares/xml
carpeta. Es posible que se necesite crear una carpeta si no existe. El contenido del archivo se muestra a continuación. Describe que nos gustaría compartir el acceso al almacenamiento externo en la carpeta raíz(path=".")
con el nombre external_files .El paso final es cambiar la línea de código a continuación en
a
Editar: si está utilizando una intención para hacer que el sistema abra su archivo, es posible que deba agregar la siguiente línea de código:
Consulte, el código completo y la solución se han explicado aquí.
fuente
(Build.VERSION.SDK_INT > M)
condición es inútil.FileProvider
debe extenderse solo si desea anular cualquiera de los comportamientos predeterminados; de lo contrario, useandroid:name="android.support.v4.content.FileProvider"
. Ver developer.android.com/reference/android/support/v4/content/…Además de la solución que usa
FileProvider
, hay otra forma de solucionar esto. Simplemente ponen
Application.onCreate()
. De esta manera, la VM ignora laURI
exposición del archivo .Método
habilita la comprobación de exposición de archivos, que también es el comportamiento predeterminado si no configuramos una VmPolicy.
Encontré un problema que si uso un
content://
URI
para enviar algo, algunas aplicaciones simplemente no pueden entenderlo. Ytarget SDK
no se permite degradar la versión. En este caso mi solución es útil.Actualizar:
Como se mencionó en el comentario, StrictMode es una herramienta de diagnóstico y no se debe utilizar para este problema. Cuando publiqué esta respuesta hace un año, muchas aplicaciones solo pueden recibir archivos uris. Simplemente se bloquean cuando intento enviarles un uri de FileProvider. Esto se soluciona en la mayoría de las aplicaciones ahora, por lo que deberíamos ir con la solución FileProvider.
fuente
VmPolicy
.StrictMode.enableDefaults();
, que ejecuto solo en mis compilaciones de desarrollo evita que ocurra este bloqueo, por lo que ahora tengo una aplicación de producción que se bloquea pero no se bloquea cuando está en desarrollo. Básicamente, habilitar una herramienta de diagnóstico aquí oculta un problema grave. Gracias @hqzxzwb por ayudarme a desmitificar esto.Si
targetSdkVersion
es superior a 24 , FileProvider se utiliza para otorgar acceso.Cree un archivo xml (Ruta: res \ xml) provider_paths.xml
Agregar un proveedor en AndroidManifest.xml
Si está utilizando androidx , la ruta de FileProvider debe ser:
y reemplazar
a
Editar: mientras incluye el URI,
Intent
asegúrese de agregar la siguiente línea:y eres bueno para ir Espero eso ayude.
fuente
Si su aplicación está dirigida a API 24+, y aún quiere / necesita usar file: // intentos, puede usar una forma hacky para deshabilitar la verificación de tiempo de ejecución:
El método
StrictMode.disableDeathOnFileUriExposure
está oculto y documentado como:El problema es que mi aplicación no es aburrida, sino que no quiere quedar paralizada al usar content: // intenciones que muchas aplicaciones no entienden. Por ejemplo, abrir un archivo mp3 con content: // esquema ofrece muchas menos aplicaciones que al abrirlo sobre file: // esquema. No quiero pagar las fallas de diseño de Google limitando la funcionalidad de mi aplicación.
Google quiere que los desarrolladores usen el esquema de contenido, pero el sistema no está preparado para esto, durante años las aplicaciones se hicieron para usar Archivos que no son "contenido", los archivos se pueden editar y guardar de nuevo, mientras que los archivos que se sirven sobre el esquema de contenido no se pueden (pueden ¿ellos?).
fuente
ContentResolver
tiene ambosopenInputStream()
yopenOutputStream()
. Una forma menos hacky de hacerlo es configurar las reglas de VM usted mismo y no habilitar lafile
Uri
regla.Si
targetSdkVersion
tiene 24 o más, no puede usarfile:
Uri
valores enIntents
dispositivos Android 7.0+ .Sus elecciones son:
Caída de su
targetSdkVersion
a 23 o menos, oPonga su contenido en almacenamiento interno, luego úselo
FileProvider
para que esté disponible selectivamente para otras aplicacionesPor ejemplo:
(de este proyecto de muestra )
fuente
/system
partición? Todas las aplicaciones deberían poder acceder a esta partición sin root./system
ser legible en todo el mundo. Dicho esto, supongo que todavía obtendrás esta excepción. Sospecho que solo están revisando el esquema y no están tratando de determinar si el archivo es realmente legible en todo el mundo. Sin embargo,FileProvider
no te ayudará, ya que no puedes enseñarle a servir/system
. Podrías crear una estrategia personalizada para miStreamProvider
, o rodar la tuyaContentProvider
, para superar el problema./data
,/system
), debido a este "buen cambio".Primero debe agregar un proveedor a su AndroidManifest
ahora cree un archivo en la carpeta de recursos xml (si usa android studio puede presionar Alt + Enter después de resaltar file_paths y seleccionar crear una opción de recurso xml)
Luego en el archivo file_paths ingrese
Este ejemplo es para una ruta externa que puede consultar aquí para obtener más opciones. Esto le permitirá compartir archivos que están en esa carpeta y su subcarpeta.
Ahora todo lo que queda es crear la intención de la siguiente manera:
EDITAR : agregué la carpeta raíz de la tarjeta SD en file_paths. He probado este código y funciona.
fuente
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
Además, recomiendo a todos los que busquen respuestas que lean primero FileProvider y entiendan a qué se enfrentan aquí con los permisos de archivos en Android N y superiores. Hay opciones de almacenamiento interno frente a almacenamiento externo y también para rutas de archivos normales frente a rutas de caché.java.lang.IllegalArgumentException: Failed to find configured root ...
y lo único que funcionó fue<files-path path="." name="files_root" />
en el archivo xml en lugar de<external-path ...
. Mi archivo se guardó en el almacenamiento interno.La respuesta de @palash k es correcta y funcionó para archivos de almacenamiento interno, pero en mi caso también quiero abrir archivos de almacenamiento externo, mi aplicación se bloqueó cuando abrí un archivo de almacenamiento externo como sdcard y usb, pero logré resolver el problema modificando proveedor_rutass.xml de la respuesta aceptada
cambiar el provider_paths.xml como a continuación
y en la clase java (Sin cambios ya que la respuesta aceptada es solo una pequeña edición)
Esto me ayuda a solucionar el bloqueo de archivos de almacenamientos externos, espero que esto ayude a alguien que tenga el mismo problema que el mío :)
fuente
<root-path
favor? Esta funcionando.<external-path path="Android/data/${applicationId}/" name="files_root" />
no tuvo ningún efecto para los archivos abiertos del almacenamiento externo.Android/data/${applicationId}/
Quise decir en SDcard.Mi solución fue 'Uri.parse' la ruta del archivo como cadena, en lugar de usar Uri.fromFile ().
Parece que fromFile () usa un puntero de archivo A, lo que supongo que podría ser inseguro cuando las direcciones de memoria están expuestas a todas las aplicaciones. Pero una cadena de ruta de archivo nunca hace daño a nadie, por lo que funciona sin lanzar FileUriExposedException.
Probado en los niveles API 9 a 27! Abre con éxito el archivo de texto para editarlo en otra aplicación. No requiere FileProvider, ni la biblioteca de soporte de Android en absoluto.
fuente
Simplemente pegue el siguiente código en la actividad onCreate ()
Ignorará la exposición a URI
fuente
Simplemente pegue el siguiente código en actividad
onCreate()
.Ignorará la exposición a URI.
Feliz codificación :-)
fuente
Usar el fileProvider es el camino a seguir. Pero puede usar esta solución simple:
reemplazar:
por
fuente
Utilicé la respuesta de Palash dada anteriormente, pero estaba algo incompleta, tuve que proporcionar un permiso como este
fuente
Simplemente pegue el siguiente código en la actividad onCreate ()
Ignorará la exposición a URI
fuente
agregue estas dos líneas en onCreate
Método de compartir
fuente
Aquí mi solución:
en Manifiesto.xml
en res / xml / provider_paths.xml
en mi fragmento tengo el siguiente código:
Eso es todo lo que necesitas.
Tampoco es necesario crear
Pruebo en Android 5.0, 6.0 y Android 9.0 y es un trabajo exitoso.
fuente
Para descargar pdf del servidor, agregue el código a continuación en su clase de servicio. Espero que esto te ayude.
Y sí, no olvide agregar permisos y proveedor en su manifiesto.
fuente
@xml/provider_paths
?No sé por qué, hice todo exactamente igual que Pkosta ( https://stackoverflow.com/a/38858040 ) pero seguí recibiendo errores:
java.lang.SecurityException: Permission Denial: opening provider redacted from ProcessRecord{redacted} (redacted) that is not exported from uid redacted
Perdí horas en este tema. ¿El culpable? Kotlin
intent
en realidad estaba configurando engetIntent().addFlags
lugar de operar en mi playIntent recientemente declarado.fuente
Puse este método para que la ruta imageuri ingrese fácilmente al contenido.
fuente
Hay 3 pasos principales aquí como se menciona a continuación
Paso 1: entrada manifiesta
Paso 2: Crear un archivo XML res / xml / provider_paths.xml
Paso 3: cambios de código
fuente
Sé que esta es una pregunta bastante antigua, pero esta respuesta es para futuros espectadores. Entonces encontré un problema similar y después de investigar, encontré una alternativa a este enfoque.
Su intención aquí, por ejemplo: para ver su imagen desde su camino en Kotlin
Función principal a continuación
Del mismo modo, en lugar de una imagen, puede usar cualquier otro formato de archivo como pdf y, en mi caso, funcionó bien
fuente
Pasé casi un día tratando de descubrir por qué recibía esta excepción. Después de mucha lucha, esta configuración funcionó perfectamente ( Kotlin ):
AndroidManifest.xml
file_paths.xml
Intención en sí
Explico todo el proceso aquí .
fuente
https://stackoverflow.com/a/38858040/395097 esta respuesta está completa.
Esta respuesta es para: ya tiene una aplicación que estaba dirigida a menos de 24, y ahora está actualizando a targetSDKVersion> = 24.
En Android N, solo se cambia el archivo uri expuesto a la aplicación de terceros. (No de la forma en que lo estábamos usando antes). Así que cambie solo los lugares donde comparte la ruta con la aplicación de terceros (Cámara en mi caso)
En nuestra aplicación, estábamos enviando uri a la aplicación de la cámara, en esa ubicación esperamos que la aplicación de la cámara almacene la imagen capturada.
Ahora tenemos 2 uri diferentes para el mismo archivo. # 1 se comparte con la aplicación de la cámara. Si la intención de la cámara es exitosa, podemos acceder a la imagen desde el n. ° 2.
Espero que esto ayude.
fuente
Xamarin.Android
Nota: La ruta xml / provider_paths.xml (.axml) no se pudo resolver, incluso después de hacer la carpeta xml en Recursos (tal vez se puede colocar en una ubicación existente como Valores , no lo intenté), así que recurrí a esto que funciona por ahora. Las pruebas mostraron que solo es necesario invocarlo una vez por ejecución de la aplicación (lo cual tiene sentido ya que cambia el estado operativo de la VM del host).
Nota: xml debe estar en mayúscula, por lo que Resources / Xml / provider_paths.xml
fuente
La respuesta de @Pkosta es una forma de hacerlo.
Además de usar
FileProvider
, también puede insertar el archivoMediaStore
(especialmente para archivos de imagen y video), porque los archivos en MediaStore son accesibles para todas las aplicaciones:Por ejemplo, puede insertar un archivo de video en MediaStore como este:
contentUri
es comocontent://media/external/video/media/183473
, que se puede pasar directamente aIntent.putExtra
:Esto funciona para mí y ahorra las molestias de usar
FileProvider
.fuente
Simplemente deje que ignore la exposición a URI ... Agréguelo después de crear
fuente
Prueba esta solución
PONER ESTOS PERMISOS EN MANIFIESTO
Intento de capturar imagen
OBTENGA LA IMAGEN CAPTURADA EN EL RESULTADO DE LA ACTIVIDAD
MÉTODO PARA OBTENER URI DE IMAGEN
fuente
En mi caso, eliminé la excepción reemplazando
SetDataAndType
por justSetData
.fuente