Android 11用File类访问下载目录仅显示子目录,如何获取文件?
Android 11下读取Download目录所有文件的可行方案
问题根源
Android 11(API 30)启用分区存储后,公共Download目录的File类访问权限被严格限制:默认仅允许APP读取自身创建的文件,以及系统预留的特定子目录(如你看到的downloaded_rom、Filemail等),其他用户或第三方APP放置的文件无法通过File直接读取。
可行解决办法
1. 使用MANAGE_EXTERNAL_STORAGE权限(需注意合规性)
该权限允许APP访问所有共享存储文件,但Google Play仅对特定类型APP(如文件管理器、系统工具类)开放审核,普通APP使用可能无法通过上架审核。
步骤1:配置Manifest权限
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" /> <!-- 兼容Android 10及以下版本 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="29" />步骤2:代码中申请权限
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:$packageName") startActivity(intent) } else { // 有权限后,即可正常读取Download目录所有内容 val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) downloadsDir.listFiles()?.forEach { file -> // 处理文件或目录 Log.d("DownloadContent", file.name) } } }
2. 重新评估MediaStore的适用性
你提到MediaStore不适用,但如果仅需读取文件内容、获取文件信息(而非直接操作File对象),MediaStore是符合分区存储规范的合法方案,且无需用户手动选择目录:
val projection = arrayOf( MediaStore.Downloads._ID, MediaStore.Downloads.DISPLAY_NAME, MediaStore.Downloads.RELATIVE_PATH ) // 筛选Download目录下的文件 val selection = "${MediaStore.Downloads.RELATIVE_PATH} LIKE ?" val selectionArgs = arrayOf("%Download/%") contentResolver.query( MediaStore.Downloads.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null )?.use { cursor -> while (cursor.moveToNext()) { val fileName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Downloads.DISPLAY_NAME)) val filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Downloads.RELATIVE_PATH)) // 读取文件内容 val fileUri = ContentUris.withAppendedId( MediaStore.Downloads.EXTERNAL_CONTENT_URI, cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID)) ) contentResolver.openInputStream(fileUri)?.use { inputStream -> // 处理文件流 } } }
3. 仅访问APP专属Download目录(限自身创建的文件)
如果你的需求仅涉及读取自身APP下载的文件,可使用APP专属存储目录,无需额外权限:
val appDownloadDir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) appDownloadDir?.listFiles()?.forEach { file -> // 处理APP自身创建的文件 }
内容的提问来源于stack exchange,提问作者MercifulSory
相关产品推荐
相关产品推荐

