46 votes

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

J'essaie de faire 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'importation java.text.SimpleDateFormat; saute également dans le runtime d'exception que je travaille avec buildtoolsversion sdk 25

165voto

rahul sondarva Points 1081

Outre la solution utilisant FileProvider, il existe une autre façon 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 façon, la machine virtuelle ignore l'exposition à l'URI du fichier.

48voto

Jared Points 435

Cette info est à partir de: FileUriExposedException

Ce n'est jeté pour des applications ciblant les N ou plus. Les Applications ciblant les précédentes versions du SDK sont autorisées à partager file:// Uri, mais c'est fortement déconseillé.

Donc, si votre app/build.gradle fichier compileSdkVersion (cible de construction) est Android N API (niveau 24) ou plus, cette erreur est levée si vous écrivez un fichier qui peut être consulté par d'autres applications. Le plus important, ici, est de savoir comment vous êtes censé le faire aller de l'avant:

prises à partir d'ici: FileProvider

Changement:

return Uri.fromFile(mediaFile);

pour être

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

Remarque: si vous contrôlez mydomain.com vous pouvez aussi remplacer getPackageName()+".fileprovider" avec "com.mydomain.fileprovider" (la même chose vaut pour votre AndroidManifest.xml ci-dessous.

Aussi, vous devez ajouter les lignes suivantes à votre AndroidManifest.xml fichier juste avant votre </application> balise

    <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 app/src/main/res/xml répertoire avec le contenu suivant

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

Remarque: pour quelqu'un d'autre, nous avons utilisé external-files-path - dessus, depuis Omer utilisé getExternalFilesDir(Environment.DIRECTORY_PICTURES) dans le code. Pour tout autre pays, veuillez vérifier FileProvider en vertu de la "Spécification des Fichiers Disponibles" et de changement external-files-path à l'une des options suivantes en fonction de l'endroit où vos fichiers sont situés:

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

Aussi, réviser Pictures ci-dessus pour être le nom de votre dossier.

Un important anti-modèle à éviter, c'est que vous devriez ne PAS utiliser if (Build.VERSION.SDK_INT < 24) { pour vous permettre de le faire à l'ancienne, parce que ce n'est pas la version d'Android que cela nécessite, c'est votre version de build (j'ai raté ce la première fois que j'ai codé il).

Je sais que c'est plus de travail, cependant, cela permet Android pour autoriser uniquement l'autre application que vous partagez, temporaire de l'accès au fichier, ce qui est plus sûr pour l'intimité de l'utilisateur.

-3voto

MEGHA DOBARIYA Points 1
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();
                    }
                }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X