安卓 - 请求写入SD卡权限对话框

6
我无法获得对设备SD卡根目录的写入访问权限。我可以在设备内部存储和SD卡中的应用程序包文件夹中写入,没有问题。我发现使用存储访问框架可以访问SD卡,所以我查看了其他应用程序,看它们如何访问SD卡,并发现Total Commander带有其整洁的权限对话框。

write to SD card permission dialog

如何显示这样的对话框,因为我找不到任何示例?我的目标是在卸载应用程序后保留在SD卡上存储大文件。
类似的问题: Android(写入外部SD卡):java.io.IOException:权限被拒绝 Android M写入SD卡-权限被拒绝 使用SAF(存储访问框架)的Android SD卡写入权限

https://developer.android.com/training/permissions/requesting - ישו אוהב אותך
2个回答

6

我找到了一个开源文件管理器。查看了代码,最终找到了解决方案。

仅适用于 Android N(7.0.0)(api 24)及以上版本。

首先获取SD卡的根路径并显示用户权限对话框。

public void takeCardUriPermission(String sdCardRootPath) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            File sdCard = new File(sdCardRootPath);
            StorageManager storageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
            StorageVolume storageVolume = storageManager.getStorageVolume(sdCard);
            Intent intent = storageVolume.createAccessIntent(null);
            try {
                startActivityForResult(intent, 4010);
            } catch (ActivityNotFoundException e) {
            }
        }
    }

当用户接受请求时,onActivityResult()会被触发,我们可以从意图数据中保存 uri.

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 4010) {

            Uri uri = data.getData();

            grantUriPermission(getPackageName(), uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
                    Intent.FLAG_GRANT_READ_URI_PERMISSION);

            final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
                    Intent.FLAG_GRANT_READ_URI_PERMISSION);

            getContentResolver().takePersistableUriPermission(uri, takeFlags);
        }
    }

现在我们可以获取SD卡根目录的URI,并将其与存储访问框架一起使用。
public Uri getUri() {
        List<UriPermission> persistedUriPermissions = getContentResolver().getPersistedUriPermissions();
        if (persistedUriPermissions.size() > 0) {
            UriPermission uriPermission = persistedUriPermissions.get(0);
            return uriPermission.getUri();
        }
        return null;
    }

@a-urbanavičius,你能分享一个开源文件管理器应用的链接吗?这会对我很有帮助。 - Nils
在哪里调用getUri方法? - Nils
@Nils https://github.com/1hakr/AnExplorer 是我找到的具有此对话框和其源代码的应用程序。但请记住,正如上面的答案所述,此对话框在Android Q中已被弃用。另外,关于uri,请观看Android存储访问框架的教程,它并不复杂。祝你好运。 - Anurban
@a-urbanavičius 感谢您的更新,它真的帮了我很多。在Android Q中,这个对话框会消失或者不起作用吗? - Nils
1
@Nils 这样做不起作用,因为它会返回 RESULT_CANCELED 而不是显示对话框。 - Anurban
没错,它总是返回RESULT_CANCELED,因为我不知道它已经被弃用了。你救了我的一天。 - Nils

4
很遗憾,在Android Q中,使用createAccessIntent已经被弃用,文档指出,如果您在Android Q中使用它,它会立即返回RESULT_CANCELED。
他们建议使用带有ACTION_OPEN_DOCUMENT_TREE的意图。您可以指定它最初打开的目录(仅支持Android O及以上版本),使用户更容易操作,但这仍然不是非常用户友好的方法。
我想知道是否有其他用户友好型的解决方案,有人知道吗?我不明白为什么Android删除了createAccessIntent,因为它似乎是最用户友好的方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接