Flutter应用因MANAGE_EXTERNAL_STORAGE权限遭谷歌拒审,需改用MediaStore API
解决方案:移除MANAGE_EXTERNAL_STORAGE权限并改用MediaStore API
1. 先移除违规权限
打开Flutter项目下的android/app/src/main/AndroidManifest.xml,删除这一行代码:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
同时确保文件中没有其他和该权限相关的配置。
2. 替换媒体文件操作逻辑(Flutter端实现)
根据功能场景,用对应插件或自定义平台通道实现MediaStore操作:
场景1:保存图片/视频到公共相册
推荐使用image_gallery_saver插件(内部已封装MediaStore逻辑):
- 添加依赖到
pubspec.yaml:dependencies: image_gallery_saver: ^2.0.3 - 调用保存方法的示例代码:
import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'dart:typed_data'; import 'package:http/http.dart' as http; // 保存网络图片到相册 Future<void> saveNetworkImage() async { final response = await http.get(Uri.parse("https://example.com/image.jpg")); final result = await ImageGallerySaver.saveImage( response.bodyBytes, name: "my_image", ); print(result); } // 保存本地图片文件到相册 Future<void> saveLocalImage(String filePath) async { final result = await ImageGallerySaver.saveFile(filePath); print(result); }
场景2:读取公共存储的媒体文件
使用media_store插件访问MediaStore中的媒体:
- 添加依赖到
pubspec.yaml:dependencies: media_store: ^1.0.0 - 读取图片的示例代码:
import 'package:media_store/media_store.dart'; Future<void> loadImages() async { // 申请读取权限(Android 13+需申请READ_MEDIA_IMAGES) await MediaStore.requestPermission(PermissionType.read); // 获取所有图片 final images = await MediaStore.getImages(); for (var image in images) { print("图片路径:${image.path},名称:${image.displayName}"); } }
注意:Android 13及以上版本,需在AndroidManifest.xml中添加对应细分权限:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
Android 12及以下版本,添加READ_EXTERNAL_STORAGE权限即可:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
场景3:批量删除/修改媒体文件
如果需要批量操作,可通过Flutter平台通道调用Android原生代码直接操作MediaStore:
- Flutter端代码:
import 'package:flutter/services.dart'; class MediaStoreHelper { static const MethodChannel _channel = MethodChannel('media_store_helper'); static Future<bool> deleteMedia(String mediaId) async { final bool result = await _channel.invokeMethod('deleteMedia', {'mediaId': mediaId}); return result; } } - Android端原生代码(在MainActivity中):
import android.content.ContentResolver import android.content.ContentUris import android.net.Uri import android.provider.MediaStore import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel class MainActivity : FlutterActivity() { private val CHANNEL = "media_store_helper" override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> if (call.method == "deleteMedia") { val mediaId = call.argument<String>("mediaId") mediaId?.let { val deleted = deleteMediaFromStore(contentResolver, it) result.success(deleted) } ?: result.error("INVALID_ARG", "Media ID is null", null) } else { result.notImplemented() } } } private fun deleteMediaFromStore(resolver: ContentResolver, mediaId: String): Boolean { val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediaId.toLong()) val rowsDeleted = resolver.delete(uri, null, null) return rowsDeleted > 0 } }
3. 测试与审核准备
- 测试不同Android版本(API 29+)的功能兼容性,确保所有文件操作都通过MediaStore完成,无直接访问根目录或非媒体目录的行为。
- 提交审核时,在审核说明中明确说明:已移除
MANAGE_EXTERNAL_STORAGE权限,所有媒体操作均使用MediaStore API实现,符合Google Play的存储政策。
内容的提问来源于stack exchange,提问作者Harjinder Bains
相关产品推荐
相关产品推荐

