android7.0以后,使用Uri.fromFile会报FileUriExposedException异常,这是因为android7.0以后执行了更加严格的文件管理,要解决这一错误需要使用7.0新添加的FileProvide类,FileProvider官方文档:官方链接
FileProvider使用步骤:
1、定义一个FileProvider
在manifest里面定义一个FileProvider:
<manifest>
...
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
...
</provider>
...
</application>
</manifest>
name直接使用系统的android.support.v4.content.FileProvider,如果需要自己继承FileProvider,则在这里写自己的FileProvider,一定要写全名,即:包名+类名。exported设置为false,即FileProvider不需要共享,grantUriPermissions设置为true,即允许获取临时读取uri的权限。
2、指定可用文件
在res资源文件夹下建立xml文件夹,在xml文件夹下创建一名为file_paths的资源文件:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="my_images" path="images"/>
...
</paths>
paths元素必须包含以下一个或者多个子元素:
- files-path 对应目录Context.getFilesDir()
- cache-path 对应目录Context.getCacheDir()
- external-path 对应目录Environment.getExternalStorageDirectory()
- external-files-path 对应目录Context,getExternalFilesDir(String) 或者Context.getExternalFilesDir(null)
- external-cache-path 对应目录Context.getExternalCacheDir()。
这一点要谨记,在后面创建文件时会用到。
name 是分享的文件路径的一部分,它会覆盖要分享的真实的路径,即path指定的路径。
path 即文件真实路径,最后创建出来的文件路径为(参照上述例子):Context.getFilesDir()+path+”/”+文件名。
然后在第一步的provider中引用这个资源文件:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
3、生成Uri
首先创建文件:
File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "default_image.jpg");
在创建第一个文件即imagePath时,使用Context.getFilesDir()是因为第二步的资源文件里面使用了files-path,如改成external-path,则这里要改成Environment.getExternalStorageDirectory(),其余皆同。“images”对应的是第二步资源文件里面的path资源。最终newFile的文件名为:Context.getFilesDir()+”images/default_image.jpg”。
接下来,生成Uri:
getUriForFile方法中的第二个参数要与第一步中在manifest文件里面创建的provider里面的android:authorities名称一样。
4、分享
使用intent分享文件时,要加入临时权限,已拍照为例:
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
i.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
startActivity(i);