美文网首页
解决Android N报错: android.os.FileUr

解决Android N报错: android.os.FileUr

作者: 我啊翔1314 | 来源:发表于2019-02-18 14:22 被阅读0次

从谷歌官方文档的描述来看,Android N版本以上,直接将file://形式的Uri暴露给了APP应用,会抛出FileUriExposedException异常。
Android N以下版本,仍然可以使用file://形式的Uri,但强烈不推荐。
不推荐使用file://的原因在于:

  1. 如果文件是私有的,app将无法访问该文件。
  2. 在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);

参考博客:

  1. 使用FileProvider解决Android 7(N)以上FileUriExposedException
  2. Android 7.0 FileProvider 使用说明

相关文章

网友评论

      本文标题:解决Android N报错: android.os.FileUr

      本文链接:https://www.haomeiwen.com/subject/pynoeqtx.html