You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 00:17:05