全文件访问权限合规问询:如何改用Media Store API替代MANAGE_EXTERNAL_STORAGE
解决MANAGE_EXTERNAL_STORAGE权限合规问题:改用Media Store API指南
一、移除违规权限声明
首先修改AndroidManifest.xml,删除以下权限声明:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
根据应用核心功能需求,保留必要的媒体权限:
- Android 13(API 33)及以上:按需添加
READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO - Android 10-12(API 29-32):添加
READ_EXTERNAL_STORAGE(读取媒体用),写入公共媒体目录无需WRITE_EXTERNAL_STORAGE - Android 9及以下:需添加
READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE
二、用Media Store API实现媒体文件读取
以读取图片为例,通过ContentResolver查询公共图片库:
fun loadImages(contentResolver: ContentResolver): List<MediaItem> { val projection = arrayOf( MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.DATE_ADDED ) val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC" val images = mutableListOf<MediaItem>() contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, sortOrder )?.use { cursor -> val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME) while (cursor.moveToNext()) { val id = cursor.getLong(idColumn) val name = cursor.getString(nameColumn) val contentUri = ContentUris.withAppendedId( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id ) images.add(MediaItem(id, name, contentUri)) } } return images } data class MediaItem(val id: Long, val name: String, val contentUri: Uri)
读取视频、音频只需替换对应的MediaStore路径(比如MediaStore.Video.Media.EXTERNAL_CONTENT_URI)。
三、用Media Store API实现媒体文件写入
以保存Bitmap到公共图片目录为例:
fun saveBitmapToGallery( contentResolver: ContentResolver, bitmap: Bitmap, fileName: String ): Uri? { val contentValues = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, fileName) put(MediaStore.Images.Media.MIME_TYPE, "image/png") // Android 10+支持指定相对路径,分类保存到应用专属子目录 put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/MyApp") put(MediaStore.Images.Media.IS_PENDING, 1) } val uri = contentResolver.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues ) ?: return null uri.let { contentResolver.openOutputStream(it)?.use { outputStream -> bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream) } // 标记文件为已完成,让系统媒体扫描器识别 contentValues.put(MediaStore.Images.Media.IS_PENDING, 0) contentResolver.update(it, contentValues, null, null) } return uri }
写入视频、音频的逻辑类似,替换MIME类型和MediaStore路径即可。
四、权限请求适配
- Android 13+:动态请求对应的媒体权限(比如
READ_MEDIA_IMAGES),用ActivityResultContracts.RequestPermission或RequestMultiplePermissions - Android 10-12:动态请求
READ_EXTERNAL_STORAGE权限 - Android 9及以下:动态请求
READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限
五、注意事项
- 避免直接访问文件路径(比如
Environment.getExternalStorageDirectory()),改用Content URI操作媒体文件 - 若需访问下载目录的非媒体文件,可使用
ACTION_OPEN_DOCUMENT让用户手动选择,而非申请全文件权限 - 测试时覆盖不同Android版本,确保所有媒体读写功能正常运行
内容的提问来源于stack exchange,提问作者VU Virtual Universe
相关产品推荐
相关产品推荐

