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

Android外部存储写入权限被拒求助:已授权仍无法写入

Hey there! Let's figure out why you're running into "Permission denied" errors when writing to external storage (including mounted SD cards) in your FileManager app, even after granting write permissions. This is a super common issue thanks to Android's storage access changes starting from Android 10 (API 29), so let's break down the fixes step by step.

Understanding the Root Cause

Android introduced Scoped Storage in API 29 to restrict direct, unrestricted access to external storage. Even if you've declared WRITE_EXTERNAL_STORAGE in your manifest and requested it dynamically, this permission no longer grants full write access to arbitrary external storage directories. For mounted SD cards, the restrictions are even tighter—you can't write to most directories without explicit user approval.

Fixes for Different Scenarios

1. Writing Media Files (Photos, Videos, Audio) to External Storage

If you're dealing with media files, use the MediaStore API instead of direct file paths. This adheres to scoped storage rules and works without extra permissions on API 30+. Here's a quick Kotlin example to copy a file to the external DCIM directory:

fun copyFileToDCIM(context: Context, sourceFile: File) {
    val contentValues = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, sourceFile.name)
        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") // Adjust MIME type for your file type
        put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
    }

    val resolver = context.contentResolver
    val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
        ?: return // Exit if URI creation fails

    resolver.openOutputStream(uri)?.use { outputStream ->
        sourceFile.inputStream().use { inputStream ->
            inputStream.copyTo(outputStream)
        }
    }
}

2. Writing Non-Media Files to External Storage

For non-media files (like documents, zips, or custom file types), you have two reliable options:

This approach follows Android's security guidelines by letting users explicitly choose the directory they want your app to write to. It works for both internal external storage and mounted SD cards.

First, launch the directory picker:

fun launchDirectoryPicker(activity: Activity, requestCode: Int) {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
    activity.startActivityForResult(intent, requestCode)
}

Then handle the selection result (use registerForActivityResult for newer Android versions if you're using Jetpack):

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_OK && data != null) {
        val treeUri = data.data ?: return
        // Persist access so you can use this URI later without re-prompting
        contentResolver.takePersistableUriPermission(
            treeUri,
            Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
        )
        // Example: Write a test file to the selected directory
        writeFileToSelectedDirectory(treeUri, "my_file.txt", "Hello from FileManager!")
    }
}

fun writeFileToSelectedDirectory(treeUri: Uri, fileName: String, content: String) {
    val documentUri = DocumentsContract.buildDocumentUriUsingTree(
        treeUri,
        DocumentsContract.getTreeDocumentId(treeUri)
    )
    val fileUri = DocumentsContract.createDocument(
        contentResolver,
        documentUri,
        "text/plain", // Adjust MIME type
        fileName
    ) ?: return

    contentResolver.openOutputStream(fileUri)?.use {
        it.write(content.toByteArray())
    }
}

Option B: Use MANAGE_EXTERNAL_STORAGE Permission (For File Managers)

If your app is a dedicated file manager (which it is), you can request the MANAGE_EXTERNAL_STORAGE permission to get full access to all storage locations. Note that Google Play requires apps to justify using this permission, so only use it if it's critical to your core functionality.

First, add the permission to your manifest:

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
    android:minSdkVersion="30" />

Then check and request the permission:

fun hasManageExternalStoragePermission(context: Context): Boolean {
    return Environment.isExternalStorageManager()
}

fun requestManageExternalStoragePermission(activity: Activity, requestCode: Int) {
    val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
    val uri = Uri.fromParts("package", activity.packageName, null)
    intent.data = uri
    activity.startActivityForResult(intent, requestCode)
}

Once granted, you can use direct file paths to write to any external storage location, including mounted SD cards.

3. Handling Mounted External Storage (SD Cards)

For SD cards, even with MANAGE_EXTERNAL_STORAGE, some devices might have manufacturer-specific restrictions. If you don't want to rely on that permission, SAF is the only reliable method—users need to select the SD card root or target directory via the picker, and you can write to it using the URI as shown in Option A.

Key Notes to Remember
  • Legacy Storage (Temporary Fix): On Android 10 (API 29), you can add android:requestLegacyExternalStorage="true" to your <application> tag in the manifest to bypass scoped storage temporarily. This won't work on Android 12+, so it's only a short-term solution.
  • Dynamic Permissions: Always request runtime permissions for WRITE_EXTERNAL_STORAGE (API 28 and below) or MANAGE_EXTERNAL_STORAGE (API 30+).
  • Google Play Policy: Apps using MANAGE_EXTERNAL_STORAGE must pass a policy review, so make sure your app's core functionality truly requires full storage access.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:32:06