通过ACTION_SEND intent filter获取URI调用takePersistableUriPermission报SecurityException如何解决
问题根因
该异常由Android系统的权限机制导致:
- 通过
ACTION_OPEN_DOCUMENT返回的URI由系统DocumentsProvider统一管理,系统会为App发放可持久化的读写权限,因此调用takePersistableUriPermission()可以正常获取长期访问权限。 - 通过
ACTION_SEND分享的URI属于发送方App临时授予的一次性权限,有效期最长仅到你的App任务栈销毁为止,系统没有对应持久化授权记录,因此调用takePersistableUriPermission()会直接抛出SecurityException。
可行解决方案
Android系统本身限制了无法直接获取ACTION_SEND分享URI的持久权限,可根据业务场景选择以下方案解决:
方案1:拷贝文件到App私有目录(适合需要长期访问文件的场景)
这是兼容性最好的方案,拿到分享的URI后直接读取内容,写入到你的App内部存储/外部私有存储目录下,后续直接访问本地拷贝的文件即可,无需依赖第三方App的权限。
示例代码:
private fun copySharedUriToPrivateDir(uri: Uri): File? { return try { val inputStream = contentResolver.openInputStream(uri) ?: return null // 自定义私有目录下的存储文件名 val outputFile = File(filesDir, "shared_${System.currentTimeMillis()}.jpg") val outputStream = FileOutputStream(outputFile) inputStream.copyTo(outputStream) inputStream.close() outputStream.close() outputFile } catch (e: Exception) { e.printStackTrace() null } }
在onNewIntent中拿到URI后直接调用该方法即可,无需再执行takePersistableUriPermission逻辑。
方案2:直接使用临时权限(适合仅短期使用文件的场景)
如果你只需要在当前App运行时读取一次文件,不需要重启App后仍能访问,直接删除takePersistableUriPermission这行代码即可,你拿到的URI已经自带临时读权限,可以正常读取内容。
方案3:引导用户用系统文件选择器授权(仅适合必须访问原URI的特殊场景)
如果业务要求必须访问原始URI不能做本地拷贝,可以在拿到分享的URI后,引导用户跳转到系统文件选择器主动选中对应文件,走ACTION_OPEN_DOCUMENT流程获取可持久化权限,该方案会打断用户操作,优先级低于前两个方案。
内容的提问来源于stack exchange,提问作者Johnneh
相关产品推荐
相关产品推荐

