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

Android Kotlin中Uri转InputStream遇权限异常,求Excel读取方案

解决Android读取Excel文件时的SecurityException权限问题

错误原因

你直接硬编码了Content Uri,没有通过Android存储访问框架(SAF)的ACTION_OPEN_DOCUMENT或相关API获取用户授权的文件访问权限。Android的安全机制禁止应用直接访问未经过用户明确授权的媒体文件Uri,因此抛出了SecurityException。

解决方案

1. 启动系统文件选择器获取Excel文件Uri

使用ACTION_OPEN_DOCUMENT启动系统文件选择器,让用户手动选择要读取的.xlsx文件,这样获取到的Uri会带有合法的访问权限。

2. 处理文件选择结果

在Activity中接收选择器返回的Uri,可选申请持久化权限,让应用后续可以继续访问该文件。

3. 修改Excel读取代码

使用获取到的合法Uri来打开输入流,进行Excel解析。

完整代码示例

启动文件选择器的代码(使用ActivityResultContracts)

// 在Activity中定义ActivityResultLauncher
private val openDocumentLauncher = registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? ->
    uri?.let {
        // 可选:申请持久化权限,让应用重启后仍能访问该文件
        contentResolver.takePersistableUriPermission(
            it,
            Intent.FLAG_GRANT_READ_URI_PERMISSION
        )
        // 调用读取Excel的方法
        readDataExcel(it)
    }
}

// 触发文件选择的方法,比如按钮点击事件中调用
fun pickExcelFile() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        // 指定只允许选择xlsx格式文件
        type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    }
    openDocumentLauncher.launch(intent)
}

修改后的读取Excel方法

private fun readDataExcel(fileUri: Uri) {
    try {
        val inputStream = contentResolver.openInputStream(fileUri) ?: return
        val workbook = WorkbookFactory.create(inputStream)

        val sheet = workbook.getSheet("list") ?: return
        for (row in sheet) {
            if (row.getCell(0) == null || row.getCell(0).cellType == CellType.BLANK) {
                break
            }
            val codeValue = row.getCell(0).stringCellValue
            val liteCodeValue = codeValue.replace(".", "").replace("-", "")
            val articleValue = row.getCell(1).stringCellValue
            articles.add(ArticleModel(
                code = codeValue,
                liteCode = liteCodeValue,
                title = articleValue
            ))
        }
        workbook.close()
        inputStream.close()
    } catch (e: Exception) {
        e.printStackTrace()
        // 处理异常,比如提示用户读取失败
    }
}

注意事项

  • 确保你的项目中已经添加了Apache POI相关依赖(用于解析Excel),比如在build.gradle中:
implementation 'org.apache.poi:poi:5.2.3'
implementation 'org.apache.poi:poi-ooxml:5.2.3'
  • Android 10+不需要申请READ_EXTERNAL_STORAGE权限,通过SAF获取的Uri已经带有访问权限。
  • 持久化权限是可选的,如果你的应用不需要在重启后继续访问该文件,可以跳过takePersistableUriPermission调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 09:27:02