如何使用MediaStore API访问Android 11中的WhatsApp文件夹
Android 11 下使用MediaStore访问外部存储实现方案
前置权限配置
在AndroidManifest.xml中添加对应权限:
<!-- 读取公共媒体文件权限,Android 13+可细化为图片/音频/视频单独权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- 写入公共媒体文件权限,Android 10+无需申请该权限即可写入自身创建的媒体文件 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
如果需要访问非媒体类公共文件,需要额外添加:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
该权限需要引导用户到系统设置页手动开启,且上架Google Play需要符合特殊应用场景要求。
读取公共媒体文件示例(Kotlin)
以读取外部存储所有图片文件为例:
val contentResolver = context.contentResolver // 要查询的文件信息列 val projection = arrayOf( MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.SIZE, MediaStore.Images.Media.DATE_ADDED ) // 筛选条件,这里查询所有图片 val selection = null val selectionArgs = null // 按添加时间倒序排序 val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC" contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, sortOrder )?.use { cursor -> val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME) while (cursor.moveToNext()) { val fileId = cursor.getLong(idColumn) val fileName = cursor.getString(nameColumn) // 构建文件访问Uri val fileUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, fileId) // 后续可通过该Uri打开输入流读取文件内容 // val inputStream = contentResolver.openInputStream(fileUri) } }
如果要访问其他类型的媒体,只需要替换对应的Uri即可:
- 视频:
MediaStore.Video.Media.EXTERNAL_CONTENT_URI - 音频:
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI - 下载文件:
MediaStore.Downloads.EXTERNAL_CONTENT_URI
写入公共目录文件示例(Kotlin)
以写入文件到公共下载目录为例:
val contentResolver = context.contentResolver val contentValues = ContentValues().apply { put(MediaStore.Downloads.DISPLAY_NAME, "test_file.txt") put(MediaStore.Downloads.MIME_TYPE, "text/plain") // Android 10+ 不需要指定路径,系统自动分配到对应公共目录 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { put(MediaStore.Downloads.DATA, "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/test_file.txt") } } // 插入文件记录获取Uri val fileUri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues) fileUri?.let { uri -> // 打开输出流写入内容 contentResolver.openOutputStream(uri)?.use { outputStream -> outputStream.write("测试内容".toByteArray()) } }
注意事项
- Android 11 分区存储规则下,MediaStore仅能访问公共媒体集合和自身应用专属目录,无法访问其他应用的专属目录文件
- 仅修改/删除其他应用创建的公共媒体文件时,需要额外申请读写权限,且操作时会触发用户授权弹窗
- 应用卸载重装后,之前创建的媒体文件会被标记为其他应用所有,需要重新申请权限才能修改
内容的提问来源于stack exchange,提问作者Yasir
相关产品推荐
相关产品推荐

