为什么用FileProvider

7.0和更高的版本使用FilrProvider,这是都知道的事情,但是为什么要使用FilrProvider,因为Android 7.0不允许intent带有file://的URI离开自身的应用了,要不然会抛出FileUriExposedException

想要在自己应用和其他应用之间共享File数据,只能使用content://的方式

(1)建议使用自己的FileProvider

建立自己的FileProvider,因为一个程序中在使用FileProvider时候,可能你调用的第三方的里面也用到了
FileProvider,那么在使用的时候就会存在冲突,建议你在使用时候直接自定义一个:

public class MyFileProvider extends FileProvider {
}

(2)必须在清单文件中配置

在清单文件中注册:

<provider
            android:name=".bases.MyFileProvider"
            android:authorities="包名.provider"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:replace="android:authorities"
            >
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/files_names"
                tools:replace="android:resource"
                />
        </provider>
        /***android:name 它的值是固定的,是你的FileProvider,也可以用系统的自带的
        android:authorities:属性的值必须要和代码中使用的时候一样。
        <meat - data >标签用来指定Uri的共享路径。并且引用了一个@xml/file_paths资源
      
*/

###(3)
建立资源文件,对应于清单文件中配置的android:resource:属性
在res - New - Directory - xml目录 - New - File

<paths xmlns:android="http://schemas.android.com/apk/res/android">

    <!--填写你要所要申请访问的目录地址,name最好是你的目录名,path是你要申请的目录-->
    <external-path name="camera_photos" path="."  />
    <external-path name="cache" path="Android/data/com.xuezj.fileproviderdemo/cache" />
    <external-path name="images" path="Pictures/" />
    <external-path name="dcim" path="DCIM/" />
    //可以配置多个
</paths>

扩展 paths标签 如何去完成

上述只是演示了外部存储的一种,其实Google还提供以下几种方法

(1)
<files-path name="name" path="path" />  对应于getFilesDir()所表示的文件路径
(2)
<cache-path name="name" path="path" /> 对应于getCacheDir()所表示的文件路径
(3)
<external-path name="name" path="path" /> 对应于Environment.getExternalStorageDirectory(没有参数)所表示的文件路径,
(4)
<external-files-path name="name" path="path" />
 对应于getExternalFilesDir(String) 或者getExternalFilesDir(null) 所表示的文件路径
 (5)
 <external-cache-path name="name" path="path" /> 对应于getExternalCacheDir()表示的文件路径
 (6)
 <external-media-path name="name" path="path" /> 对应于Context.getExternalMediaDirs()所表示的文件路径

你可以选择你想要的存储位置,进行选择,对于这些存储位置不懂得,可以参考文件存储体系

上面有关键两个属性,都有name 与 path,下面展示两个例子

实例一:

路径配置:

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

使用:

File file = new File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),test.jpeg),;
 Uri contentUri = FileProvider.getUriForFile(Main2Activity.this,"与清单文件中配置的android:authorities一样",file);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive"); //可以使用Uri了
前面提到的path = Pictures ,所以这里使用的参数是Environment.DIRECTORY_PICTURES
前面如果是DCIM,这里相应的也要变成这个Environment.DIRECTORY_DCIM

实例二:

路径配置

<files-path name= "suiyidemingzi" path="apk_path" />

使用

private File apkpath = null;
    private File contentFile = null;
    apkpath = new File(getFilesDir(),"apk_path"); //先建立与路径配置中你自定义的path一致的子目录 
    ,实例一通过传参的方式得到的(因为上述路径是系统肯定自带的)
    contentFile = new File(apkpath,"test.jepg"); //这里文件名无所谓了,随便配置了
    Uri contentUri = FileProvider.getUriForFile(Main2Activity.this, "和清单文件中配置的android:authorities一样",contentFile );
    这时候就得到7.0以上版本使用的Uri了

发现name可以随便取,但是不能重复了,而path则要慎重用,和文件存储中的内部存储,外部存储一一相关,作用是为了抽象Uri中路径,不让外部应用直接得到使用.

android 分享文件时提示获取资源失败 分享失败安卓11需使用fileprovider_uri

上面的话如果难懂,下面是我自己的理解:

在xml中定义的标签:
external-path  就等于 代码中调用 Environment.getExternalStoragePublicDirectory这个方法得到的路径,path就是子路径
path表示的就是具体的哪个路径如Pictures文件夹
两者的作用一个样,但是要对应起来,这样系统在对外使用uri的时候才不为空。
files-path 就等于 getFilesDir()得到的路径。
如果上面的话很难理解,不妨可以这样想:
files-path + path 拼接成的路径 必须保证和你代码中构建的file路径一致。

(4)

使用:在7.0之前的版本还是使用Uri.fromFile();方法的得到Uri

Uri uriP;
uriP = FileProvider.getUriForFile(MineStudentFragment.this.getContext()
                                , "包名.建议是自定义的provider"
                                , file);
                                /**这里的参数二和清单文件注册时候的android:authorities一致*/

(5)

权限,还是需要的。如果是想像外部存储空间中存储

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

错误:java.lang.IllegalArgumentException: Failed to find configured root that contains xxx文件路径

再后来的使用中有些手机会返回这个异常,经过查找资料,发现需要额外配置如下:

<root-path
        name = "root_path"
        path="."
        />

这样就可以解决部分机型因为使用外置sd卡或者应用分身导致的问题。
华为 p9与华为 nove 2s在使用微信应用分身时候,会导致这个问题。
所以没事就配置上就可以!!!!