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
相关产品推荐
相关产品推荐

