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

