Android || FileProvider 控件的使用

it2025-07-28  33

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。

最新回复(0)