Flutter移除MANAGE_EXTERNAL_STORAGE权限并合规访问WhatsApp状态文件夹
具体修改方案
一、权限替换(移除违规权限,添加合规权限)
1. 修改AndroidManifest.xml
直接删除android.permission.MANAGE_EXTERNAL_STORAGE权限,替换为以下合规权限配置:
<!-- Android 10及以下版本的基础存储读取权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13+ 专属媒体读取权限 --> <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_VISUAL_USER_SELECTED" />
同时在<application>标签内添加适配Android 10的旧存储模型配置:
<application ... android:requestLegacyExternalStorage="true"> ... </application>
二、适配WhatsApp状态文件夹访问逻辑
WhatsApp状态文件夹WhatsApp/Media/.Statuses是隐藏目录,Android 10及以上无法直接通过文件路径访问,必须通过MediaStore API查询获取。
1. 修改数据获取Provider(替换原文件读取逻辑)
替换原直接读取目录的代码,改用MediaStore查询状态文件:
import 'dart:io'; import 'package:permission_handler/permission_handler.dart'; import 'package:flutter/services.dart'; import 'package:device_info_plus/device_info_plus.dart'; // 请求对应存储权限 Future<bool> requestRequiredPermissions() async { if (!Platform.isAndroid) return true; final androidInfo = await DeviceInfoPlugin().androidInfo; PermissionStatus status; if (androidInfo.version.sdkInt >= 33) { // Android 13+ 请求媒体权限 status = await Permission.photos.request(); } else if (androidInfo.version.sdkInt >= 30) { // Android 11/12 请求存储权限 status = await Permission.storage.request(); } else { // Android 10及以下 请求存储权限 status = await Permission.storage.request(); } return status.isGranted; } // 查询WhatsApp状态媒体文件 Future<List<File>> fetchWhatsAppStatuses() async { final List<File> statusFiles = []; if (!await requestRequiredPermissions()) return statusFiles; // 构造MediaStore查询条件,匹配WhatsApp状态目录 const selection = "${MediaStore.MediaColumns.RELATIVE_PATH} LIKE ?"; const selectionArgs = ["%WhatsApp/Media/.Statuses%"]; final cursor = await MediaStore.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection: [MediaStore.MediaColumns.DATA], selection: selection, selectionArgs: selectionArgs, ); if (cursor != null && cursor.moveToFirst()) { do { final filePath = cursor.getString( cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA) ); final file = File(filePath); if (await file.exists()) statusFiles.add(file); } while (cursor.moveToNext()); cursor.close(); } return statusFiles; }
2. UI展示适配
原UI逻辑无需大幅修改,只需在加载数据时调用新的查询方法,并确保先完成权限校验:
List<File> _statusList = []; void loadStatusContent() async { final statuses = await fetchWhatsAppStatuses(); setState(() => _statusList = statuses); } // 在initState或用户触发操作时调用loadStatusContent @override void initState() { super.initState(); loadStatusContent(); }
三、Google Play合规要点
- 严格限制访问范围:仅读取
WhatsApp/Media/.Statuses下的文件,禁止访问其他无关存储内容 - 明确权限用途:在应用内权限申请弹窗、隐私政策中,清晰说明权限用于读取和保存WhatsApp状态
- 最小权限原则:Android 13+仅申请必要的媒体权限,不要额外请求多余权限
内容的提问来源于stack exchange,提问作者Alpesh Kukadiya
相关产品推荐
相关产品推荐

