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

Android运行时权限异常:请求WRITE_EXTERNAL_STORAGE后应用设置无显示

问题分析与解决方案

核心原因

你的targetSdk设置为34(Android 14),而WRITE_EXTERNAL_STORAGE权限在Android 10(API29)开始就被逐步废弃,在Android 13(API33)及以上系统中,该权限不再被视为运行时权限——系统会直接忽略对它的申请请求,所以应用设置页面不会显示这个权限项。

同时,直接使用File类操作公共下载目录的方式,在Android 10+的分区存储机制下会受到限制,这也是你遇到「找不到该文件名」异常的根本原因。

解决方案

1. 移除无效的权限申请代码

删掉所有针对WRITE_EXTERNAL_STORAGE的运行时申请逻辑(包括requestRuntimePermissions方法和onRequestPermissionsResult的相关处理),这些代码在高版本系统中完全无效。

2. 调整Manifest权限声明

如果你的应用需要兼容Android 9(API28)及以下版本,可以给权限声明加上maxSdkVersion,避免高版本系统处理该权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="29" />

如果只需要兼容Android 10+,可以直接移除这个权限声明。

3. 使用MediaStore保存图片到下载文件夹

Android 10+推荐使用MediaStore API向公共下载目录写入文件,无需申请任何存储权限。以下是示例代码:

import android.content.ContentValues
import android.graphics.Bitmap
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.widget.Toast
import java.io.IOException

private fun saveProcessedImageToDownloads(bitmap: Bitmap) {
    // 生成唯一文件名
    val fileName = "removed_bg_${System.currentTimeMillis()}.png"
    val contentValues = ContentValues().apply {
        put(MediaStore.Downloads.DISPLAY_NAME, fileName)
        put(MediaStore.Downloads.MIME_TYPE, "image/png")
        // 指定保存到下载文件夹
        put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // 标记文件为待完成,避免系统提前扫描
            put(MediaStore.Downloads.IS_PENDING, 1)
        }
    }

    contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)?.let { uri ->
        try {
            contentResolver.openOutputStream(uri)?.use { outputStream ->
                // 压缩并写入图片
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                // 标记文件完成,系统会正常扫描到该文件
                contentValues.put(MediaStore.Downloads.IS_PENDING, 0)
                contentResolver.update(uri, contentValues, null, null)
            }
            Toast.makeText(this, "图片已保存到下载文件夹", Toast.LENGTH_SHORT).show()
        } catch (e: IOException) {
            e.printStackTrace()
            Toast.makeText(this, "保存失败:${e.message}", Toast.LENGTH_SHORT).show()
        }
    } ?: run {
        Toast.makeText(this, "无法创建文件", Toast.LENGTH_SHORT).show()
    }
}

4. 兼容Android 9及以下版本(可选)

如果需要兼容API28及以下系统,只需在保存文件前检查WRITE_EXTERNAL_STORAGE权限是否授予,授予后使用传统File方式保存即可,但这部分逻辑仅在低版本系统中触发。

验证

运行修改后的代码,处理完图片后调用saveProcessedImageToDownloads方法,图片会直接保存到系统下载文件夹,无需申请权限,也不会再出现「找不到文件名」的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 00:38:21