存储访问框架持久权限不起作用

Posted

技术标签:

【中文标题】存储访问框架持久权限不起作用【英文标题】:Storage Access Framework persist permissions not working 【发布时间】:2015-12-10 08:58:11 【问题描述】:

我使用 android Storage Access Framework 来访问 SD 卡上的一些文件。保留此权限对我来说很重要,以便能够在设备重启后编辑文件。

因此,根据Storage Access Framework documentation,我使用 Persist 权限,即使设备已重新启动,用户也可以通过您的应用继续访问文件。

但是,一段时间后,我注意到某些用户的权限以某种方式被撤销。因为当我尝试使用 SAF 写作时,我得到 android.system.ErrnoException: open failed: EACCES (Permission denied) 在该异常之后,我使用mContext.getContentResolver().getPersistedUriPermissions() 检查我有哪些权限,但它返回空列表。我确信用户为我提供了正确的权限,并且该权限适用于当前安装的 SD 卡,因为我在数据库中跟踪此操作。

目前,在这种情况下,我正在显示文档选择器,以便用户可以再次向我提供新权限,但要求用户执行相同的操作通常对用户不友好。

什么会导致权限被撤销?以及如何防止这种撤销?

我已经在我的所有设备上测试了多次重启手机、更改时间、移除插入的 sd 卡,但无法丢失任何 saf 权限。

我有下一个获取权限的代码:

private void openDocumentTree() 
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        startActivityForResult(intent, REQUEST_CODE);
    

public void onActivityResult(int requestCode, int resultCode, Intent data) 
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE) 
            Uri treeUri = data.getData();
            final int takeFlags = data.getFlags() & ( 
                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            mContext.getContentResolver().takePersistableUriPermission(treeUri,
                    takeFlags);

                    //this is my internal class for saving and restoring tree uri permissions.
                    final Permission permission = Permission.from(treeUri);
                    mPermissionDao.save(permission);
        
    

【问题讨论】:

“我使用 Android 存储访问框架来访问 SD 卡上的一些文件”——不,您正在使用 SAF 处理文档。是否存储这些文档取决于用户,而不是您。它们可以由任何提供商(Google Drive、Dropbox 等)管理。 “我确信用户为我提供了正确的权限,并且该权限适用于当前安装的 SD 卡,因为我在数据库中跟踪此操作”——用户选择的文档不必位于 SD 卡上。 “什么会导致权限被撤销?” -- 可能是用户从提供者那里删除了文件。 我只使用 Saf 来处理 SD 卡上的文件,因为特定的应用程序,只有与外部存储提供商合作的理由。我检查树 uri 是外部存储格式。 也许用户从提供者那里删除了文件——这是不可能的,因为我收到了代表外部存储根路径的树 uri。没有办法删除它。另外,正如我所提到的,我无法创建新文件(它正在抛出 android.system.ErrnoException)并且 getContentResolver().getPersistedUriPermissions() 返回了空列表。所以用户以某种方式撤销了权限。 “我检查树 uri 是否采用外部存储格式”——因为没有记录“外部存储格式”,并且欢迎设备制造商和自定义 ROM 构建器更改 Android,您的方法不可靠。 “我收到了代表外部存储根路径的树 uri”——您自己承认,您不知道,因为您无法重现该问题。欢迎用户选择用户想要的任何文档树,您无法可靠地确定它是否是“外部存储的根路径”。 是的,你说得对,这种方法不可靠,但这是在 Android 4.3 更新后访问 SD 卡的唯一方法。 【参考方案1】:

请求ACTION_OPEN_DOCUMENT_TREE时需要额外的标志。

openDocumentTree 应该是这样的

private void openDocumentTree() 
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    intent.addFlags(
        Intent.FLAG_GRANT_READ_URI_PERMISSION
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
        | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
    startActivityForResult(intent, REQUEST_CODE);

查看FLAG_GRANT_PERSISTABLE_URI_PERMISSION 和FLAG_GRANT_PREFIX_URI_PERMISSION 的文档

【讨论】:

以上是关于存储访问框架持久权限不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Spring安全令牌持久性存储不起作用

当指定存储级别时,在 pyspark2 中持久化数据帧不起作用。我究竟做错了啥?

尝试使用基于S3资源的策略允许Lambda访问S3,为什么它不起作用?

持久性 EHcache 文档中的代码不起作用 java

VS 2010 - 带有 MySql 存储过程的实体框架似乎不起作用

从代码中修改文件权限不起作用