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

Android 9及以下系统如何申请特定目录权限?

Android 9及以下系统申请特定目录权限的问题解答

核心结论

Android 9(API 28及以下)无法通过ACTION_OPEN_DOCUMENT_TREE指定初始目录,因为DocumentsContract.EXTRA_INITIAL_URI参数是从Android 10(API 29)才开始正式支持的,你当前代码里的该参数在Android9上完全无效,系统会默认打开最近访问的目录。

原因分析

Android 10之前采用传统外部存储模型:只要申请了READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE权限,就能直接访问外部存储上的任意目录(包括WhatsApp状态目录),不需要依赖文档选择器。而ACTION_OPEN_DOCUMENT_TREE在Android9及以下仅能打开文档树,但不支持指定初始路径,这是系统API的硬性限制。

适配方案

方案1:直接申请存储权限(推荐)

对于Android9及以下,直接申请存储权限即可直接访问目标目录,无需文档选择器:

fun openDirectory() {
    if (Build.VERSION.SDK_INT >= 29) {
        // Android 10+ 沿用原文档选择器逻辑
        val pickerInitialPath = "${Environment.getExternalStorageDirectory().absolutePath}$WS_DIRECTORY_PATH"
        val folderUri = Uri.parse(pickerInitialPath)
        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
            putExtra(DocumentsContract.EXTRA_INITIAL_URI, folderUri)
        }
        startActivityForResult(intent, 2000)
    } else {
        // Android 9及以下 申请存储权限
        val readPermission = Manifest.permission.READ_EXTERNAL_STORAGE
        if (ContextCompat.checkSelfPermission(this, readPermission) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, arrayOf(readPermission), 1000)
        } else {
            // 权限已授予,直接访问目录
            accessTargetDirectory()
        }
    }
}

private fun accessTargetDirectory() {
    val statusDir = File(Environment.getExternalStorageDirectory(), WS_DIR_OLDER_PATH)
    if (statusDir.exists() && statusDir.isDirectory) {
        // 此处处理目录内容,比如读取文件列表
        val files = statusDir.listFiles()?.filter { it.isFile }
        // ...
    }
}

// 处理权限申请结果
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == 1000 && grantResults.isNotEmpty()) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            accessTargetDirectory()
        } else {
            // 权限被拒绝,提示用户开启权限以访问目标目录
        }
    }
}

方案2:保留文档选择器(不推荐)

如果一定要用文档选择器,Android9及以下无法指定初始目录,只能引导用户手动找到/WhatsApp/Media/.Statuses目录,原onActivityResult逻辑可以继续使用,但体验较差:

// Android9及以下的文档选择器调用逻辑
fun openDirectoryForOlderDevices() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
    startActivityForResult(intent, 2000)
}

// 原onActivityResult逻辑不变
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    try {
        if (requestCode == 2000 && resultCode == Activity.RESULT_OK) {
            data?.data?.also { uri ->
                val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION
                contentResolver.takePersistableUriPermission(uri, takeFlags)
                // 保存URI,后续通过ContentResolver访问目录
            }
        }
    } catch (ex: Exception) {
        Log.d("OnActivity failure", "ON_ACTIVITY_RESULT FAILED WITH EXCEPTION $ex")
    }
}

注意事项

  • Android9及以下的存储权限申请需要在AndroidManifest.xml中声明:
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- 如果需要写入权限,添加下面一行 -->
    <!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> -->
    
  • 对于隐藏目录(比如.Statuses),Android9及以下默认允许访问,无需额外配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 20:03:20