如何通过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"); } } } }
- 遇到两个待解决问题:
- 文件选择器启动后默认进入内部存储根目录,无法直接定位到Download文件夹
- 选择界面未显示默认值为「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
相关产品推荐
相关产品推荐

