聊聊对Andorid的FileProvider的理解
最近在项目中遇到一个有关FileProvider的问题,由此来学习了一下FileProvider,有关笔记记录如下。
FileProvider是 Android 系统中一个特殊的内容提供者(ContentProvider), 它主要用于应用之间安全的共享文件。通过 FileProvider,应用可以生成一个 content URI并授予其它应用临时访问的权限,而不需要将文件的实际路径暴露给其它应用。这样可以有效的避免安全问题。
主要用途
FileProvider主要应用于以下几种场景:
- 文件共享:当一个应用需要与另外一个应用共享文件时(比如使用Intent发送图片/文件),可以使用 FileProvider来生成一个 content URI;
- 文件访问控制:通过 FileProvider 可以控制其他应用对文件的读写权限,确保文件访问的安全性;
- 避免使用file://URI:由于从Andorid 7.0起,file://URI被弃用,使用 FileProvider 提供的 content URI 可以避免兼容性。
使用步骤
a. 在 AndroidManifest.xml 中声明 FileProvider:
b. 配置文件路径
在 res/xml 目录下创建一个 file_paths.xml 文件,定义共享文件的路径。
c. 生成 content URI
使用 FileProvider.getUriForFile() 方法来生成一个 content URI。
File file = new File(context.getExternalFilesDir(null), "example.jpg"); Uri contentUri = FileProvider.getUriForFile(context, "com.example.myapp.fileprovider", file);
d. 授予临时权限,并分享
当通过Intent发送文件时,可以授予接收临时访问文件的权限:
Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("image/*"); intent.putExtra(Intent.EXTRA_STREAM, contentUri); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(Intent.createChooser(intent, "Share image via"));
详细解释 file_paths.xml
在 file_paths.xml, 的解释如下:
- external-files-path 用于指定应用的外部私有存储目录中的文件路径。外部私有存储目录是指通过 Context.getExternalFilesDir()方法获取的目录,它通常用于存储应用专属的文件,这些文件会随着应用的卸载而被删除。
- name=“my_files”: 这是一个可选的属性,用于为这个路径配置起一个别名。在生成的Content URI中,这个别名会作为路径的一部分。如果不需要这个别名,那么也可以直接去掉。
- path="."这个属性指定了相对于 external-files-path 目录的相对路径. "."代表当前目录,即整个 external-files-path 所在的目录。如果你想指定该目录下的某个子目录,你可以在 path属性中提供相对路劲,例如path=“images/”.
我们来一个例子:
假设我们的包名是com.xing.dev,并且在 file_path.xml中配置了如下内容:
然后通过getExternalFilesDir获取文件保存目录,并且在该目录下有一个a.png文件:
File file = new File(context.getExternalFilesDir(null), "a.png"); Uri contentUri = FileProvider.getUriForFile(context, "com.xing.dev.fileprovider", file);
那么,此时生成的 contentUri就应该是如下的样子:
content://com.xing.dev.fileprovider/my_files/a.png
当然,我们还可以配置更加复杂的路径:
如果我现在只想别的应用仅仅共享特定目录下的文件,那么我就可以配置更加具体的路径:
这样,那么就只能访问 /external-files-path /images/ 和 /external-files-path/documents/ 文件夹下的文件了。
那么,除了external-files-path 这个外部私有存储目录中的文件路径,file_paths.xml中还支持哪些tag呢?
目前来说,现在支持的是5个,分别是external-path,external-files-path,external-cache-path , files-path 和 cache-path, 可以通过下表来查看他们之间的含义:
假设我们的包名还是上面那个:com.xing.dev:
标签名称 对应java代码 路径Demo 含义 external-path Environment.getExternalStorageDirectory() /storage/emulated/0 整个外部存储目录 external-files-path Context.getExternalFilesDir(String) /storage/emulated/0/Android/data/com.xing.dev/files 应用的外部私有存储目录中的文件路径 external-cache-path Context.getExternalCacheDir() /storage/emulated/0/Android/data/com.xing.dev/cache 应用的外部私有存储目录中的缓存路径 files-path Context.getFilesDir() /data/user/0/com.xing.dev/files 应用的内部私有存储目录中的文件路径 cache-path Context.getCacheDir() /data/user/0/com.xing.dev/cache 应用的内部私有存储目录中的缓存路径 那么,如果我们理解了以上文件目录所代表的含义,那么使用FileProvider就非常容易了。总结下来,我们就可以有以下步骤:
- 确定我们需要共享文件的位置,是在整个外部存储目录中(这个显然不是特别安全,不推荐使用),还是在外部/内部私有文件/缓存目录中;
- 确定好之后,那么我们可以确定使用哪个标签;
- 确定好标签之后,如果还有更细粒度的要求,我们还可以加上子文件夹;
- 确定好 file_paths.xml之后,可以通过代码获取对应目标的文件夹,然后生成对应的 ContentURI;
- 最后就可以进行分享了。
对于一个越来越安全的android系统,使用FileProvider将App的存储目录分为5个部分,然后通过各自定义文件配置,实现对文件精细粒度的控制。