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
相关产品推荐
相关产品推荐

