美文网首页
Android7.0以上通过FileProvider访问文件

Android7.0以上通过FileProvider访问文件

作者: 狂奔的_土豆 | 来源:发表于2020-05-20 15:12 被阅读0次
            //选择照片
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        String filename = "img_0001.png";
        File file = new File(Environment.getExternalStorageDirectory(), filename);
    
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
        startActivityForResult(takePictureIntent, 0X000f);
    }
    

    此时如果我们使用Android 7.0或者以上的原生系统,再次运行一下,你会发现应用直接停止运行。

    Caused by: android.os.FileUriExposedException: 
        file:///storage/emulated/0/img_0001.png 
        exposed beyond app through ClipData.Item.getUri()
        at android.os.StrictMode.onFileUriExposed(StrictMode.java:1932)
        at android.net.Uri.checkFileUriExposed(Uri.java:2348)
    

    对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI。如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException 异常。

    FileProvider实际上是ContentProvider的一个子类,它的作用也比较明显了,file:///Uri不给用,那么换个Uri为content://来替代。

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.zhy.android7.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
    

    注意一点,他需要设置一个meta-data,里面指向一个xml文件。

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <root-path name="root" path="" />
        <files-path name="files" path="" />
        <cache-path name="cache" path="" />
        <external-path name="external" path="" />
        <external-files-path name="name" path="path" />
        <external-cache-path name="name" path="path" />
    </paths>
    

    在paths节点内部支持以下几个子节点,分别为:
    1.<root-path/> 代表设备的根目录new File("/");
    2.<files-path/> 代表context.getFilesDir()
    3.<cache-path/> 代表context.getCacheDir()
    4.<external-path/> 代表Environment.getExternalStorageDirectory()
    5.<external-files-path>代表context.getExternalFilesDirs()
    6.<external-cache-path>代表getExternalCacheDirs()

    每个节点都支持两个属性:
    1.name
    2.path
    path即为代表目录下的子目录,比如:

    <external-path
            name="external"
            path="pics" />
    

    代表的目录即为:Environment.getExternalStorageDirectory()/pics,其他同理。

    本例使用的是SDCard所以这么写即可:

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name="external" path="" />
    </paths>
    
    //选择照片
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        String filename = "img_0001.png";
        File file = new File(Environment.getExternalStorageDirectory(), filename);
    
        Uri fileUri = FileProvider.getUriForFile(this, "com.zhy.android7.fileprovider", file);
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
        startActivityForResult(takePictureIntent, 0X000f);
    }
    

    然后再看一眼我们生成的uri:

    content://com.zhy.android7.fileprovider/external/20170601-041411.png
    

    可以看到格式为:content://authorities/定义的name属性/文件的相对路径,即name隐藏了可存储的文件夹路径。

    相关文章

      网友评论

          本文标题:Android7.0以上通过FileProvider访问文件

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