Android 11及以上版本中listFiles()方法无法显示部分扩展名文件的解决方法咨询
解决Android 11+下
listFiles()无法识别非媒体文件的问题 这个问题的核心原因是Android 11及以上版本强制启用了Scoped Storage(分区存储),它限制了应用对公共媒体目录(比如DCIM、Pictures)的访问范围——默认情况下,应用只能访问属于"媒体类型"的文件(图片、音频、视频),像.bin、.txt这类非媒体格式的文件不在默认允许的访问列表里,所以folder.listFiles()会自动过滤掉它们。而Android 10及以下版本可以通过requestLegacyExternalStorage=true绕过这个限制,因此之前功能正常。
下面是几种可行的解决方案,按Google推荐优先级排序:
方案1:使用Storage Access Framework(SAF)让用户授权访问目录
这是最符合Scoped Storage规范的做法,通过让用户手动选择目标目录,应用就能获得该目录下所有文件的完整访问权限。
实现步骤:
- 注册目录选择的Activity结果回调(适配新版API):
// 在Activity或Fragment中实现 private val openDocumentTreeLauncher = registerForActivityResult( ActivityResultContracts.OpenDocumentTree() ) { treeUri: Uri? -> treeUri?.let { // 持久化Uri权限,避免应用重启后丢失访问权 requireContext().contentResolver.takePersistableUriPermission( it, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) // 用DocumentFile遍历目录下的所有文件 val targetDir = DocumentFile.fromTreeUri(requireContext(), it) targetDir?.listFiles()?.forEach { documentFile -> Log.d("FileList", "文件名:${documentFile.name},类型:${documentFile.type}") } } }
- 触发目录选择弹窗(比如点击按钮时调用):
openDocumentTreeLauncher.launch(null)
优势:
- 完全符合Google的存储规范,无Play商店审核风险
- 用户对文件访问权限有完全控制权
- 支持访问任意目录下的所有类型文件
方案2:将文件存储到应用专属外部目录
如果这些非媒体文件是你的应用自己生成的、不需要被其他应用访问,那么可以把它们放到应用专属的外部存储目录。这个目录无需任何权限,应用可以自由读写所有类型的文件。
获取专属目录的代码:
// 获取应用专属外部存储目录,卸载应用时该目录会被自动删除 val appSpecificDir = context.getExternalFilesDir(null) // 在专属目录下创建你的子文件夹 val myFolder = File(appSpecificDir, "MyFolder") if (!myFolder.exists()) { myFolder.mkdirs() } // 此时调用listFiles()可以正常获取所有类型文件 val files = myFolder.listFiles()
优势:
- 无需申请任何权限,实现简单
- 完全避开Scoped Storage的各种限制
劣势:
- 文件会随应用卸载而被删除
- 其他应用无法直接访问这些文件
方案3:申请MANAGE_EXTERNAL_STORAGE权限(不推荐普通应用使用)
这个权限可以让应用获得外部存储的完全访问权,但Google对它的审核极为严格,只有文件管理器、备份工具这类"核心文件管理类"应用才能通过审核。
实现步骤:
- 在
AndroidManifest.xml中声明权限:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
- 动态请求权限并跳转系统设置页面:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (!Environment.isExternalStorageManager()) { val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) intent.data = Uri.parse("package:${context.packageName}") startActivity(intent) } else { // 权限已授予,此时listFiles()可正常访问所有文件 val myFolder = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "MyFolder") val files = myFolder.listFiles() } }
注意:
- 普通应用使用该权限大概率会被Google Play拒绝上架
- 仅在你的应用确实是文件管理器类工具时考虑使用
内容的提问来源于stack exchange,提问作者Yevgen
相关产品推荐
相关产品推荐

