- 解决Android N报错: android.os.FileUr
- 解决 Android N 7.0 上 报错:android.o
- 解决 Android N 7.0 上 报错:android.os
- Android build的时候报错 问题以及答案收集
- 解决:Android N (7.0)上 android.os.F
- flutter doctor --android-license
- [React-Native 0.56.0]Android Cou
- 解决Android 7.0(N)调用相机报错
- 解决 Android 7.x相机拍照报 Android.os.F
- 解决 Android N 7.0 上 报错:android.os
从谷歌官方文档的描述来看,在Android N版本以上,直接将file://形式的Uri暴露给了APP应用,会抛出FileUriExposedException异常。
Android N以下版本,仍然可以使用file://
形式的Uri,但强烈不推荐。
不推荐使用file://
的原因在于:
- 如果文件是私有的,app将无法访问该文件。
- 在Android6.0之后引入运行时权限,如果接收file://Uri的app没有申请READ_EXTERNAL_STORAGE权限,在读取文件时会引发崩溃。
Android N以上版本,将使用content://
代替file://
形式的Uri,系统将赋予APP临时的权限去获取目标Uri的资源。
1.FileProvider
FileProvider是ContentProvider的一个子类。使用FileProvider可以创建content://
形式的Uri,保证APP对文件资源的安全共享。
要使用FileProvider解决Android N以上版本android.os.FileUriExposedException的问题,首先要在AndroidManifest.xml注册该FileProvider:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.myPackage.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
然后在res文件夹里添加创建xml/file_paths.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- 物理路径为Context.getFilesDir() + /files/* -->
<files-path path="files" name="files" />
<!-- 物理路径为Context.getCacheDir() + /files/* -->
<cache-path path="files" name="cache" />
<!-- 物理路径为Environment.getExternalStorageDirectory() + /files/* -->
<external-path path="files" name="external" />
<!-- 物理路径为Context.getExternalFilesDir(String) + /files/* -->
<external-files-path path="files" name="externalfiles"/>
<!-- 物理路径为Context.getExternalCacheDir() + /files/* -->
<external-cache-path path="files" name="externalcache"/>
<!-- 物理路径为`Context.getExternalMediaDirs() + /files/*, 要求API21+ -->
<external-media-path name="externalmedia" path="files" />
</paths>
创建content://
Uri,通过FileProvider.getUriForFile(Context context, String authorities, File file)实现。为了实现兼容,可通过根据设备系统使用不同的方法获取Uri:
public class FileUtils {
public static Uri getUri(Context context, String authorites, File file) {
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//设置7.0以上共享文件,分享路径定义在xml/file_paths.xml
uri = FileProvider.getUriForFile(context, authorites, file);
} else {
// 7.0以下,共享文件
uri = Uri.fromFile(file);
}
return uri;
}
}
这样就同时兼容file://
和content://
的Uri形式,下面的例子是调用系统相机拍照时,通过FileUtils获取照片保存路径的Uri:
File file = new File(Environment.getExternalStorageDirectory() + "/files/", System.currentTimeMillis() + ".jpg".)
cameraFile.getParentFile().mkdirs();
// 获取照片保存路径Uri
Uri uri = FileUtils.getUri(getContext(), "com.myPackage.fileProvider", )
// 调用系统相机
startActivityForResult(
new Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, uri),
REQUEST_CODE_CAMERA);
参考博客:
网友评论