【问题标题】:Can't access Sd Card after providing permission with Storage Access Framework使用存储访问框架提供权限后无法访问 SD 卡
【发布时间】:2016-07-20 20:57:35
【问题描述】:

我正在尝试使用存储访问框架在我的应用内提供 sd 卡访问。

这就是我所说的让用户选择 sd 卡目录的意图。

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_OPEN_DOCUMENT_TREE);
}

这就是我管理意图结果以设置权限的方式:

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case REQUEST_CODE_OPEN_DOCUMENT_TREE:
                if (resultCode == Activity.RESULT_OK) {
                    Uri treeUri = data.getData();
                    int takeFlags = data.getFlags();
                    takeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION |
                                  Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        this.getContentResolver().takePersistableUriPermission(treeUri, takeFlags);
                    }
               }
        }

但仍然无法在 sd 卡上保存任何文件。

我设备上@9​​87654323@ 的值是:

content://com.android.externalstorage.documents/tree/6921-B9FD%3A

我在这里错过了什么,系统仍然不能让用户访问 sd 卡(在 sd 卡上保存一个简单的文件)?

【问题讨论】:

  • “这就是我所说的让用户选择 sd 卡目录的意图”——你可以摆脱 addFlags() 的调用。这些都不相关。这些是给内容的发布者的,告诉系统他们为内容的消费者提供了什么。你是消费者。 “但仍然无法在 sd 卡上保存任何文件”——在使用 DocumentFilecreateDirectory()createFile() 等方法后,您应该可以使用 ContentResolveropenOutputStream()。显示您保存内容的代码,并说明您遇到了什么错误(或您的一般症状)。
  • 请记住,用户不必为ACTION_OPEN_DOCUMENT_TREE 选择可移动存储。用户可以选择 Google Drive、Dropbox 或任何其他存储提供商,这些都与您其他问题中的硬编码路径无关。而且,如果您所做的只是复制单个文件,请使用ACTION_CREATE_DOCUMENT 获取Uri,然后使用ContentResolveropenOutputStream() 获取将内容写入到的流,这样可以省去一些麻烦。
  • 这并没有改变 用户 可能会选择其他存储提供商的事实。除此之外,您应该仍然可以使用DocumentFileContentResolver 来完成此操作,从而处理那些选择不同存储提供商的用户同时处理可移动媒体。 “那么是否可以检查用户是否有意选择了正确的目录?” ——不可靠。你可以检查getHost()Uri,看看它是否符合你的预期,但我希望它会在不同的设备上中断,因为制造商会搞砸这些东西。
  • findFile() 查看子目录是否存在。 createDirectory() 如果不存在则创建它。
  • 不要打电话给getPath()永远不要Uri 上调用getPath(),除非方案是file。您可以调用getDisplayName() 来获取提供者想要为DocumentFile 标识的文档的显示名称使用的内容。此显示名称不必是目录名或文件名,因为它取决于存储提供程序。

标签: android android-permissions android-sdcard storage-access-framework


【解决方案1】:

好的。这就是我使用提供的权限在 sd 卡上复制图像的方式,该权限调用文件选择器以由用户选择 sd 卡目录(可能用户选择了错误的目录,因此请准备好您的代码)。

private void newcopyFile(File fileInput, String outputParentPath,
                        String mimeType, String newFileName) {

    DocumentFile documentFileGoal = DocumentFile.fromTreeUri(this, treeUri);

    String[] parts = outputParentPath.split("\\/");
    for (int i = 3; i < parts.length; i++) { //ex: parts:{"", "storage", "extSdCard", "MyFolder", "MyFolder", "MyFolder"}
        if (documentFileGoal != null) {
            documentFileGoal = documentFileGoal.findFile(parts[i]);
        }
    }
    if (documentFileGoal == null) {
        Toast.makeText(MainActivity.this, "Directory not found", Toast.LENGTH_SHORT).show();
        return;
    }

    DocumentFile documentFileNewFile = documentFileGoal.createFile(mimeType, newFileName);

    InputStream inputStream = null;
    OutputStream outputStream = null;
    try {
        outputStream = getContentResolver().openOutputStream(documentFileNewFile.getUri());
        inputStream = new FileInputStream(fileInput);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    try {
        if (outputStream != null) {
            byte[] buffer = new byte[1024];
            int read;
            if (inputStream != null) {
                while ((read = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, read);
                }
            }
            if (inputStream != null) {
                inputStream.close();
            }
            inputStream = null;
            outputStream.flush();
            outputStream.close();
            outputStream = null;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

注意:阅读问题下的所有comments

并注意setting a ContentObserver to your ContentResolver 如果您想在新创建的图像在ContentResolver 中注册时得到通知,因此是时候查询它了(如果您愿意的话)。

【讨论】:

  • 这里的 outputParentPath 是什么?请在这里帮助我解决我的问题:- stackoverflow.com/q/39054454/6289068 它也有活跃的赏金。请帮我解决一下这个。真的卡在这里
  • yourFile.getParentFile(),您必须考虑许多情况,我会告诉您作为您问题的答案。别担心,这是一款简单的游戏。
  • @Eftekhari 我尝试使用您的上述方法 newcopyFile。但它显示没有找到目录。请帮助我为我的问题提供解决方案:- stackoverflow.com/q/39054454/6289068
猜你喜欢
  • 2016-08-20
  • 2011-11-13
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 2015-12-10
  • 2016-08-01
  • 2020-09-06
  • 1970-01-01
相关资源
最近更新 更多