Android || FileProvider 控件的使用

本文详细介绍了Android中的FileProvider组件,它是ContentProvider的子类,用于安全地在应用间共享文件。文章阐述了FileProvider的工作原理,包括如何注册FileProvider、添加共享目录、生成ContentURI以及如何授予和提供访问权限。此外,还讲解了两种授权访问ContentURI的方法,确保了文件共享过程的安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 FileProvider 概述

FileProvider 是ContentProvider 的子类。 ContentProvider 用于应用间的数据共享,FileProvider 用于不用应用间的文件共享。

FileProvider 的共享流程

  • 与ContentProvider 相似:
    当一个 请求文件的 client app 想要向共享了文件的 Server app 发送请求来获取文件,大多数情况,该请求第一个会开启一个分享的文件列表的 Activity(该 Activity隶属于Server app,目的是为了让用户选择先要获取的文件,因为他可能分享了不止一个文件)。
    用户选择文件之后,Server app返回文件的 Uri 和权限给 client app。client app根据 Uri 去找文件,有了权限也就能对该文件进行读写操作了。

为什么选择使用 Uri

  • 如果直接将文件传输为 client app:当该文件非常大时,十分消耗资源。
    如果将文件的地址传给 client app:这样相当于把自身的app的文件共享地址暴露出来。这是非常危险的,我们无法估计其他app拿到这个地址之后的操作。如果这个地址下也有其他的共享文件,就不能保证他们的安全。

  • 因此,app共享文件以一种提供content Uri的形式提供一个对文件的安全操作:android 中的 FileProvider 组件通过 getUriForFile 方法为 File 生成一个 Content Uri。

2 FileProvider 的使用流程


2.1 注册 FileProvider

和 ContentProvider一样,需要在Manifest 文件中等记,在manifest 中指定 authority属性用来生成 content Uri。
额外的,必须指定一个分享 xml 文件的目录,所以分享的 xml 文件都在该目录下。

<provider
   android:name="androidx.core.content.FileProvider"
   android:authorities="${applicationId}.fileprovider"
   android:exported="false"
   android:grantUriPermissions="true">
   <meta-data
       android:name="android.support.FILE_PROVIDER_PATHS"
       android:resource="@xml/file_paths" />
</provider>
  • name 一般固定为android.support.v4.content.FileProvider。如果开发者继承了FileProvider,则可以写上其绝对路径。
  • authorities 字段的值是一个由 build.gradle 文件中的 applicationId 值和自定义的名称 组成的 Uri 字符串(这样写是约定俗成的)。用来表明使用的使用者,在FileProvider的函数getUriForFile需要传入该参数。
  • exported 的值为false,表示该FileProvider只能本应用使用,不是public的。
  • grantUriPermissions 的值为true,表示允许赋予临时权限。
  • <meta-data> resourece 属性指向 res/xml/file_paths 文件,在这个文件中存放的是想要分享的目录。

2.2 添加共享目录

在 res/xml/file_paths.xml 文件,指名目录

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <files-path name="my_images" path="images/"/>
</resources>
  • 元素必须包含一到多个子元素,这些子元素用于指定共享文件的目录路径:
    <file-path>:内部存储空间应用私有目录下的 files/ 目录,即 Content.getFilesDir() 所获得的的路径
    <cache-path>:内部存储空间应用私有目录下的 cache/ 目录,即 Content.getCacheDir() 所获得的的路径
    <external-path>:外部存储空间根目录,即 Environment.getExternalStorageDirectory() 所获得的的路径
    <external-file-path>:外部存储空间应用私有目录下的 files/ 目录,即 Context.getExternalFilesDir(null) 所获得的的路径
    <external-cache-path>:外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir()
  • 上面的5种基本涵盖内外存储空间所有目录路径,包含应用私有目录。其中,都会有 name 和path 两个属性
    path:用于指定当前子元素所代表目录下需要共享的子目录名称。注意:path属性值不能直接使用具体的独立文件名,只能是目录名
    name:用于给path 属性所指定的子目录名称取一个别名。后续生成 content:// URI 时,会使用这个别名替代真实目录名。可以提供安全性。

2.3 生成 Content URI

在 Android 7.0 出现之前,通常使用 Uri.fromFile() 方式生成一个 File URI。现在这里,使用 FileProvider 类提供的公有静态方法 getUriForFile 生成 Content URI。

Uri contentUri = FileProvider.getUriForFile(this, 
        BuildConfig.APPLICATION_ID + " myprovider", myFile);

其中,第2个参数是 Manifest 文件中注册 FileProvider 时设置的 authority 属性值;第3个参数是要共享的文件,并且这个文件一定位于第二步在 path 文件中添加的子目录中。

String filePath = Environment.getExternalStorageDirectory() + "/images/"+System.currentTimeMillis()+".jpg"; 
File outputFile = new File(filePath); 
if (!outputFile.getParentFile().exists()) { 
   outputFile.getParentFile().mkdir(); 
} 
Uri contentUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".myprovider", outputFile);

生成的 Content URI:
【content://com.yifeng.samples.myprovider/my_images/1493715330339.jpg】
其中,构成URI的【host 】部分为 <provider> 元素的 authorties 属性值(applicationId + customname);【path】片段 my_images 为 res/xml 问文件中指定的子目录别名(真实名为 images)


2.4 授予访问权限

生成 Content URI 对象后,需要对其授权访问权限。授权方式有两种:

  • 第一种方式,使用 Context 提供的 grantUriPermission(package, Uri, mode_flags) 方法向其他应用授权访问 URI 对象。三个参数分别表示授权访问 URI 对象的其他应用包名,授权访问的 Uri 对象,和授权类型。其中,授权类型为 Intent 类提供的读写类型常量:
    FLAG_GRANT_READ_URI_PERMISSION FLAG_GRANT_WRITE_URI_PERMISSION
    或者二者同时授权。这种形式的授权方式,权限有效期截止至发生设备重启或者手动调用 revokeUriPermission() 方法撤销授权时。
  • 第二种方式,配合 Intent 使用。通过 setData() 方法向 intent 对象添加 Content URI。然后使用 setFlags() 或者 addFlags() 方法设置读写权限,可选常量值同上。这种形式的授权方式,权限有效期截止至其它应用所处的堆栈销毁,并且一旦授权给某一个组件后,该应用的其它组件拥有相同的访问权限。

2.5 提供 Content URI 给其它应用

拥有授予权限的 Content URI 后,便可以通过 startActivity() 或者 setResult() 方法启动其他应用并传递授权过的 Content URI 数据。当然,也有其他方式提供服务。
如果你需要一次性传递多个 URI 对象,可以使用 intent 对象提供的 setClipData() 方法,并且 setFlags() 方法设置的权限适用于所有 Content URIs。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值