FileProvider

本文详细介绍了FileProvider的使用方法,包括如何定义FileProvider、指定允许访问的文件路径、生成文件对应的contentURI以及如何给一个URI临时授权等内容。

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

参考文档:

FileProvider 是一个特殊的 ContentProvider 的子类,它使用 content://Uri 代替了 file:/// Uri ,更便利而且安全的为另一个 app 分享文件。

定义 FileProvider

在项目的 Manifest 文件中添加如下代码:

<manifest>
    ...
    <application>
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.yourdomain.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            ...
        </provider>
        ...
    </application>
</manifest>

其中,

  • android:name 属性固定为 android.support.v4.content.FileProvider

  • android:authorities属性设置为 com.yourdomain.fileprovider 格式,yourdomain为你自己的项目包名;

  • android:exported属性设置为 false, FileProvider 不需要被其他程序访问;

  • android:grantUriPermissions属性设为 true, 以便允许你给特定文件进行临时授权。

如果你要覆盖 FileProvider 的属性,可以继承 FileProvider,继承的时候,FileProvider 要导入 android:name 中指定的全名,如下所示:

import android.support.v4.content.FileProvider;

public class MyFileProvider extends FileProvider {
    ......
}

指定允许访问的文件路径

FileProvider 只能访问你预先指定的目录。可以使用 <paths> 子标签来指定要访问的文件路径。例如,下面的代码告诉 FileProvider, 我们打算访问 images/ 子目录下的文件。

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="images/"/>
    ...
</paths>

<paths> 标签必须包含一个或多个下述子标签的内容:

  • <files-path> 共享app内部的存储(等价于 Context.getFilesDir() 返回的内容):
<files-path name="name" path="path" />
  • <cache-path> 共享内部缓存目录(等价于 getCacheDir() 返回的内容):
<cache-path name="name" path="path" />
  • <external-path> 共享外部的存储(等价于 Environment.getExternalStorageDirectory() 返回的内容):
<external-path name="name" path="path" />
  • <external-files-path> 共享外部存储中与你的应用关联的目录(等于 Context.getExternalFilesDir(String)Context.getExternalFilesDir(null) 返回的内容):
<external-files-path name="name" path="path" />
  • <external-cache-path> 共享外部存储中与你的应用关联的缓存目录(等价于 Context.getExternalCacheDir() 返回的内容):
<external-cache-path name="name" path="path" />

上述子标签都用到了下面两个属性:

  • name="name"
    引号里的内容可以随便填,建议填有意义的内容。

  • path="path"
    path属性的值表示共享的具体路径。注意:path属性里指定的是路径,而不是某个特定文件。这里不能指定为一个文件,也不能用通配符指定为一组文件。

对每一个你想要请求的文件,都必须在 <paths> 标签下指定。例如,下面的 XML 标签指定了两个目录:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="images/"/>
    <files-path name="my_docs" path="docs/"/>
</paths>

其中属性的意思:

  • path="images/" 就是你所要共享的文件路径;

  • name="my_images" 就是告诉 FileProvider 用 my_images 添加进 URI 内容字段去访问 files/images/ 的子目录。

然后就可以通过URI访问 app 的文件了:content://com.mydomain.fileprovider/my_images/default_image.jpg。下文有关于获取该 Uri 的内容。

可以看到:
com.mydomain.fileprovider 是我们在 AndroidManifest.xml 中指定的;
myimages:是我们指定的 name;
default_image.jpg:就是我们想要访问的图片了。

官方推荐的写法是,将 <paths> 标签及其子标签指定的内容放在项目下的一个 XML 文件中。例如,将它们放入 res/xml/file_paths.xml 文件中。

为了能使 FileProvider 访问到 file_paths.xml 文件,可在 <provider> 标签下加入一个 <meta-data> 子标签:

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

生成文件对应的 content URI

为了和其他应用共享文件,你需要生成该文件对应的 Content URI。

以下是共享文件的操作步骤:

首先: 为要共享的文件创建一个 File 对象;

然后: 将该 File 对象传入 getUriForFile(),该方法会返回一个 content URI;

接着: 可以通过 Intent 将该 content URI 传递给其他应用或外部存储;

最后: 接收到该 content URI 的其他应用可以通过调用 ContentResolver.openFileDescriptor 得到一个 ParcelFileDescriptor

下面是一个官网的例子:

假设通过 一个权限为 com.mydomain.fileprovider 的 FileProvider 来获取在应用内部存储的子目录 image/ 下的文件 default_image.jpg

File imagePath = new File(Context.getFilesDir, "images");
File newFile = new File(imagePath, "default_image.jpg");
Uri contentUri = getUriForFile(getContext, "com.mydomain.fileprovider", newFile);

上述代码片段中,getUriForFile(...)返回的 contentUri 的值为 content://com.mydomain.fileprovider/my_images/default_image.jpg

给一个 URI 临时授权

为了给上述 contentUri 授予访问权限,可以采用下面的方法之一:

第一种

  • 调用方法 Context.grantUriPermission(package, Uri, mode_flags)。对于给定的 Uri, 这个方法根据 mode_flags 授予对指定 package 的临时访问权限。mode_flags 有 FLAG_GRANT_READ_URI_PERMISSIONFLAG_GRANT_WRITE_URI_PERMISSION 两个值。除非你调用 revokeUriPermission() 撤销授权或者重启设备,这种授权将一直有效。

第二种

  • 通过 setData() 将该 contentUri 放到一个 Intent 中;

  • 调用 Intent.setFlags() 方法,传入 FLAG_GRANT_READ_URI_PERMISSIONFLAG_GRANT_WRITE_URI_PERMISSION,也可以两个都传入;

  • 最后,调用 setResult(int resultCode, Intent data) 返回授权给请求者。

通过 Intent 授予的权限在当请求 Activity 处于栈顶的时候有效。当该 Activity 所在的栈被清除时,授予的权限也会被自动清除掉。

值得注意的是,授予给一个 Activity 的权限也就是等于授予给该 Activity 所在应用的所有组件该权限。

向另一个应用提供 Content URI

有很多种方式向一个应用提供 content URI。

这部分信息建议看官网,很好理解,我就不翻译了。

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值