You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过ACTION_OPEN_DOCUMENT_TREE跳转Download文件夹创建App目录

问题背景
  • 基于Java开发Android Studio应用,为满足Google Play上架合规要求未使用MANAGE_EXTERNAL_STORAGE权限,已收到该权限相关的使用警告。
  • 核心需求:应用启动后在公共Download目录下创建名为「App」的文件夹;在获取存储读写权限后,唤起系统文件选择器直接定位到Download目录,引导用户完成授权后自动创建目标文件夹,预期效果参考截图:
    预期实现效果
  • 初始实现采用ACTION_OPEN_DOCUMENT_TREE方案,代码如下:
// 权限申请通过后执行
Integer NEW_FOLDER_REQUEST_CODE=810;

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, NEW_FOLDER_REQUEST_CODE);


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_OK) { 
        if (requestCode == NEW_FOLDER_REQUEST_CODE) { 
            if (data != null) {
                Uri currentUri = data.getData();
                DocumentFile pickedDir = DocumentFile.fromTreeUri(this, currentUri);
                DocumentFile newDir = pickedDir.createDirectory("App"); 
            } 
        } 
    }
}
  • 遇到两个待解决问题:
    1. 文件选择器启动后默认进入内部存储根目录,无法直接定位到Download文件夹
    2. 选择界面未显示默认值为「App」的新建文件夹名称输入框
解决方案

1. 直接定位到Download文件夹

Android 8.0(API 26)及以上系统支持通过DocumentsContract.EXTRA_INITIAL_URI参数指定文件选择器初始打开目录,传入Download目录对应的标准系统Uri即可实现直接跳转,低版本系统会自动忽略该参数,兼容默认打开逻辑。
注意使用SAF(存储访问框架)访问公共目录时,不需要申请READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE权限,用户通过文件选择器授权后即可通过返回的Uri完成读写操作,移除这两个权限可以进一步降低Google Play审核驳回风险。

2. 新建文件夹输入框预填名称

Android原生系统的ACTION_OPEN_DOCUMENT_TREE选择器默认在右上角提供「新建文件夹」按钮,但没有公开API可以强制选择器启动时自动弹出新建文件夹输入框。部分厂商定制ROM支持读取Intent.EXTRA_TITLE参数预填新建项名称,添加该参数即可做兼容适配。
现有代码中用户授权选定目录后调用createDirectory("App")的逻辑本身是正确的,只要用户选定的是Download目录,就会自动在该路径下创建目标文件夹,不需要依赖系统选择器的新建文件夹弹窗。如果需要强制引导用户选择Download目录,可以在onActivityResult中校验返回的Uri是否对应Download目录,不符合则重新唤起选择器提示用户选择正确路径即可。

修正后完整可运行代码

private static final int NEW_FOLDER_REQUEST_CODE = 810;

// 唤起文件选择器入口方法
private void openDownloadDirectoryPicker() {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    // 配置初始定位到Download目录,API26+生效
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        Uri downloadInitialUri = Uri.parse("content://com.android.externalstorage.documents/document/primary%3ADownload");
        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, downloadInitialUri);
    }
    // 预填新建文件夹名称,适配支持该逻辑的定制ROM
    intent.putExtra(Intent.EXTRA_TITLE, "App");
    // 为返回Uri授予读写权限,避免后续操作失败
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    startActivityForResult(intent, NEW_FOLDER_REQUEST_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_OK && requestCode == NEW_FOLDER_REQUEST_CODE && data != null) {
        Uri selectedUri = data.getData();
        // 持久化存储授权,应用重启后不需要重新申请权限
        final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        getContentResolver().takePersistableUriPermission(selectedUri, takeFlags);
        
        DocumentFile pickedDir = DocumentFile.fromTreeUri(this, selectedUri);
        // 校验目录是否存在,避免重复创建报错
        DocumentFile appDir = pickedDir.findFile("App");
        if (appDir == null || !appDir.exists()) {
            appDir = pickedDir.createDirectory("App");
        }
        // 后续通过appDir.getUri()即可对目标目录下的文件做读写操作
    }
}

内容的提问来源于stack exchange,提问作者comsys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 18:14:52