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

Android截图保存遇EPERM(Operation not permitted)权限错误求助

Android 截图保存报错 EPERM (Operation not permitted) 解决方案

问题描述

实现截图功能时,已申请READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE、MANAGE_EXTERNAL_STORAGE权限,但保存图片时仍报错open failed: EPERM (Operation not permitted),错误触发在fOut = new FileOutputStream(file);代码行。

相关代码及日志

截图实现代码

public void tackeAndSaveScreenShot(Activity mActivity) {
        View MainView = mActivity.getWindow().getDecorView();
        MainView.setDrawingCacheEnabled(true);
        MainView.buildDrawingCache();
        Bitmap MainBitmap = MainView.getDrawingCache();
        Rect frame = new Rect();

        mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        // 移除截图中的状态栏
        int statusBarHeight = frame.top;
        // 获取屏幕尺寸创建Bitmap
        int width = mActivity.getWindowManager().getDefaultDisplay().getWidth();
        int height = mActivity.getWindowManager().getDefaultDisplay().getHeight();
        Bitmap OutBitmap = Bitmap.createBitmap(MainBitmap, 0, statusBarHeight, width, height - statusBarHeight);
        MainView.destroyDrawingCache();
        try {

            String path = Environment.getExternalStorageDirectory().toString();
            OutputStream fOut = null;
            // 也可以用当前时间生成文件名
            String name="YourName";
            File file = new File(path, name + ".png");
            fOut = new FileOutputStream(file);

            OutBitmap.compress(Bitmap.CompressFormat.PNG, 1000, fOut);
            fOut.flush();
            fOut.close();

            // 将保存的图片添加到图库
            MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

权限申请代码

private void userPermission2(){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.MANAGE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE},REQUEST_CODE1);
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE && grantResults.length > 0
        && grantResults[0] == PackageManager.PERMISSION_GRANTED){
            Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
            userPermission2();
        }else {
            Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();

        }

    }

Logcat日志

D/CompatibilityChangeReporter: Compat change id reported: 147798919; UID 10351; state: ENABLED
W/System.err: java.io.FileNotFoundException: /storage/emulated/0/YourName.png: open failed: EPERM (Operation not permitted)
W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:492)
W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:236)
W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:186)
W/System.err:     at com.example.myapplication.MainActivity.tackeAndSaveScreenShot(MainActivity.java:93)
W/System.err:     at com.example.myapplication.MainActivity$1.onClick(MainActivity.java:64)
W/System.err:     at android.view.View.performClick(View.java:7570)
W/System.err:     at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1202)
W/System.err:     at android.view.View.performClickInternal(View.java:7525)
W/System.err:     at android.view.View.access$3900(View.java:836)
W/System.err:     at android.view.View$PerformClick.run(View.java:28680)
W/System.err:     at android.os.Handler.handleCallback(Handler.java:938)
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:99)
W/System.err:     at android.os.Looper.loop(Looper.java:254)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:8243)
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612)
W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)
W/System.err: Caused by: android.system.ErrnoException: open failed: EPERM (Operation not permitted)
W/System.err:     at libcore.io.Linux.open(Native Method)
W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254)
W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
W/System.err:     at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:8125)
W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:478)
W/System.err:   ... 16 more

问题原因及解决办法

1. 权限申请逻辑错误

  • MANAGE_EXTERNAL_STORAGE是系统特殊权限,无法通过requestPermissions()申请,必须跳转系统设置页面让用户手动开启:
    private void checkManageStoragePermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (!Environment.isExternalStorageManager()) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                Uri uri = Uri.fromParts("package", getPackageName(), null);
                intent.setData(uri);
                startActivity(intent);
            }
        }
    }
    
  • 权限回调中的REQUEST_CODE与申请时的REQUEST_CODE1不匹配,导致权限判断逻辑失效,统一两者的常量值即可。

2. Android 10+ 分区存储限制

从Android 10(API 29)开始,系统启用分区存储机制,禁止直接写入外部存储根目录,推荐两种修改方案:

方案一:使用应用私有外部存储目录

无需额外权限(WRITE_EXTERNAL_STORAGE在API 30+已废弃),文件会随应用卸载自动删除:

// 替换原路径获取代码
File path = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File file = new File(path, name + ".png");

方案二:通过MediaStore保存到公共图库

无需申请WRITE_EXTERNAL_STORAGE(API 29+),直接将图片插入系统媒体库:

// 替换原保存逻辑
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, name + ".png");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Screenshots");
}

Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (uri != null) {
    OutputStream fOut = getContentResolver().openOutputStream(uri);
    OutBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
    fOut.flush();
    fOut.close();
}

3. 其他注意点

  • Bitmap.compress()的质量参数范围是0-100,代码中写的1000会被系统自动修正为100,建议改为合法值。
  • 确保调用截图方法前,所有必要权限已被授予。

内容的提问来源于stack exchange,提问作者Rumaion Tomal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 21:11:07