使用存储访问框架(Storage Access Framework)请求文件夹权限时,Intent.FLAG_GRANT_PREFIX_URI_PERMISSION的作用是什么?
FLAG_GRANT_PREFIX_URI_PERMISSION的详细解释 好问题!这个FLAG_GRANT_PREFIX_URI_PERMISSION确实是Storage Access Framework(SAF)里容易让人混淆的权限标志,我来一步步拆解你的疑问:
一、什么是“前缀匹配”?
简单来说,前缀匹配就是只要两个URI的协议(scheme)、授权方(authority),以及路径的前缀部分完全一致,就会被视为符合权限要求,而不需要整个URI完全相同。
举个实际的例子:当你通过SAF选择了内部存储/Documents文件夹时,系统返回的原始URI大概是这样的:
content://com.android.externalstorage.documents/tree/primary%3ADocuments
如果添加了FLAG_GRANT_PREFIX_URI_PERMISSION,那么以下这些URI都会被授予权限:
- 文件夹里的某个文件:
content://com.android.externalstorage.documents/tree/primary%3ADocuments/document/primary%3ADocuments%2Fnotes.txt - 文件夹下的子文件夹:
content://com.android.externalstorage.documents/tree/primary%3ADocuments/document/primary%3ADocuments%2FPhotos - 子文件夹里的文件:
content://com.android.externalstorage.documents/tree/primary%3ADocuments/document/primary%3ADocuments%2FPhotos%2Fpic.jpg
这些URI的scheme都是content://,authority都是com.android.externalstorage.documents,并且路径前缀都包含tree/primary%3ADocuments,所以都属于前缀匹配的范畴。如果没有这个标志,只有你选中的那个文件夹的原始URI会被授权,里面的文件和子文件夹都无法直接访问,必须单独申请权限——这显然不符合我们请求文件夹权限的初衷。
二、“原始授权URI”具体指的是什么?
这里的“原始授权URI”就是用户通过SAF选择文件夹后,系统在onActivityResult中返回给你的那个URI,也就是代码里你后续会从intent.data拿到的对象。
比如上面例子里的content://com.android.externalstorage.documents/tree/primary%3ADocuments,这个就是系统给你的“原始授权URI”,所有和它前缀匹配的子URI都会继承你申请的读写权限。
三、该标志位在应用请求新文件夹权限时有用么?
非常有用!甚至可以说,当你请求的是**文件夹权限(ACTION_OPEN_DOCUMENT_TREE)**时,这个标志是必不可少的:
- 如果你只添加了
FLAG_GRANT_READ_URI_PERMISSION和FLAG_GRANT_WRITE_URI_PERMISSION,没有加前缀标志,那么你只能对选中的文件夹本身做操作(比如重命名文件夹),但无法访问里面的任何文件或子文件夹——因为这些内容的URI和原始文件夹URI不是完全匹配的,只有前缀匹配。 - 加上
FLAG_GRANT_PREFIX_URI_PERMISSION后,你才能真正拥有整个文件夹及其所有子内容的读写权限,这才是我们请求文件夹权限的核心目的。
结合你给出的代码,四个标志的作用可以总结为:
FLAG_GRANT_READ_URI_PERMISSION+FLAG_GRANT_WRITE_URI_PERMISSION:授予基础的读写权限FLAG_GRANT_PERSISTABLE_URI_PERMISSION:让权限在设备重启后依然保留,不需要重新申请FLAG_GRANT_PREFIX_URI_PERMISSION:让权限覆盖原始授权URI下的所有子内容,实现真正的文件夹级访问
内容的提问来源于stack exchange,提问作者vepzfe

