when take photo get - java.lang.Throwable: file:// Uri exposed through ClipData.Item.getUri()

后端 未结 5 1499
灰色年华
灰色年华 2020-12-05 10:49

The Exception is:

file:// Uri exposed through ClipData.Item.getUri()
java.lang.Throwable: file:// Uri exposed through ClipData.Item.getUri()
    at android.         


        
相关标签:
5条回答
  • 2020-12-05 11:01

    So, I was actually reading about this, and it seems the correct solution to handle this is the following:

    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);
            }
        }
    }
    

    Notice there is a note that google says to create a "content://" file instead of a "file://" based resource.

    This is from 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.

    Also, you will need to setup the following: 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>
    

    Note: (Taken from google's site) 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>
    

    If you would like more information: read up here https://developer.android.com/training/camera/photobasics.html

    0 讨论(0)
  • 2020-12-05 11:11

    The reason of this error is that file:// uri scheme no more supported because the security is exposed. https://code.google.com/p/android/issues/detail?id=203555

    And We can not use file:// uri any more after with targetSDK 'N'. https://commonsware.com/blog/2016/03/14/psa-file-scheme-ban-n-developer-preview.html

    So, answer is right. Anyone who use file:// have change content:// to provide kinds of local files.

    0 讨论(0)
  • 2020-12-05 11:12

    To sum up : file:// scheme is now not allowed to be attached with Intent on targetSdkVersion 24 (Android Nougat)

    You have to Change your code if you plan to support api 24+ two links : https://developer.android.com/training/camera/photobasics.html https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/en

    0 讨论(0)
  • 2020-12-05 11:16

    Besides the solution using the FileProvider, there is another way to work around this. Simply put in Application.onCreate() method. In this way the VM ignores the file URI exposure.

    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
     StrictMode.setVmPolicy(builder.build());
    
    0 讨论(0)
  • 2020-12-05 11:22

    I have already resolved this problem.

    First, this problem occurred because StrictMode prevents passing URIs with a file:// scheme.

    So there are two solutions:

    1. Change StrictMode. See similar problem and its code. But for our apps, it is not realistic to modify the Android source code.

    2. Use another URI scheme, instead of file://. For example, content:// related to MediaStore.

    So I chose the second method:

    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);
    }
    

    Also, there is another solution.

    0 讨论(0)
提交回复
热议问题