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

Android 10+下无需MANAGE_EXTERNAL_STORAGE创建DCIM/Download空子目录求示例

解决方案:Android 10+ 分区存储下创建DCIM/Download子目录

一、利用MediaStore间接创建空子目录

MediaStore本身没有直接创建空目录的接口,因为分区存储中目录是随媒体文件自动生成的。可以通过创建临时媒体文件再删除的方式间接生成目录:

示例代码(Kotlin)

import android.content.ContentValues
import android.content.Context
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

suspend fun createEmptySubDirInDCIM(context: Context, subDirName: String): Boolean {
    return withContext(Dispatchers.IO) {
        val contentValues = ContentValues().apply {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                put(MediaStore.Images.Media.RELATIVE_PATH, "DCIM/$subDirName")
                put(MediaStore.Images.Media.DISPLAY_NAME, "temp_file.jpg")
                put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
            }
        }

        val uri = context.contentResolver.insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            contentValues
        ) ?: return@withContext false

        // 删除临时文件,保留目录
        context.contentResolver.delete(uri, null, null)
        return@withContext true
    }
}

说明

  • 针对Android 10+(API 29+),通过RELATIVE_PATH指定DCIM下的子目录,插入一个临时图片文件后立即删除,系统会保留创建的空目录。
  • targetSDK33下无需额外静态权限,系统自动授予媒体文件写入权限。
  • 修改RELATIVE_PATH为"Download/$subDirName"即可创建Download下的子目录。

二、SAF方式创建子目录(需用户手动授权)

如果需要直接通过SAF创建目录,需引导用户选择父目录(如DCIM或Download),再通过DocumentFile创建子目录:

示例代码(Kotlin)

1. 启动SAF选择父目录

import android.app.Activity
import android.content.Intent
import android.os.Build
import android.provider.DocumentsContract

const val REQUEST_CODE_PICK_PARENT_DIR = 1001

fun startSAFParentDirPicker(activity: Activity) {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // 默认定位到DCIM目录
            val dcimUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            putExtra(DocumentsContract.EXTRA_INITIAL_URI, dcimUri)
        }
    }
    activity.startActivityForResult(intent, REQUEST_CODE_PICK_PARENT_DIR)
}

2. 处理SAF返回结果并创建子目录

import android.content.ContentResolver
import android.net.Uri
import androidx.documentfile.provider.DocumentFile

fun createSubDirViaSAF(contentResolver: ContentResolver, parentUri: Uri, subDirName: String): Boolean {
    val parentDoc = DocumentFile.fromTreeUri(contentResolver, parentUri) ?: return false
    val subDir = parentDoc.createDirectory(subDirName)
    return subDir != null
}

// 在Activity的onActivityResult中处理
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_CODE_PICK_PARENT_DIR && resultCode == RESULT_OK) {
        data?.data?.let { parentUri ->
            // 保留长期访问权限
            contentResolver.takePersistableUriPermission(
                parentUri,
                Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
            )
            val success = createSubDirViaSAF(contentResolver, parentUri, "MyAppDir")
            // 根据success状态处理结果提示
        }
    }
}

说明

  • SAF需要用户手动确认父目录,但可通过EXTRA_INITIAL_URI默认定位到目标目录,减少操作步骤。
  • 调用takePersistableUriPermission可保留对目录的长期访问权限,避免重复授权。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:23:25