Android API 30(Android 11)无法读取隐藏文件问题求助
Android 11(API 30)读取WhatsApp .Statuses隐藏目录失效解决方案
失效原因
Android 11 强制启用分区存储(Scoped Storage),Android 10上可使用的requestLegacyExternalStorage兼容标记在API 30及以上版本完全失效。普通应用即使申请了READ_EXTERNAL_STORAGE权限,也无法通过原生File API直接访问其他应用私有目录下的文件,你代码中读取的.Statuses属于WhatsApp私有目录下的隐藏文件夹,因此会出现listFiles()返回空的问题。
同时注意Android 13及以上版本中,WhatsApp的存储路径已迁移为/Android/media/com.whatsapp/WhatsApp/Media/.Statuses,原有根目录下的路径已废弃,需要适配新路径。
可行解决方案
方案1:申请所有文件访问权限(适合文件管理类应用)
该方案可直接沿用原有File API逻辑,但是属于Google Play限制的特殊权限,仅允许符合使用场景的应用上架。
- 在
AndroidManifest.xml中添加权限声明:
<!-- 基础存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 11及以上所有文件访问权限 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:maxSdkVersion="33" /> <!-- Android 13及以上媒体访问权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
- 运行时申请权限,普通存储权限通过后,跳转系统设置页引导用户开启「允许访问所有文件」权限:
private static final int REQUEST_MANAGE_STORAGE = 1001; // 权限判断逻辑 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (!Environment.isExternalStorageManager()) { Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION); startActivityForResult(intent, REQUEST_MANAGE_STORAGE); } else { // 权限已获取,执行原有文件读取逻辑 } } else { // 低于Android 11版本,原有逻辑直接运行 }
权限获取完成后,你原有代码即可正常读取.Statuses目录下的所有隐藏文件。
方案2:使用存储访问框架(SAF)授权(合规性更高,适合所有应用)
不需要申请特殊权限,不会被Google Play限制,仅需要用户首次使用时手动授权对应目录即可。
- 发起目录授权请求,引导用户选择
.Statuses目录:
private static final int REQUEST_SAF_PERMISSION = 1002; // 发起授权逻辑 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); // 可选:预先定位到.Statuses目录,减少用户操作步骤 Uri preUri = Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses"); intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, preUri); startActivityForResult(intent, REQUEST_SAF_PERMISSION);
- 用户授权后,在回调中获取目录访问权限并持久化,之后即可读取目录下的所有文件:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_SAF_PERMISSION && resultCode == RESULT_OK && data != null) { Uri treeUri = data.getData(); // 持久化授权,后续打开应用无需重复授权 getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // 遍历目录下的所有文件,包含隐藏文件 DocumentFile rootDir = DocumentFile.fromTreeUri(this, treeUri); DocumentFile[] allFiles = rootDir.listFiles(); // 后续处理allFiles即可 } }
内容的提问来源于stack exchange,提问作者Jaymin Bhadani
相关产品推荐
相关产品推荐

