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

Android(Kotlin) API33+文件选择器无法访问文档/下载文件夹求助

问题:无法选择文档/下载文件夹中的CSV文件

我正在为小型企业(仅3人使用)开发一款APP,支持选择CSV文件、转换数据并保存为新CSV文件。目前可成功读取并处理直接导入Android Studio的文件,且已实现可访问最近文档的文件选择器,但无法选择文档或下载文件夹中的文件。现附上相关代码及截图,恳请帮助解决问题。

编辑补充:新增代码并明确问题点。


文件选择器代码

private var uriToFile:String = "Path"

private var fileImportCompletionHandler: (Uri.()->Unit)? = null

private val fileImportIntentLauncher =
    registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result: ActivityResult ->

        if (result.resultCode == Activity.RESULT_OK) {

            val intent = result.data
            intent?.data?.let { uri ->

                Log.i("MYTAG","uri at first check is $uri")
                fileImportCompletionHandler?.invoke(uri) ?: run {
                    // TODO() warn

                }

                fileImportCompletionHandler = null
               val p = uri.path
                Log.i("MYTAG","p is $p")
                

            } ?: run {
                // TODO() warn

            }

        }
        else {
            // TODO() warn
        }

    }

private val importIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {

    addCategory(Intent.CATEGORY_OPENABLE)
    type = "text/csv"

}

fun showActionOpenDocument(completion: Uri.()->Unit) {

    fileImportCompletionHandler = completion
    fileImportIntentLauncher.launch(importIntent)

}

调用代码

binding.btnImport.setOnClickListener {
    //requestPermission()
    showActionOpenDocument {
        uriToFile = this.toString()
        binding.tvPath.text = uriToFile
    }

读取逻辑代码

fun readCSV(path:String): BufferedReader {
    val inputStream: InputStream? = contentResolver.openInputStream(Uri.parse(path))
    //return BufferedReader(InputStreamReader(assets.open("Test.csv")))

    return BufferedReader(InputStreamReader(inputStream))

}

AndroidManifest权限配置

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

权限请求代码

private val requestPermissionLauncher =
    registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
            // Permission is granted. Continue the action or workflow in your
            // app.
            Log.i("MYTAG", "isGranted = true")

        } else {
            // Explain to the user that the feature is unavailable because the
            // feature requires a permission that the user has denied. At the
            // same time, respect the user's decision. Don't link to system
            // settings in an effort to convince the user to change their

        }
    }

fun requestPermission(){
    when{
        ContextCompat.checkSelfPermission(
            vContext,
            Manifest.permission.READ_EXTERNAL_STORAGE
        ) == PackageManager.PERMISSION_GRANTED -> {
            //Permission is Granted

            Log.i("MYTAG","Permission Granted")

        }
        ActivityCompat.shouldShowRequestPermissionRationale(
            vActivity,
            Manifest.permission.READ_EXTERNAL_STORAGE
        ) -> {
            //Permission denied : Additional Rational should be displayed
            Log.i("MYTAG","Permission Denied")
            showRationaleDialog("TCG Inventory Converter",
                "TCG Inventory Converter needs access to your External Storage"+
                        "\n"+"\n"+"REASON: Required to import and export CSV Files ")

        }
        else -> {
            // Permission has not been asked yet
            Log.i("MYTAG","Permission Requested")
            requestPermissionLauncher.launch(
                Manifest.permission.READ_EXTERNAL_STORAGE
            )
        }
    }
}

private fun showRationaleDialog(title:String, message:String){
    val builder: AlertDialog.Builder = AlertDialog.Builder(vContext)
    builder.setTitle(title)
        .setMessage(message)
        .setPositiveButton("Cancel"){ dialog, _->
         dialog.dismiss()
        }
        .setNegativeButton("Open Permissions"){ dialog, _ ->
            dialog.run {
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                val uri = Uri.fromParts("package","com.example.filereadtest",null)
                intent.data =uri
                startActivity(intent)
            }

        }
    builder.create().show()
}

截图说明

  • 想要选择的不可选文件:文档/下载文件夹中的CSV文件无法选中
  • 唯一可选位置:仅能访问最近文档,该路径无法保存文件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 09:37:54