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

Android 6及以上系统截图保存至相册功能失效问题求助

解决Android 6+截图保存相册失效的问题

嘿,这个问题我之前也碰到过!核心原因是Android 6.0(API 23)引入了运行时权限机制,存储权限属于「危险权限」,必须在运行时主动向用户申请;另外Android 10(API 29)开始的分区存储政策也会影响文件保存逻辑,咱们一步步来修复:

一、先明确核心问题

在Android 5及以下,只要在AndroidManifest.xml里声明权限就能直接使用;但Android 6+要求危险权限必须动态申请,用户同意后才能访问存储。你的代码里应该缺少了权限申请的逻辑,导致保存文件时被系统拦截。

二、具体修复步骤

1. 在Manifest中声明必要权限

先确保AndroidManifest.xml里有这些权限(兼顾新旧版本兼容):

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Android 13+ 需单独申请媒体权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" />

2. 动态申请存储权限

在你的Activity中,先判断权限状态,未授权则主动申请:

private static final int REQUEST_STORAGE_PERMISSION = 100;
private ImageView imgSS;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.tes_screenshot);
    imgSS = findViewById(R.id.imgSS); // 替换为你的ImageView实际ID
    
    // 检查存储权限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        // 未授权,发起权限申请
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_STORAGE_PERMISSION);
    } else {
        // 已授权,直接执行截图逻辑
        takeScreenshotAndSave();
    }
}

// 处理权限申请结果回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_STORAGE_PERMISSION) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            takeScreenshotAndSave();
        } else {
            Toast.makeText(this, "需要存储权限才能保存截图", Toast.LENGTH_SHORT).show();
        }
    }
}

3. 适配截图与保存逻辑(兼容Android 10+)

Android 10开始推荐使用MediaStore保存媒体文件,替代直接操作外部存储路径,适配分区存储政策:

private void takeScreenshotAndSave() {
    // 获取当前Activity的根View
    View view = getWindow().getDecorView().getRootView();
    view.setDrawingCacheEnabled(true);
    Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
    view.setDrawingCacheEnabled(false);

    // 显示截图到ImageView
    imgSS.setImageBitmap(bitmap);

    // 保存到相册
    saveBitmapToGallery(bitmap);
    
    // 回收Bitmap避免内存泄漏
    if (bitmap != null && !bitmap.isRecycled()) {
        bitmap.recycle();
    }
}

private void saveBitmapToGallery(Bitmap bitmap) {
    String displayName = "Screenshot_" + System.currentTimeMillis() + ".png";
    String mimeType = "image/png";
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.DISPLAY_NAME, displayName);
    values.put(MediaStore.Images.Media.MIME_TYPE, mimeType);
    
    // 适配Android 10+的分区存储
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/Screenshots");
        values.put(MediaStore.Images.Media.IS_PENDING, 1);
    } else {
        // 低版本直接创建文件夹
        String savePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/Screenshots";
        File dir = new File(savePath);
        if (!dir.exists()) dir.mkdirs();
        values.put(MediaStore.Images.Media.DATA, new File(dir, displayName).getAbsolutePath());
    }

    ContentResolver resolver = getContentResolver();
    Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    if (uri != null) {
        try (OutputStream outputStream = resolver.openOutputStream(uri)) {
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
            
            // Android 10+ 标记文件为已完成
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                values.put(MediaStore.Images.Media.IS_PENDING, 0);
                resolver.update(uri, values, null, null);
            }
            
            // 通知相册刷新文件
            sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
            Toast.makeText(this, "截图已保存到相册", Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show();
            resolver.delete(uri, null, null); // 删除失败的记录
        }
    }
}

三、额外注意事项

  • 若仅针对Android 13+开发,可使用READ_MEDIA_IMAGES替代旧存储权限,更贴合新权限政策
  • 避免在onCreate直接调用截图逻辑(此时View可能未绘制完成),可通过postDelayed延迟执行
  • 始终记得回收Bitmap对象,防止内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:29:09