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

Android 13下如何彻底移除WRITE_EXTERNAL_STORAGE权限?

Android 13 存储权限适配方案

Android 13将原存储权限拆分为三个细分权限,不再需要WRITE_EXTERNAL_STORAGE,适配方式如下:

1. 替换Manifest权限声明

根据应用需求添加对应细分权限:

  • 读取图片:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
  • 读取视频:
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
  • 读取音频:
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

针对Android 13以下版本,保留旧权限并限制最高适用版本:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="32" />

2. 动态申请权限

代码中区分Android版本,申请对应权限:

private const val REQUEST_CODE_MEDIA = 1001
private const val REQUEST_CODE_STORAGE = 1002

fun checkAndRequestStoragePermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        // Android 13及以上,申请媒体细分权限
        val neededPermissions = mutableListOf<String>()
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
            neededPermissions.add(Manifest.permission.READ_MEDIA_IMAGES)
        }
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_VIDEO) != PackageManager.PERMISSION_GRANTED) {
            neededPermissions.add(Manifest.permission.READ_MEDIA_VIDEO)
        }
        if (neededPermissions.isNotEmpty()) {
            requestPermissions(neededPermissions.toTypedArray(), REQUEST_CODE_MEDIA)
        }
    } else {
        // Android 13以下,申请READ_EXTERNAL_STORAGE
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_CODE_STORAGE)
        }
    }
}

3. 适配文件读写逻辑

Android 13推荐使用MediaStore或SAF(存储访问框架)操作公共目录文件,避免直接读写外部存储路径。例如保存图片到公共图片目录:

fun saveImageToPublicGallery(bitmap: Bitmap) {
    val contentValues = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, "app_image_${System.currentTimeMillis()}.jpg")
        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
        }
    }

    contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)?.let { uri ->
        contentResolver.openOutputStream(uri).use { outputStream ->
            bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 06:55:37