android.os.FileUriExposedException: file:///storage/emulated/0/test.txt expuesto más allá de la aplicación a través de Intent.getData()

Resuelto Thomas Vos asked hace 54 años • 23 respuestas

La aplicación falla cuando intento abrir un archivo. Funciona bajo Android Nougat, pero en Android Nougat falla. Sólo falla cuando intento abrir un archivo desde la tarjeta SD, no desde la partición del sistema. ¿Algún problema de permisos?

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

Registro:

android.os.FileUriExposedException: file:///storage/emulated/0/test.txt expuesto más allá de la aplicación a través de Intent.getData()

Editar:

Cuando se orienta a Android Nougat, file://ya no se permiten URI. Deberíamos usar content://URI en su lugar. Sin embargo, mi aplicación necesita abrir archivos en directorios raíz. ¿Algunas ideas?

Thomas Vos avatar Jan 01 '70 08:01 Thomas Vos
Aceptado

Si es así targetSdkVersion >= 24, entonces tenemos que usar FileProviderla clase para dar acceso al archivo o carpeta en particular para que otras aplicaciones puedan acceder a ellos. Creamos nuestra propia herencia de clases FileProviderpara asegurarnos de que nuestro FileProvider no entre en conflicto con los FileProviders declarados en dependencias importadas como se describe aquí .

Pasos para reemplazar file://URI con content://URI:

  • Agregue una <provider>etiqueta FileProvider debajo de AndroidManifest.xmlla <application>etiqueta. Especifique una autoridad única para el android:authoritiesatributo para evitar conflictos, podrían especificar dependencias importadas ${applicationId}.providery otras autoridades de uso común.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    <application
        ...
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>
    </application>
</manifest>
  • Luego cree un provider_paths.xmlarchivo en res/xmlla carpeta. Es posible que sea necesario crear una carpeta si aún 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 .
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="external_files" path="."/>
</paths>
  • El último paso es cambiar la línea de código siguiente en

     Uri photoURI = Uri.fromFile(createImageFile());
    

    a

     Uri photoURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", createImageFile());
    
  • Editar: si está utilizando la intención de hacer que el sistema abra su archivo, es posible que deba agregar la siguiente línea de código:

     intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    

Consulte el código completo y la solución que se explican aquí.

Palash kosta avatar Aug 09 '2016 18:08 Palash kosta

Además de la solución que utiliza FileProvider, existe otra forma de solucionar este problema. Simplemente pon

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());

en Application.onCreate(). De esta manera, la VM ignora la URIexposición del archivo.

Método

builder.detectFileUriExposure()

habilita la verificación de exposición de archivos, que también es el comportamiento predeterminado si no configuramos una VmPolicy.

Encontré un problema que si uso content:// URIpara enviar algo, algunas aplicaciones simplemente no pueden entenderlo. Y target SDKno se permite degradar la versión. En este caso mi solución es útil.

Actualizar:

Como se menciona en el comentario, StrictMode es una herramienta de diagnóstico y no debe usarse para este problema. Cuando publiqué esta respuesta hace un año, muchas aplicaciones solo pueden recibir File uris. Simplemente fallan cuando intenté enviarles una uri de FileProvider. Esto ya está solucionado en la mayoría de las aplicaciones, por lo que deberíamos optar por la solución FileProvider.

hqzxzwb avatar Nov 18 '2016 10:11 hqzxzwb

Si targetSdkVersiones superior a 24 , se utiliza FileProvider para otorgar acceso.

Cree un archivo xml (Ruta: res\xml) proveedor_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

Agregar un proveedor en AndroidManifest.xml

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>

Si está utilizando androidx , la ruta de FileProvider debe ser:

 android:name="androidx.core.content.FileProvider"

y reemplazar

Uri uri = Uri.fromFile(fileImagePath);

a

Uri uri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider",fileImagePath);

Editar: mientras incluye el URI con un Intentasegúrese de agregar la siguiente línea:

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

y estás listo para irte.

Pankaj Lilan avatar Aug 18 '2017 07:08 Pankaj Lilan