zoukankan      html  css  js  c++  java
  • Android 7.0 通过FileProvider共享文件

    一.概述

    Android 7.0后,提供了很多新特性,其中最主要的是禁止了通过file://URI直接在文件操作共享文件(该操作会触发FileUriExposedException),而是通过content://URI来实现共享。

    FileRrovider是ContentProvider的子类,用于不同应用间的文件共享。

    二 使用

    1.在Mainfest文件中声明provider。

     <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="${applicationId}.fileProvider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths"/>
     </provider>

    2.编写资源文件provider_paths。

    <?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="external-file"
            path=""/>
    
        <external-cache-path
            name="external-cache"
            path=""/>
    </paths>

    在paths节点内部支持以下几个子节点,分别为:

    • <root-path/> 代表设备的根目录new File("/");
    • <files-path/> 代表context.getFilesDir()
    • <cache-path/> 代表context.getCacheDir()
    • <external-path/> 代表Environment.getExternalStorageDirectory()
    • <external-files-path>代表context.getExternalFilesDirs()
    • <external-cache-path>代表getExternalCacheDirs()

    path代表目录下的子目录,如:

    <cache-path
        name = "cache"
        path = "path
    />

    代表context.getChcheDir()/path目录,如果path为空,代表直接使用该根目录。

    既然要使用content://URI替代file://URI,那么我们需要一个虚拟路径对真实文件路径进行映射。通过编写xml文件,其中path路径确定了可访问的文件目录,name属性映射了真实文件路径。

    3.使用fileProvider API 安装APK

    我们一般编写安装APK操作时,是这么写的。

      private void installAPK() {
            File file = new File(Environment.getExternalStorageDirectory(),"test.apk");
    
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
            startActivity(intent);
    
        }

    拿着在7.0上的手机跑一下,果不其然会报android.os.FileUriExposedException。

    简单修改下URI的获取方式。

        private void installAPK() {
            File file = new File(Environment.getExternalStorageDirectory(),"test.apk");
    
            Intent intent = new Intent(Intent.ACTION_VIEW);
            Uri fileUri = null;
            if(Build.VERSION.SDK_INT >= 24){
                //输出 content://com.example.fanggao.fgtextdemo/external/test.apk
                fileUri = FileProvider.getUriForFile(this,BuildConfig.APPLICATION_ID+".fileProvider",file);
            }else {
               fileUri = Uri.fromFile(file);
            }
            intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            startActivity(intent);
    
        }

    这样就可以正常运行了。注意,我们还需要加上权限,否则会报Permission Denial异常。

    那么问题来了,当我们直接使用fileProvider时,在5.0以下的手机也会报Permission Denial异常,是不是也可以使用addFlags()方法添加权限呢?

    答案是不行的,但addFlags只是使用与setData,setDataandType以及setClipData,而且该方法在5.0以下是无效的,需要使用grantUrlPermission()方法,获取所有符合授权的应用,全部授权。

    三 小结

    7.0后使用fileProvider来实现文件共享,主要目的是隐藏真实的文件目录,因为fileProvider是ContentProvider的子类,所以需要在AndroidManifest.xml文件中注册;并且需要编写xml文件描述可使用的文件夹目录,通过name 去映射文件真实目录,实现访问的安全性。

    另外获取授权的方式有2种,

    1.通过addFlags()来获取,仅使用setData,setDataandType以及setClipData方法传递uri时支持。

    2.通过grantUrlPermission()方式,具体参考下文博客。

    更多参考博客:

    https://blog.csdn.net/lmj623565791/article/details/72859156

  • 相关阅读:
    Python读写文件学习笔记
    前端轻量级、简单、易用的富文本编辑器 wangEditor 的基本用法
    选择本地文件上传控件 input标签
    push 和 append 以及appendchild 用法和区别
    关于时间获取和时间戳的换算
    动态设置html根字体大小(随着设备屏幕的大小而变化,从而实现响应式)
    JS 判断是否为安卓或IOS系统
    JS动态获取 Url 参数
    for 循环遍历数据动态渲染html
    VUE框架下安装自带http协议
  • 原文地址:https://www.cnblogs.com/fangg/p/10761568.html
Copyright © 2011-2022 走看看