android.os.FileUriExposedException: archivo.jpg expuesto más allá de la aplicación a través de ClipData.Item.getUri()

6 minutos de lectura

Avatar de usuario de Omer
Ómer

Intento hacer un botón que abra la cámara y tome una foto. mi código está aquí

//for imports check on bottom of this code block

public class HomeProfileActivity extends AppCompatActivity {
//Button camera
public static final String TAG = HomeProfileActivity.class.getSimpleName();
public static final int REQUEST_TAKE_PHOTO = 0;
public static final int REQUEST_TAKE_VIDEO = 1;
public static final int REQUEST_PICK_PHOTO = 2;
public static final int REQUEST_PICK_VIDEO = 3;
public static final int MEDIA_TYPE_IMAGE = 4;
public static final int MEDIA_TYPE_VIDEO = 5;

private Uri mMediaUri;
private ImageView photobutton;
private Button buttonUploadImage, buttonTakeImage;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home_profile);
    ButterKnife.bind(this);
}

@OnClick(R.id.buttonTakeImage)
void takePhoto() {
    mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
    if (mMediaUri == null) {
        Toast.makeText(this,
                "There was a problem accessing your device's external storage.",
                Toast.LENGTH_LONG).show();
    }
    else {
        Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
        startActivityForResult(takePhotoIntent, REQUEST_TAKE_PHOTO);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == RESULT_OK){
        if (requestCode == REQUEST_TAKE_PHOTO) {
            Intent intent = new Intent(this, ViewImageActivity.class);
            intent.setData(mMediaUri);
            startActivity(intent);
        }
    }
    else if (resultCode != RESULT_CANCELED){
        Toast.makeText(this, "Sorry, there was an error", Toast.LENGTH_SHORT).show();
    }
}

private Uri getOutputMediaFileUri(int mediaType) {
    // check for external storage
    if (isExternalStorageAvailable()) {
        // get the URI

        // 1. Get the external storage directory
        File mediaStorageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);

        // 2. Create a unique file name
        String fileName = "";
        String fileType = "";
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

        if (mediaType == MEDIA_TYPE_IMAGE) {
            fileName = "IMG_" + timeStamp;
            fileType = ".jpg";
        } else if (mediaType == MEDIA_TYPE_VIDEO) {
            fileName = "VID_" + timeStamp;
            fileType = ".mp4";
        } else {
            return null;
        }
        // 3. Create the file
        File mediaFile;
        try {
            mediaFile = File.createTempFile(fileName, fileType, mediaStorageDir);
            Log.i(TAG, "File: " + Uri.fromFile(mediaFile));

            // 4. Return the file's URI
            return Uri.fromFile(mediaFile);
        }
        catch (IOException e) {
                Log.e(TAG, "Error creating file: " +
                        mediaStorageDir.getAbsolutePath() + fileName + fileType);
            }
        }

        // something went wrong
        return null;
    }

private boolean isExternalStorageAvailable(){
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)){
        return true;
    }
    else {
        return false;
    }
}

import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import butterknife.ButterKnife;
import butterknife.OnClick;

yo tambien tengo un problema con startActivityForResult en el método onclick y la importación java.text.SimpleDateFormat; también salte en el tiempo de ejecución de excepción. Estoy trabajando con buildtoolsversion sdk 25

  • Uri.fromFile() no funcionará en Android 7.0+, con un targetSdkVersion de 24 o superior. Usar FileProvider en cambio, como demuestro en esta aplicación de muestra. Ver también esta entrada de blog y esta entrada de blog.

    – CommonsWare

    15 de febrero de 2017 a las 14:30


  • Consulte la respuesta en esta pregunta: stackoverflow.com/questions/38200282/…

    – Spark.Bao

    16 de febrero de 2017 a las 3:12

  • Fácil explicación disponible aquí: enlace

    – Conoce a Vora

    2 de marzo de 2017 a las 11:35

avatar de usuario de rahul sondarva
raul sondarva

Además de la solución que utiliza FileProvider, hay otra forma de evitar esto. Simplemente pon

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

