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

API 31+下图片保存失败及相机调用异常问题求助

API 31+ 图片保存与相机问题解决方案

一、图片保存失败问题(含分享场景)

核心原因

API 31+ 收紧了外部存储权限管控:

  • Environment.getExternalStorageDirectory() 属于共享存储区域,直接通过File类写入会触发权限异常,需改用MediaStore API操作
  • getExternalFilesDir(null) 是应用私有外部存储,无需权限但文件仅当前应用可见,且原代码仅传入目录未指定具体文件名,导致写入逻辑失效

解决步骤

1. 保存到应用私有目录(仅应用内使用)

修正buttonSaveImageClicked的路径传递逻辑,并确保SaveLayoutToFile内部正确写入文件:

public void buttonSaveImageClicked(View view) throws IOException {
    editorImage.setDrawingCacheEnabled(true);
    Bitmap bitmap = editorImage.getDrawingCache();
    SaveLayoutToFile saveImage = new SaveLayoutToFile(this, bitmap, editorImage);
    // 拼接完整文件名,而非仅目录
    String filePath = new File(getExternalFilesDir(null), "spooky.png").getAbsolutePath();
    saveImage.execute(filePath);
}

// 示例SaveLayoutToFile的核心写入逻辑
@Override
protected Boolean doInBackground(String... params) {
    String fullPath = params[0];
    try (FileOutputStream fos = new FileOutputStream(fullPath)) {
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
        return true;
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
}

2. 保存到共享存储(DCIM目录,支持分享)

改用MediaStore API写入共享存储,无需直接操作File:

public File saveFileToShare() {
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.DISPLAY_NAME, "attachment.png");
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
    values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/Camera");

    Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    if (uri == null) return null;

    try (OutputStream outputStream = getContentResolver().openOutputStream(uri)) {
        editorImage.setDrawingCacheEnabled(true);
        Bitmap bitmap = editorImage.getDrawingCache();
        boolean saveSuccess = bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
        editorImage.setDrawingCacheEnabled(false);

        if (saveSuccess) {
            // 可选:获取实际文件路径(分享时直接用Uri更安全)
            String[] projection = {MediaStore.Images.Media.DATA};
            try (Cursor cursor = getContentResolver().query(uri, projection, null, null, null)) {
                if (cursor != null && cursor.moveToFirst()) {
                    String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
                    return new File(path);
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

权限配置:在AndroidManifest.xml中添加适配权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" />

同时需在代码中动态申请对应权限(API 23+)。

二、相机无法打开问题

核心原因

  • API 31+ 无法直接在Environment.getExternalStorageDirectory()路径创建文件
  • 缺少相机权限,且FileProvider配置可能存在错误
  • 未授予相机应用写入临时文件的权限

解决步骤

1. 修正拍照逻辑,改用应用私有存储存临时文件

public void cameraClicked(View view) {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // 先检查是否有可用相机应用
    if (takePictureIntent.resolveActivity(getPackageManager()) == null) {
        return;
    }

    // 用应用私有外部存储存放临时照片
    File tempDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    if (!tempDir.exists()) tempDir.mkdirs();
    File tempFile = new File(tempDir, "photoTemp.png");

    try {
        if (tempFile.exists()) tempFile.delete();
        tempFile.createNewFile();

        Uri uri = FileProvider.getUriForFile(
                this,
                getPackageName() + ".provider",
                tempFile);
        // 必须授予相机应用写入权限
        takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        startActivityForResult(takePictureIntent, 2);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2. 检查FileProvider配置

在AndroidManifest.xml中确保已注册FileProvider:

<application>
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
</application>

在res/xml目录下创建file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="external_files" path="." />
</paths>

3. 添加相机权限

在AndroidManifest.xml中添加:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />

并在代码中动态申请相机权限(API 23+)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:53:12