Android 11下File.listFiles()无法返回非媒体扩展名文件的问题排查与解决咨询
Android 11下遍历Download目录无法获取非媒体文件的原因与解决方案
这是个非常典型的Android 11存储权限机制变更带来的问题,咱们一步步理清楚:
问题原因
从Android 11(API Level 30)开始,谷歌对外部存储权限做了严格的限制:
- 原来的
READ_EXTERNAL_STORAGE权限,在API 30及以上版本中,仅能访问媒体类型的文件(就是你提到的.jpg、.png、.mp4这类),非媒体文件(.txt、.pdf、.doc等)会被系统自动过滤,所以listFiles()拿不到它们。 - 当你把targetAPI降到28(对应Android 9)时,系统还没启用这个权限限制,
READ_EXTERNAL_STORAGE依然能访问外部存储下的所有文件,所以问题自然就消失了。
解决方案
根据你的业务需求,有几个可行的方案可选:
方案1:申请MANAGE_EXTERNAL_STORAGE特殊权限(适用于需要批量访问全目录文件的场景)
这个权限是Android 11新增的特殊权限,能让应用获得对外部存储所有文件的访问权,但需要引导用户到系统设置页面手动开启:
// 检查是否拥有全存储访问权限 if (Environment.isExternalStorageManager()) { // 有权限,执行你的文件遍历逻辑 DebugListingFile(); } else { // 没有权限,跳转至系统设置页面申请 Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent); }
注意:这个权限的审核比较严格,如果你是普通应用,谷歌Play可能会限制上架,除非你的应用确实是文件管理器、备份类等必须全存储访问的类型。
方案2:使用存储访问框架(SAF)让用户主动选择目录(推荐,符合现代Android存储规范)
这种方式不需要特殊权限,通过系统的文件选择器让用户授权访问Download目录,之后就能获取该目录下的所有文件:
// 启动SAF选择Download目录 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); // 预设打开Download目录,提升用户体验 intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.parse("content://com.android.externalstorage.documents/tree/primary%3ADownload")); startActivityForResult(intent, 1001); // 在onActivityResult中处理返回的权限与目录 @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1001 && resultCode == RESULT_OK) { if (data != null) { Uri treeUri = data.getData(); // 持久化权限,避免应用重启后失效 getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); // 通过DocumentFile遍历目录下的所有文件 DocumentFile root = DocumentFile.fromTreeUri(this, treeUri); if (root != null) { for (DocumentFile file : root.listFiles()) { Util.LogError(file.getUri().toString()); } } } } }
这种方式完全符合Android 11及以上的存储规范,不会有上架审核的问题,是官方推荐的做法。
方案3:仅针对媒体文件(如果你的应用只需要处理媒体文件)
如果你的应用不需要访问非媒体文件,那保持原来的READ_EXTERNAL_STORAGE权限即可,不需要额外修改代码。
补充说明
你的原始代码在API 30+下只能拿到媒体文件,核心原因就是权限范围被系统限制了,根据你的业务场景选择上面的方案就能解决问题啦。
内容的提问来源于stack exchange,提问作者UltraVoltage
相关产品推荐
相关产品推荐

