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

Android API29 二级外部存储(SD卡)调用mkdir()返回false问题排查

Android 10(API29)SD卡创建目录失败原因及解决方案

核心原因

  • 即使开启了android:requestLegacyExternalStorage="true",WRITE_EXTERNAL_STORAGE权限也仅能授权访问内置公共存储区域,无法授予外置SD卡任意路径的写入权限,这是Android分区存储机制的强制限制。
  • 你当前的代码通过多次调用parentFile跳转到SD卡根目录创建文件夹,该路径不属于应用专属存储范围,传统FileAPI无写入权限,因此mkdir()返回false。
  • ContextCompat.getExternalFilesDirs返回的第二个路径是SD卡上的应用专属存储目录,该路径下你拥有完整读写权限,不需要额外申请权限,但向上跳转父目录后就超出了权限范围。

解决方案

场景1:仅需在SD卡存储应用私有数据

直接在SD卡的应用专属目录下创建文件夹即可,不需要跳转到根目录:

val externalFiles = ContextCompat.getExternalFilesDirs(this, null)
// 先判断是否存在外置SD卡
if (externalFiles.size >= 2 && externalFiles[1] != null) {
    val sdCardAppDir = externalFiles[1]
    val myDirectory = File(sdCardAppDir, "Folder")
    if (!myDirectory.exists()) {
        val createResult = myDirectory.mkdir()
        Log.i("Create", createResult.toString())
    }
}

场景2:需要在SD卡公共区域创建用户可见的目录

必须使用系统存储访问框架(SAF)主动申请SD卡的访问权限,步骤如下:

  1. 触发授权弹窗让用户选择SD卡根目录:
val REQUEST_CODE_SD_PERM = 1001
// 替换为你的SD卡标识,也可以不传初始Uri让用户手动选择
val sdCardUri = Uri.parse("content://com.android.externalstorage.documents/tree/3C03-69OD%3A")
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
    putExtra(DocumentsContract.EXTRA_INITIAL_URI, sdCardUri)
}
startActivityForResult(intent, REQUEST_CODE_SD_PERM)
  1. 接收授权结果,使用DocumentFile创建目录:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_CODE_SD_PERM && resultCode == Activity.RESULT_OK) {
        val treeUri = data?.data ?: return
        // 持久化保存权限,下次启动应用无需重复申请
        contentResolver.takePersistableUriPermission(
            treeUri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        )
        val sdRoot = DocumentFile.fromTreeUri(this, treeUri)
        // 创建Folder目录
        val newFolder = sdRoot?.createDirectory("Folder")
        Log.i("Create", (newFolder != null && newFolder.exists()).toString())
    }
}

注意事项

  • 若后续将应用目标版本升级到API30及以上,requestLegacyExternalStorage配置会完全失效,所有公共存储区域的写入操作都需要使用SAF或者MediaStore实现,无法再通过传统FileAPI操作。
  • 使用getExternalFilesDirs之前务必先判断数组长度,避免用户未插入SD卡时出现空指针崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 07:24:03