使用SAF(存储访问框架)在Android中获取SD卡写入权限

25

经过一番探索,我发现在Android 5及以上版本中如何写入(和重命名)SD卡文件,我认为需要使用Android提供的新SAF来获取用户写入SD卡文件的权限。

我在这个文件管理应用程序ES文件浏览器中看到,最初它以以下方式获取读写权限,如图片所示。

enter image description here

Picture 2

选择SD卡后,将授予写入权限。

所以我尝试使用SAF,但在重命名文件时失败了。我的代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    rename = (Button) findViewById(R.id.rename);

    startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), 42);
}

@Override
public void onActivityResult(int requestCode,int resultCode,Intent resultData) {
    if (resultCode != RESULT_OK)
        return;
    Uri treeUri = resultData.getData();
    DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
    grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}

public void renameclick(View v) {
    File ff = new File("/storage/sdcard1/try1.jpg");
    try {
        ff.createNewFile();
    } catch (Exception e) {
        Log.d("error", "creating");
        e.printStackTrace();
    }
}

尽管我已经运行了代码,但仍然收到EAacces权限被拒绝的提示。

1个回答

31

让用户选择“SD卡”甚至是“内部存储”SAF根目录,可以使您的应用程序通过SAF API访问相应的存储空间,但不能直接通过文件系统访问。例如,您的代码可能被转换成以下内容:

public void writeFile(DocumentFile pickedDir) {
    try {
        DocumentFile file = pickedDir.createFile("image/jpeg", "try2.jpg");
        OutputStream out = getContentResolver().openOutputStream(file.getUri());
        try {

            // write the image content

        } finally {
            out.close();
        }

    } catch (IOException e) {
        throw new RuntimeException("Something went wrong : " + e.getMessage(), e);
    }
}

在最近的Android版本中,几乎完全废弃了使用java.io.File访问应用程序外部数据的方式。


1
但是每当我需要创建或重命名文件时,SAF选择器就会打开。 - Ankesh kumar Jaisansaria
4
一旦您获得了树形URI,您可以对其中包含的文件和目录进行任何操作。只要您使用takePersistableUriPermission()并将URI存储在某个地方,以便在应用程序启动时检索它,就无需每次询问用户。 - bwt
我们如何在createFile只接受MimeType和名称作为参数的情况下访问所选目录的子目录?我们如何将java.io.file类型的路径转换为DocumentFile - Eftekhari
3
你可以这样做:DocumentFile pickedTree = DocumentFile.fromFile(App.getContext(), uriTree); for (DocumentFile file : pickedTree.listFiles()) { if (file.isDirectory()) file.createFile(mimeType, fileName); } 意思是从 uriTree 创建一个 DocumentFile 对象,然后遍历该对象下的所有文件和文件夹。如果当前项是一个文件夹,则创建一个新的文件,并以 mimeTypefileName 命名。 - Ruslan Berozov
如何将数据写入SD卡中某个子目录下的文件。 - Rahulrr2602

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