存储访问框架,takePersistableUriPermission

Storage Access Framework, takePersistableUriPermission

在我的应用程序中,用户可以select 下载目录。如果他selects external removable SD卡(不是模拟的sd卡!,而是内存,例如真正的physicel microSD卡),从Android 4.4 我只能使用 SAF(存储访问框架)写入它。

我已经弄清楚如何使用 SAF 创建和写入单个文件:

public void newFile() {
    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);

    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("text/plain");
    intent.putExtra(Intent.EXTRA_TITLE, "newfile.txt");

    startActivityForResult(intent, CREATE_REQUEST_CODE);
}

public void saveFile() {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("text/plain");

    startActivityForResult(intent, SAVE_REQUEST_CODE);
}

这是我的 onActivityResult,我实际写入文件的地方:

public void onActivityResult(int requestCode, int resultCode,
                             Intent resultData) {
    Uri currentUri = null;

    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == CREATE_REQUEST_CODE) {
            if (resultData != null) {
                Log.d(TAG, "CREATE_REQUEST_CODE resultData = " + resultData);
            }
        } else if (requestCode == SAVE_REQUEST_CODE) {

            if (resultData != null) {
                currentUri = resultData.getData();
                getContentResolver().takePersistableUriPermission(currentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                writeFileContent(currentUri);
                Log.d(TAG, "SAVE_REQUEST_CODE currentUri = " + currentUri);
            }
        }
    }
}

还有writeFileContent

private void writeFileContent(Uri uri) {
    try {
        ParcelFileDescriptor pfd =
                this.getContentResolver().
                        openFileDescriptor(uri, "w");

        FileOutputStream fileOutputStream =
                new FileOutputStream(pfd.getFileDescriptor());

        String textContent = "some text";

        fileOutputStream.write(textContent.getBytes());

        fileOutputStream.close();
        pfd.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

最后是我的问题:

如何创建其他文件,并在我调用 getContentResolver().takePersistableUriPermission 之后在没有提示的情况下将它们写入 select 目录?

如果我是对的,那么getContentResolver().takePersistableUriPermission应该允许我这样做

感谢@earthw0rmjim 的回答和谷歌搜索,我找到了一个完整的解决方案:

public void saveFile() {
    List<UriPermission> permissions = getContentResolver().getPersistedUriPermissions();
    if (permissions != null && permissions.size() > 0) {
        DocumentFile pickedDir = DocumentFile.fromTreeUri(this, permissions.get(0).getUri());
        DocumentFile file = pickedDir.createFile("text/plain", "try2.txt");
        writeFileContent(file.getUri());
    } else {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("text/plain");

        startActivityForResult(intent, SAVE_REQUEST_CODE);
    }
}

所以首先,如果我们没有PersistedUriPermissions,它会请求这样的权限。这样 onActivityResult 看起来像

public void onActivityResult(int requestCode, int resultCode,
                             Intent resultData) {
    Uri currentUri = null;

    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == SELECT_DIR_REQUEST_CODE) {
            if (resultData != null) {
                Uri treeUri=resultData.getData();
                Log.d(TAG, "SELECT_DIR_REQUEST_CODE resultData = " + resultData);
                getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
                DocumentFile file = pickedDir.createFile("text/plain", "try2.txt");
                writeFileContent(file.getUri());
            }
        }
    }
}

writeFileContent 看起来和问题中的一样

private void writeFileContent(Uri uri) {
    try {
        ParcelFileDescriptor pfd =
                this.getContentResolver().
                        openFileDescriptor(uri, "w");

        FileOutputStream fileOutputStream =
                new FileOutputStream(pfd.getFileDescriptor());

        String textContent = "some text";

        fileOutputStream.write(textContent.getBytes());

        fileOutputStream.close();
        pfd.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}