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

Android 13中WRITE_EXTERNAL_STORAGE失效,如何保存图片至存储?

Android 13 下保存图片到存储的解决方案

Android 13(API 33)开始,WRITE_EXTERNAL_STORAGE权限已被废弃,这就是你声明该权限后仍无法正常工作的原因。以下是两种可行的实现方案:

一、保存到公共媒体目录(相册可见)

1. 权限配置

在AndroidManifest.xml中声明兼容权限:

<!-- 仅针对Android 12及以下版本生效 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- Android 13+ 读取图片时需声明,写入无需此权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

Android 13+ 写入公共媒体目录无需申请WRITE_EXTERNAL_STORAGE,直接通过MediaStore API操作即可。

2. Kotlin代码实现

fun saveImageToPublicGallery(bitmap: Bitmap, context: Context): Uri? {
    val fileName = "IMG_${System.currentTimeMillis()}.png"
    val contentValues = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
        put(MediaStore.Images.Media.MIME_TYPE, "image/png")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // 指定保存到Pictures下的自定义子目录
            put(MediaStore.Images.Media.RELATIVE_PATH, "${Environment.DIRECTORY_PICTURES}/MyApp")
        } else {
            // 兼容Android 9及以下,需先创建目录
            val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).resolve("MyApp")
            if (!dir.exists()) dir.mkdirs()
            put(MediaStore.Images.Media.DATA, dir.resolve(fileName).absolutePath)
        }
    }

    return context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)?.also { uri ->
        context.contentResolver.openOutputStream(uri)?.use { outputStream ->
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
        }
    }
}

3. Java代码实现

public Uri saveImageToPublicGallery(Bitmap bitmap, Context context) {
    String fileName = "IMG_" + System.currentTimeMillis() + ".png";
    ContentValues contentValues = new ContentValues();
    contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
    contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/png");

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyApp");
    } else {
        File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        contentValues.put(MediaStore.Images.Media.DATA, new File(dir, fileName).getAbsolutePath());
    }

    Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
    if (uri != null) {
        try (OutputStream outputStream = context.getContentResolver().openOutputStream(uri)) {
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    return uri;
}

二、保存到应用私有存储(无需权限,仅应用可访问)

如果不需要图片在系统相册中显示,可保存到应用私有目录,无需申请任何存储权限:

Kotlin实现

fun saveImageToPrivateStorage(bitmap: Bitmap, context: Context): Boolean {
    val dir = File(context.filesDir, "AppImages")
    if (!dir.exists()) dir.mkdirs()
    val imageFile = File(dir, "IMG_${System.currentTimeMillis()}.png")
    return try {
        FileOutputStream(imageFile).use { outputStream ->
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
        }
        true
    } catch (e: IOException) {
        e.printStackTrace()
        false
    }
}

Java实现

public boolean saveImageToPrivateStorage(Bitmap bitmap, Context context) {
    File dir = new File(context.getFilesDir(), "AppImages");
    if (!dir.exists()) {
        dir.mkdirs();
    }
    File imageFile = new File(dir, "IMG_" + System.currentTimeMillis() + ".png");
    try {
        FileOutputStream outputStream = new FileOutputStream(imageFile);
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
        outputStream.close();
        return true;
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
}

额外提示

  • 保存到公共目录后,若需立即让相册刷新显示,可调用媒体扫描:
MediaScannerConnection.scanFile(context, arrayOf(uri?.path), arrayOf("image/png"), null)
  • Android 12及以下版本,需动态申请WRITE_EXTERNAL_STORAGE权限后再执行保存操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:35:54