自定义DocumentsProvider在API<26调用takePersistableUriPermission失败
API 21-25 自定义DocumentsProvider持久化URI权限报错解决方案
核心差异根因
Android 8.0(API 26)对SAF(存储访问框架)的权限逻辑做了大量兼容优化,低版本(API 21-25)的校验规则严格很多,你遇到的报错90%的情况是清单配置多了冗余权限属性导致的。
必改配置项
- 移除provider标签中的
android:permission="android.permission.MANAGE_DOCUMENTS"属性MANAGE_DOCUMENTS是系统级权限,仅用于系统内置的文档提供器,自定义DocumentsProvider配置该属性后,API 25及以下系统会要求调用方持有该权限才能申请持久化URI权限,普通第三方应用无法获取该权限,因此系统找不到对应的权限授予记录,直接抛出你遇到的SecurityException。
修改后的provider配置应该如下:
<provider android:name=".storageproviders.FacebookProvider" android:authorities="${facebookDocumentsAuthority}" android:exported="true" android:grantUriPermissions="true"> <intent-filter> <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> </intent-filter> </provider>
额外校验点
如果修改上述配置后仍报错,检查以下两处低版本专属规则:
- queryRoots方法必须配置持久化权限标记
API 21-25要求自定义DocumentsProvider的queryRoots方法返回的根目录Cursor中,必须显式设置FLAG_SUPPORTS_PERSISTABLE_PERMISSIONS标记,否则系统不会生成持久化权限记录,示例代码如下:@Override public Cursor queryRoots(String[] projection) throws FileNotFoundException { MatrixCursor cursor = new MatrixCursor(projection); MatrixCursor.RowBuilder row = cursor.newRow(); // 其他根目录配置项省略 row.add(DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.FLAG_SUPPORTS_PERSISTABLE_PERMISSIONS // 追加你原本的其他flag,比如FLAG_LOCAL_ONLY、FLAG_SUPPORTS_SEARCH等 | DocumentsContract.Root.FLAG_LOCAL_ONLY); return cursor; } - 返回的URI必须严格符合DocumentsProvider规范
低版本系统要求SAF选择器返回的URI必须严格遵循content://<authority>/document/<documentId>格式,不能有多余的路径参数或者查询参数,API 26+对格式做了兼容容错,低版本只要格式有偏差就会匹配不到权限记录。
调试参考
修改后可以先打印contentResolver.getPersistedUriPermissions()的返回值,确认调用takePersistableUriPermission之前系统是否已经生成了对应的临时权限记录。
内容的提问来源于stack exchange,提问作者tfrysinger
相关产品推荐
相关产品推荐

