Android 12下Flutter native_screenshot路径为空且EPERM权限异常求助
Android系统级截图保存失败(EPERM操作不允许异常)
基础信息
- 构建目标:开发一款可后台定期截图的应用
- 当前场景:仅测试点击按钮截图功能,暂不涉及后台运行
- 需求说明:需实现Android系统级截图(非应用内截图)
- 核心问题:调用native_screenshot插件时返回路径为空,截图无法保存,抛出
EPERM (Operation not permitted)异常
版本信息
- Flutter: 3.7.8
- permission_handler: ^10.2.0
- native_screenshot: ^1.0.0
- minSdkVersion: 23
错误日志
I/NativeScreenshotPlugin(15682): Permission to write granted! I/NativeScreenshotPlugin(15682): Trying to take screenshot [old way] I/NativeScreenshotPlugin(15682): Built ScreeshotPath: /storage/emulated/0/native_screenshot-20230328162022.png I/NativeScreenshotPlugin(15682): Error writing bitmap: /storage/emulated/0/native_screenshot-20230328162022.png: open failed: EPERM (Operation not permitted) I/NativeScreenshotPlugin(15682): The bitmap cannot be written, invalid path. I/flutter (15682): Screenshot taken, path: null
AndroidManifest.xml配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.reelback"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <application android:label="reelback" android:name="${applicationName}" android:icon="@mipmap/ic_launcher" android:requestLegacyExternalStorage="true" android:preserveLegacyExternalStorage="true"> <activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" tools:ignore="Instantiatable"> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <meta-data android:name="flutterEmbedding" android:value="2" /> <service android:name="flutter.overlay.window.flutter_overlay_window.OverlayService" android:exported="false" tools:ignore="MissingClass" /> </application> </manifest>
使用的插件
import 'package:permission_handler/permission_handler.dart';import 'package:native_screenshot/native_screenshot.dart';
main.dart核心代码
FilledButton( onPressed: () async { await [Permission.storage].request(); String? path = await NativeScreenshot.takeScreenshot(); debugPrint('Screenshot taken, path: $path'); if( path == null || path.isEmpty ) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Error taking the screenshot :('), backgroundColor: Colors.red, ) ); return; } ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('The screenshot has been saved to: $path') ) ); }, child: Text('Screenshot Test'), ),
已尝试操作
替换为native_screenshot_ext插件后问题依旧。
解决方案
1. 修正权限请求逻辑
Android 10+的分区存储机制下,写入公共根目录需要MANAGE_EXTERNAL_STORAGE权限,该权限无法通过Permission.storage请求获取,需单独处理:
onPressed: () async { // 请求基础存储权限 await [Permission.storage].request(); // 检查并请求MANAGE_EXTERNAL_STORAGE权限 if (await Permission.manageExternalStorage.isDenied) { await Permission.manageExternalStorage.request(); // 如果用户拒绝,引导到系统设置开启 if (await Permission.manageExternalStorage.isPermanentlyDenied) { openAppSettings(); return; } } // 执行截图 String? path = await NativeScreenshot.takeScreenshot(); // 后续逻辑不变... }
2. 适配Android 13+权限
Android 13(API33)及以上版本,原WRITE_EXTERNAL_STORAGE权限被废弃,需添加细分媒体权限到AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
3. 改用应用私有存储路径(推荐)
如果不需要将截图暴露到公共目录,可修改插件保存路径到应用私有外部存储目录(无需额外权限):
- 查看
native_screenshot插件源码,找到截图保存路径的配置,替换为context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)对应的路径 - 或使用支持自定义保存路径的截图插件,避免依赖公共目录权限
4. 确认分区存储兼容配置
确保AndroidManifest.xml中的requestLegacyExternalStorage仅对Android 10(API29)生效,可添加tools:targetApi="q"限制:
android:requestLegacyExternalStorage="true" tools:targetApi="q"
内容的提问来源于stack exchange,提问作者lenzfliker
相关产品推荐
相关产品推荐

