web-dev-qa-db-fra.com

lors de la prise de photo, obtenez - Java.lang.Throwable: file: // Uri exposé via ClipData.Item.getUri ()

L'exception est:

file:// Uri exposed through ClipData.Item.getUri()
Java.lang.Throwable: file:// Uri exposed through ClipData.Item.getUri()
    at Android.os.StrictMode.onFileUriExposed(StrictMode.Java:1618)
    at Android.net.Uri.checkFileUriExposed(Uri.Java:2341)
    at Android.content.ClipData.prepareToLeaveProcess(ClipData.Java:808)
    at Android.content.Intent.prepareToLeaveProcess(Intent.Java:7926)
    at Android.app.Instrumentation.execStartActivity(Instrumentation.Java:1506)
    at Android.app.Activity.startActivityForResult(Activity.Java:3832)
    at Android.app.Activity.startActivityForResult(Activity.Java:3783)
    at Android.support.v4.app.FragmentActivity.startActivityFromFragment(Unknown Source)
    at Android.support.v4.app.Fragment.startActivityForResult(Unknown Source)
    at me.chunyu.ChunyuDoctor.Utility.w.takePhoto(Unknown Source)
    at me.chunyu.ChunyuDoctor.Dialog.ChoosePhotoDialogFragment.takePhoto(Unknown Source)
    at me.chunyu.ChunyuDoctor.Dialog.ChoosePhotoDialogFragment.access$000(Unknown Source)
    at me.chunyu.ChunyuDoctor.Dialog.b.onClick(Unknown Source)
    at me.chunyu.ChunyuDoctor.Dialog.ChoiceDialogFragment.onClick(Unknown Source)
    at Android.view.View.performClick(View.Java:4848)
    at Android.view.View$PerformClick.run(View.Java:20270)
    at Android.os.Handler.handleCallback(Handler.Java:815)
    at Android.os.Handler.dispatchMessage(Handler.Java:104)
    at Android.os.Looper.loop(Looper.Java:194)
    at Android.app.ActivityThread.main(ActivityThread.Java:5643)
    at Java.lang.reflect.Method.invoke(Native Method)
    at Java.lang.reflect.Method.invoke(Method.Java:372)
    at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:960)
    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:755)

Mon code est ici:

public static void takePhoto(Fragment fragment, int token, Uri uri) {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (uri != null) {
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    }
    fragment.startActivityForResult(intent, token);
}

J'ai cherché les problèmes et les solutions similaires. Et modifiez le code comme suit:

public static void takePhoto(Fragment fragment, int token, Uri uri) {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    if (uri != null) {
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
    }
    fragment.startActivityForResult(intent, token);
}

Mais ce n'est pas non plus le travail.

Il est arrivé le Android 5.1 Bien que cela fonctionne bien sur Android 4.3. Y a-t-il quelqu'un qui rencontre le même problème? Demandez une avance. Attendez en ligne ...

24
Michael

J'ai déjà résolu ce problème.

Tout d'abord, ce problème est survenu car StrictMode empêche la transmission d'URI avec un file:// schéma.

Il y a donc deux solutions:

  1. Modifiez StrictMode. Voir problème similaire et son code . Mais pour nos applications, il n'est pas réaliste de modifier le code source Android.

  2. Utilisez un autre schéma d'URI, au lieu de file://. Par exemple, content:// lié à MediaStore.

J'ai donc choisi la deuxième méthode:

private void doTakePhoto() {
    try {
        ContentValues values = new ContentValues(1);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
        mCameraTempUri = getActivity().getContentResolver()
                .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

        takePhoto(this, RequestCode.REQCODE_TAKE_PHOTO, mCameraTempUri);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void takePhoto(Fragment fragment, int token, Uri uri) {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    if (uri != null) {
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
    }
    fragment.startActivityForResult(intent, token);
}

En outre, il existe une autre solution .

15
Michael

Donc, je lisais à ce sujet, et il semble que la bonne solution pour gérer cela est la suivante:

String mCurrentPhotoPath;

private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(
        imageFileName,  /* prefix */
        ".jpg",         /* suffix */
        storageDir      /* directory */
    );

    // Save a file: path for use with ACTION_VIEW intents
    mCurrentPhotoPath = "file:" + image.getAbsolutePath();
    return image;
}

static final int REQUEST_TAKE_PHOTO = 1;

private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // Ensure that there's a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        // Create the File where the photo should go
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            // Error occurred while creating the File
            ...
        }
        // Continue only if the File was successfully created
        if (photoFile != null) {
            Uri photoURI = FileProvider.getUriForFile(this,
                                                  "com.example.Android.fileprovider",
                                                  photoFile);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
        }
    }
}

Notez qu'il y a une note que Google dit de créer un fichier "content: //" au lieu d'une ressource basée sur "file: //".

C'est de google:

Note: We are using getUriForFile(Context, String, File) which returns a content:// URI. For more recent apps targeting Android N and higher, passing a file:// URI across a package boundary causes a FileUriExposedException. Therefore, we now present a more generic way of storing images using a FileProvider.

De plus, vous devrez configurer les éléments suivants: Now, you need to configure the FileProvider. In your app's manifest, add a provider to your application:

<application>
   ...
   <provider
        Android:name="Android.support.v4.content.FileProvider"
        Android:authorities="com.example.Android.fileprovider"
        Android:exported="false"
        Android:grantUriPermissions="true">
        <meta-data
            Android:name="Android.support.FILE_PROVIDER_PATHS"
            Android:resource="@xml/file_paths"></meta-data>
    </provider>
    ...
</application>

Remarque: (Tiré du site de google) Make sure that the authorities string matches the second argument to getUriForFile(Context, String, File). In the meta-data section of the provider definition, you can see that the provider expects eligible paths to be configured in a dedicated resource file, res/xml/file_paths.xml. Here is the content required for this particular example:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />
</paths>

Si vous souhaitez plus d'informations: lisez ici https://developer.Android.com/training/camera/photobasics.html

11
ngoctranfire

Outre la solution utilisant FileProvider, il existe une autre façon de contourner ce problème. Mettez simplement la méthode Application.onCreate (). De cette façon, le VM ignore l'exposition de l'URI du fichier.

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

La raison de cette erreur est que le schéma file: // uri n'est plus pris en charge car la sécurité est exposée. https://code.google.com/p/Android/issues/detail?id=203555

Et nous ne pouvons plus utiliser file: // uri avec targetSDK 'N'. https://commonsware.com/blog/2016/03/14/psa-file-scheme-ban-n-developer-preview.html

Donc, la réponse est juste. Quiconque utilise file: // a change content: // pour fournir des types de fichiers locaux.

4
Seungwon Lee

Pour résumer: le schéma file: // n'est plus autorisé à être attaché avec Intent sur targetSdkVersion 24 (Android Nougat)

Vous devez changer votre code si vous prévoyez de prendre en charge api 24+ deux liens: https://developer.Android.com/training/camera/photobasics.htmlhttps: // inthecheesefactory .com/blog/comment-partager-l'accès-à-fichier-avec-fileprovider-on-Android-nougat/en

3
Tobliug