expuesto más allá de la aplicación a través de ClipData.Item.getUri

99

Estoy tratando de solucionar un problema después de que se agregó la nueva función en el sistema de archivos de Android, pero aparece este error:

android.os.FileUriExposedException: file:///storage/emulated/0/MyApp/Camera_20180105_172234.jpg exposed beyond app through ClipData.Item.getUri()

Así que espero que alguien pueda ayudarme a solucionar este problema :)

Gracias

private Uri getTempUri() {
    // Create an image file name
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
    String dt = sdf.format(new Date());
    imageFile = null;
    imageFile = new File(Environment.getExternalStorageDirectory()
            + "/MyApp/", "Camera_" + dt + ".jpg");
    AppLog.Log(
            TAG,
            "New Camera Image Path:- "
                    + Environment.getExternalStorageDirectory()
                    + "/MyApp/" + "Camera_" + dt + ".jpg");
    File file = new File(Environment.getExternalStorageDirectory() + "/MyApp");
    if (!file.exists()) {
        file.mkdir();
    }
    imagePath = Environment.getExternalStorageDirectory() + "/MyApp/"
            + "Camera_" + dt + ".jpg";
    imageUri = Uri.fromFile(imageFile);
    return imageUri;
}
JonathanNet
fuente

Respuestas:

170

Para sdk 24 y posteriores, si necesita obtener el Uri de un archivo fuera del almacenamiento de su aplicación, tiene este error.
Las soluciones de @ eranda.del le permiten cambiar la política para permitir esto y funciona bien.

Sin embargo, si desea seguir las pautas de Google sin tener que cambiar la política de API de su aplicación, debe usar un FileProvider.

Al principio, para obtener el URI de un archivo, debe usar el método FileProvider.getUriForFile ():

Uri imageUri = FileProvider.getUriForFile(
            MainActivity.this,
            "com.example.homefolder.example.provider", //(use your app signature + ".provider" )
            imageFile);

Entonces necesitas configurar tu proveedor en tu manifiesto de Android:

<application>
  ...
     <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.example.homefolder.example.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <!-- ressource file to create -->
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths">  
        </meta-data>
    </provider>
</application>

(En "autoridades", use el mismo valor que el segundo argumento del método getUriForFile () (firma de la aplicación + ".provider"))

Y finalmente necesitas crear el archivo de recursos: "file_paths". Este archivo debe crearse en el directorio res / xml (probablemente también necesite crear este directorio):

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="." />
</paths>
Brendon
fuente
79
"Facilite la vida a los desarrolladores": este es el lema de cada API nueva, ¿verdad Google?
Kirill Karmazin
12
La solución proporcionada por Brendon es la correcta, pero no está lista para copiar y pegar, por ejemplo, debe verificar si se adapta a sus necesidades. <external-path ...se utiliza cuando se desea Environment.getExternalStorageDirectory (). y utilícelo <files-path ...si necesita Context.getFilesDir (). Es mejor que primero consulte los documentos oficiales: developer.android.com/reference/android/support/v4/content/…
Kirill Karmazin
9
Un recordatorio si está utilizando androidx (nuevo espacio de nombres de soporte), puede encontrar aquí ( developer.android.com/reference/androidx/core/content/… ) la documentación adecuada.
Rodrirokr
20
Tenga en cuenta que en androidxél está:android:name="androidx.core.content.FileProvider"
smörkex
150

Agregue el siguiente bloque de código antes de iniciar la cámara o la exploración de archivos

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

Consulte el modo estricto del enlace de referencia y se explican todos los detalles técnicos y de uso.

eranda.del
fuente
24
No es la forma correcta de resolver esto, esto básicamente eliminará las políticas de modo estricto. e ignorará la advertencia de seguridad
Ahsan Zaheer
Hay algunos pros y contras en esto. Consulte lo siguiente para obtener más información stackoverflow.com/questions/18100161/…
eranda.del
Funciona, si hay algún inconveniente, hágamelo saber :)
Hanan
El código resolvió la excepción para mí. Sin embargo, el comentario superior aquí dice que el código no es la forma correcta de resolver esto. ¿Alguien sabe cuál sería el método adecuado entonces?
Shn_Android_Dev
Google odia a los programadores.
Joubert Vasconcelos
0

No se debe permitir ninguna configuración de proveedor requerida en AndroidManifest only Camera and Storage. Utilice el siguiente código para iniciar la cámara:

final int REQUEST_ACTION_CAMERA = 9;
void openCamra() {
Intent cameraImgIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

cameraImgIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID +".provider",
                new File("your_file_name_with_dir")));
startActivityForResult(cameraImgIntent, REQUEST_ACTION_CAMERA);
}

Después de capturar la imagen, puede encontrar su imagen capturada en:

"your_file_name_with_dir"
Hemraj Patel
fuente
Es mejor explicar la configuración del proveedor en AndroidManifest que dar otro código.
fury.slay