美文网首页适配
Android 7.0后访问文件权限:android.os.Fi

Android 7.0后访问文件权限:android.os.Fi

作者: 皓皓amous | 来源:发表于2019-08-05 13:39 被阅读28次

    最近项目中有一个很简单的需求:就是用系统自带图库打开在APP中下载的图片,结果就遇到了

    android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/xxx.jpg exposed beyond app through Intent.getData()

    的异常。

    原来从Android 7.0开始,谷歌收回了访问文件的权限,即一个应用提供自身资源文件给其它应用使用时,如果给出 file://xxx 这样格式的URI的话,谷歌会认为目标应用不具备访问此文件的权限,便会抛出 FileUriExposedException 的异常。我这里的解决方法是使用 FileProvider,来生成一个content://xxx 格式的URI,并授予此 URI 临时访问权限,ok,异常解决了。下面我们来一起看看实现方式吧:

    1.在 Manifest中声明FileProvider

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

    name为 FileProvider的完整类名:android.support.v4.content.FileProvider ,是固定的;

    authorities为自定义的权限名称,大家可以自定义,通常都会带上包名来避免与其他应用冲突;

    exported为 false,代表只有同一个应用程序的组件或带有相同用户ID的应用程序才能使用,在 FileProvider的使用中一定要填false,否则会报错;

    grantUriPermissions为true,代表允许通过接受传递的权限方式进行访问,拥有共享文件的临时权限。即如果应用A具有读取 ContentProvider 的权限,它去调用另一个应用B的activity,但是B没有读取此 ContentProvider 的权限,那么应用A可以将自己的权限通过intent传递给应用B,让其也具有访问此ContentProvider 的权限。(因此后面代码中会对Intent 进行设置: intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

    2.在res下的xml文件夹中新建一个provider_paths.xml文件(名字可自定义,和上一步中resource的value一致即可)

    <resources>   
     <paths>        <external-path            name="gallery_photos"            path=""/>   
     </paths>
    </resources>
    

    内部的element可以是 files-path,cache-path,external-path等,代表的根目录分别对应为:Context.getFilesDir(),Context.getCacheDir(),Environment.getExternalStorageDirectory()等。

    name是一个标识,作为根目录的名称,可以自定义;

    path代表根目录下要共享的目标。

    这里大家也许看的会有些困惑,我举个简单的例子:

    大家都知道 ContentProvider 使用 URI 标识要操作的数据,这里的内容 URI 主要包括两部分:authority:整个提供程序的符号名称;path:指向表的名称/路径,所以内容 URI 统一的形式就是:content://authority/path

    那么当我们以上面为例,通过 FileProvider 获取到的某资源文件(比如根目录下的xxx.jpg)的uri链接即为:content://com.xxx.fileprovider/gallery_photos/xxx.jpg

    3.在代码中调用(我这里就以实现用系统自带图库打开下载的一张图片为例了)

    Intent intent = new Intent(Intent.ACTION_VIEW);                    
    Uri photoURI = FileProvider.getUriForFile(getApplicationContext(),   "com.xxx.fileprovider",   file);//file即为所要共享的file                    
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//授予临时权限别忘了                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                  
    intent.setDataAndType(photoURI, "image/*");                   
    startActivity(intent);
    

    ok,至此 FileProvider 的基本使用就完成了。

    相关文章

      网友评论

        本文标题:Android 7.0后访问文件权限:android.os.Fi

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