en el método Application.onCreate(). De esta forma, la máquina virtual ignora la exposición del URI del archivo.

  • Esto funcionó para mí, gracias, ¿algo que deba saber para un posible problema futuro o estoy bien por un tiempo?

    – Thiago Queiroz

    17 de agosto de 2017 a las 11:48

  • StrictMode está deshabilitado de forma predeterminada y los usuarios deben ingresar al “Modo de desarrollador” en su Android para habilitarlo. Eso hace que la solución de usar StrictMode sea irrelevante.

    – Tamtom

    26 de diciembre de 2017 a las 10:32

  • Gracias, trabajando para mí. Dispositivo de prueba Android: 7.0 targetSdkVersion 26

    – DILSHAD AHMAD

    21 de junio de 2018 a las 18:59

  • ¡Trabajado como un encanto!

    – GeekConGafas

    7 de agosto de 2019 a las 17:48

  • ¿Debería envolver esto solo con SDK versión 24 o superior?

    – Abu Nayem

    18 de mayo de 2020 a las 6:13

Avatar de usuario de Jared
Jared

Esta información es de:
FileUriExposedException

Esto solo se lanza para aplicaciones que apuntan a N o superior. Las aplicaciones destinadas a versiones anteriores del SDK pueden compartir file:// Uri, pero se desaconseja enfáticamente.

Entonces si tu app/build.gradle archivo compileSdkVersion (objetivo de compilación) es Android N (API nivel 24) o superior, este error se produce si escribe un archivo al que posiblemente puedan acceder otras aplicaciones. Lo más importante, así es como se supone que debe hacerlo en el futuro:

tomado de aquí:
proveedor de archivos

Cambiar:

return Uri.fromFile(mediaFile);

ser

return FileProvider.getUriForFile(getApplicationContext(), getPackageName()+".fileprovider", mediaFile);

Nota: si controlas mydomain.com también podrías reemplazar getPackageName()+".fileprovider" con "com.mydomain.fileprovider" (lo mismo ocurre con su AndroidManifest.xml abajo.

También debe agregar lo siguiente a su AndroidManifest.xml archivo justo antes de su </application> etiqueta

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

Entonces necesitas agregar un archivo llamado filepaths.xml para usted app/src/main/res/xml directorio con los siguientes contenidos

<paths>
    <external-files-path name="Pictures" path="Pictures" />
</paths>

Nota: para cualquier otra persona, usamos external-files-path arriba, ya que Omer usó getExternalFilesDir(Environment.DIRECTORY_PICTURES) en el código. Para cualquier otra ubicación, consulte proveedor de archivos en la sección “Especificación de archivos disponibles” y cambie external-files-path a uno de los siguientes según la ubicación de sus archivos:

files-path
cache-path
external-path
external-files-path
external-cache-path

También, revisa Pictures arriba para que sea el nombre de su carpeta.

Un antipatrón importante que debe evitar es que debe NO usar if (Build.VERSION.SDK_INT < 24) { permitirte hacerlo a la antigua, porque no es su versión de Android que requiere esto, es su versión de compilación (Me perdí esto la primera vez que lo codifiqué).

Sé que esto es más trabajo, sin embargo, esto permite que Android permita solo la otra aplicación con la que está compartiendo, acceso temporal al archivo, que es más seguro para la privacidad del usuario.

  • Solo edición rápida: la ruta = “imágenes” distingue entre mayúsculas y minúsculas. Al usar Environment.DIRECTORY_PICTURES en mi extremo, tuve que ponerlo en mayúsculas como path=”Pictures”, de lo contrario no podría encontrar una ruta.

    –David Sanders

    10 de noviembre de 2017 a las 22:59

  • @DaveSanders Gracias por notarlo, actualicé mi respuesta para reflejar el caso de Environment.DIRECTORY_PICTURES, que se evalúa como “Imágenes” (caso del título)

    – Jared

    15 de diciembre de 2017 a las 2:51


  • por favor, no esa versión de androidX de FileProvider tiene paquete androidx.core.content.FileProvider

    – avispón2319

    22 de abril de 2021 a las 11:04

Add the below code where the SharingIntent called:-

if(Build.VERSION.SDK_INT>=24){
                    try{
                        Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
                        m.invoke(null);
                        shareImage(Uri.fromFile(new File(Path)));
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }

¿Ha sido útil esta solución?