1 问题
(1)以下是一段简单的代码,它调用系统的相机app来拍摄照片:
void takePhoto() {
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String cameraPhotoPath = getApplicationContext().getExternalCacheDir().getPath();
File cameraFile = new File(cameraPhotoPath, "test.jpg");
Uri photoUri = Uri.fromFile(cameraFile); // file://Uri
takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takePhotoIntent, REQUEST_TAKE_PHOTO);
}
(2)在Android 7.0之前是没有任何问题,但是如果你尝试在7.0(API>=24)的系统上运行,会抛出文章开头提到的FileUriExposedException异常:
android.os.FileUriExposedException:
file:///storage/emulated/0/DCIM/IMG_20170125_144112.jpg exposed beyond app through ClipData.Item.getUri()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
at android.net.Uri.checkFileUriExposed(Uri.java:2346)
at android.content.ClipData.prepareToLeaveProcess(ClipData.java:832)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8909)
2 原因
Android不再允许在app中把file://Uri暴露给其他app,包括但不局限于通过Intent或ClipData 等方法,原因在于使用file://Uri会有一些风险,比如:
①文件是私有的,接收file://Uri的app无法访问该文件;
②在Android6.0之后引入运行时权限,如果接收file://Uri的app没有申请READ_EXTERNAL_STORAGE权限,在读取文件时会引发崩溃。
因此,google提供了FileProvider,使用它可以生成content://Uri来替代file://Uri。
3 解决方案
(1)首先在AndroidManifest.xml中添加provider
public class XstFileProvider extends FileProvider {
public static final String XST_PROVIDER = ".XstFileProvider";
/**
* 获取文件Uri
*/
public static Uri getUri(File file, Intent intent) {
if (file == null || intent == null) {
return null;
}
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 7.0及以上需要使用fileProvider方式
uri = getUriForFile(BaseApplication.getContext(), getPackageName() + XST_PROVIDER, file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
uri = Uri.fromFile(file);
}
return uri;
}
}
<provider
android:name="com.utils.XstFileProvider"
android:authorities="${applicationId}.XstFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/xst_file_paths" />
</provider>
(2)res/xml/xst_file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="." />
</paths>
(3)修改代码
void takePhoto() {
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String cameraPhotoPath = getApplicationContext().getExternalCacheDir().getPath();
File cameraFile = new File(cameraPhotoPath, "test.jpg");
Uri photoUri = FileProvider.getUri(cameraFile, takePhotoIntent); // content:

本文介绍如何使用FileProvider解决Android7.0以上版本中因file://Uri暴露引起的FileUriExposedException异常,包括FileProvider的配置、使用方法及其优点。
3万+

被折叠的 条评论
为什么被折叠?



