天天看點

Android7.0異常:FileUriExposedException

參考:​​http://www.jianshu.com/p/a1eb3ad79ef6?mType=Group​​​

又遇到android相容問題,差點哭暈在廁所。。。

錯誤描述:7.0拍照調用:intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));報異常FileUriExposedException,看了一下各種解釋,好頭暈。。。

尤其是那個路徑,真的不知道怎麼配置,後面調試放在源碼裡才知道配置方式。

記錄一下:

方法1

<application ...>
<provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="Authorities名,一般包含包名,例如com.A.B"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths"/>
    </provider>

    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>

</application>      

然後再res檔案夾建立檔案夾xml,裡面放置一個xml,命名為file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!--注意後面的名字images,等一下有個配置必須和這個一緻,否則報錯-->
    <files-path name="my_images" path="images"/>
</paths>      

拍照方法:

private void takePhoto() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getPackageManager())!=null){
            //這裡必須和前面的images一緻,這兩個是相同的
            //源碼邏輯會将這裡的路徑和前面xml配置的路徑嘗試比對
            //即tempFile的路徑必須以前面配置的路徑中至少一個比對
            File imagePath = new File(getFilesDir(),"images");
            tempFile = new File(imagePath, System.currentTimeMillis() + ".jpg");
                FileUtils.createFile(tempFile);

            if (tempFile!=null){
                Uri photoURI = FileProvider.getUriForFile(this,"Authorities名,一般包含包名,例如com.A.B,和前面provider中配置相同",tempFile);

                List<ResolveInfo> resInfoList= getPackageManager().queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);
                for (ResolveInfo resolveInfo : resInfoList) {
                    String packageName = resolveInfo.activityInfo.packageName;
                    grantUriPermission(packageName, photoURI,
                            Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                }

                if(AppUtil.getApiVersion()>=24){
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI);
                }else{
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));
                }
             takePictureIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                this.startActivityForResult(takePictureIntent, TAKE_PICTURE);      

這裡有兩個地方要求一緻性

(1)manifest的provider中android:authorities=”此處”

和 Uri photoURI = FileProvider.getUriForFile(this,”此處”,tempFile);

“此處”的替換字元串必須相同

(2)file_paths.xml中配置的路徑和File imagePath = new File(getFilesDir(),”images”);中imagePath的路徑必須相同,這裡有個轉換問題,直接參看上面的參考url了:

<files-path name="name" path="path" />
Context.getFilesDir()
<cache-path name="name" path="path" />
Context.getCacheDir()
<external-path name="name" path="path" />
Environment.getExternalStorageDirectory()
<external-files-path name="name" path="path" />
Context#getExternalFilesDir(String) Context.getExternalFilesDir(null).
<external-cache-path name="name" path="path" />
Context.getExternalCacheDir()      

這裡是說,file-path.xml中配置的路徑例如第一條

<file-path name="my_img" path="path"/>      

意思就是

File file = new File(getFilesDir(),path);
String path = file.getAbsolutePath();      

總之是getXXDir()+path,如果需要加分割“/”則添加

這樣一個路徑。

方法2

.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(builder.build());      

方法3