web-dev-qa-db-fra.com

android.os.FileUriExposedException: fichier.jpg exposé au-delà de l'application via ClipData.Item.getUri ()

J'essaie de créer un bouton qui ouvre l'appareil photo et prend une photo. mon code est ici

//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;

J'ai également un problème avec startActivityForResult dans la méthode onclick Et l'import Java.text.SimpleDateFormat; également dans l'exécution à l'exception Je travaille avec buildtoolsversion sdk 25

28
Omer

Outre la solution utilisant FileProvider, il existe un autre moyen de contourner ce problème. Tout simplement

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

dans la méthode Application.onCreate (). De cette manière, le VM ignore l'exposition du fichier URI.

108
rahul sondarva

Cette information provient de: FileUriExposedException

Ceci n'est émis que pour les applications ciblant N ou plus . Les applications ciblant des versions antérieures du SDK sont autorisées à partager file: // Uri, mais c'est fortement déconseillé.

Ainsi, si la variable compileSdkVersion (cible de génération) de votre fichier app/build.gradle est Android N (niveau 24 de l'API) ou plus, cette erreur est générée si vous écrivez un fichier auquel d'autres applications peuvent éventuellement accéder. Plus important encore, voici comment vous êtes censé le faire pour aller de l'avant:

pris à partir d'ici: FileProvider

Changement:

return Uri.fromFile(mediaFile);

être

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

Remarque: si vous contrôlez mydomain.com, vous pouvez également remplacer getPackageName()+".fileprovider" par "com.mydomain.fileprovider" (il en va de même pour votre AndroidManifest.xml ci-dessous.

De plus, vous devez ajouter ce qui suit dans votre fichier AndroidManifest.xml juste avant votre balise </application>

    <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>

Ensuite, vous devez ajouter un fichier nommé filepaths.xml à votre répertoire app/src/main/res/xml avec le contenu suivant.

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

Remarque: pour quiconque, nous avons utilisé external-files-path ci-dessus, car Omer a utilisé getExternalFilesDir(Environment.DIRECTORY_PICTURES) dans le code. Pour tout autre emplacement, veuillez vérifier FileProvider dans la section "Spécification des fichiers disponibles" et remplacez external-files-path par l'un des éléments suivants en fonction de l'emplacement de vos fichiers:

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

En outre, remplacez Pictures ci-dessus par votre nom de dossier.

Un anti-motif important à éviter est que ET NON utilise if (Build.VERSION.SDK_INT < 24) { pour vous permettre de le faire à l'ancienne, car ce n'est pas leur version Android qui le nécessite, c'est votre build version (j'ai raté ça la première fois que je l'ai codé).

Je sais que cela représente plus de travail, cependant, cela permet à Android d'autoriser uniquement l'accès temporaire au fichier de l'autre application avec laquelle vous partagez l'accès, ce qui est plus sécurisé pour la confidentialité de l'utilisateur.

23
Jared
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();
                    }
                }
0
MEGHA DOBARIYA