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

Android应用使用Aspose.Cells加载非自建.xlsx文件遇权限拒绝问题

Android读取下载目录Excel文件权限拒绝问题

问题现象

开发的Android应用可正常加载自身通过Aspose.Cells创建的.xlsx文件,但加载下载目录中的.xlsx文件时触发权限拒绝错误,具体报错如下:

Caused by: java.io.FileNotFoundException: /storage/emulated/0/Download/ECR.xlsx: open failed: EACCES (Permission denied)

实现代码

class Home: Fragment(R.layout.fragment_home) {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view: View = inflater.inflate(R.layout.fragment_home, container, false)

        val load = view.findViewById<Button>(R.id.button3)
        val new = view.findViewById<Button>(R.id.button4)
        val editText = view.findViewById<EditText>(R.id.editTextTextPersonName)

        new.setOnClickListener(View.OnClickListener {
            Excel.name = "${Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS)}/${editText.text.toString()}.xlsx"
            Excel.workbook = Workbook()
            Excel.workbook!!.save(Excel.name)
            println("Created: ${Excel.workbook}")
        })

        load.setOnClickListener(View.OnClickListener {
            Excel.workbook = Workbook("${Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS)}/${editText.text.toString()}.xlsx")
            Excel.name = "${Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS)}/${editText.text.toString()}.xlsx"
            Excel.workbook!!.save("${Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS)}/${editText.text.toString()}.xlsx")
            println("Loaded: ${Excel.workbook}")
        })
        return view
    }
}

AndroidManifest.xml配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.FRCScout22"
        tools:targetApi="31">
        <activity
            android:name=".DropDownActivity"
            android:exported="false">
            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>
</manifest>

解决办法

1. 适配Android 13+权限规则

Android 13(API 33)起,READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限不再生效,针对文档类文件(如.xlsx)需额外申请READ_MEDIA_DOCUMENTS权限,在Manifest中添加:

<uses-permission android:name="android.permission.READ_MEDIA_DOCUMENTS" android:minSdkVersion="33"/>

2. 动态申请危险权限

Android 6.0(API 23)及以上需动态申请权限,在Fragment中添加权限检查逻辑:

private val REQUEST_PERMISSIONS = 1001
private val requiredPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    arrayOf(Manifest.permission.READ_MEDIA_DOCUMENTS)
} else {
    arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    checkPermissions()
}

private fun checkPermissions() {
    val permissionsNeeded = mutableListOf<String>()
    for (permission in requiredPermissions) {
        if (ContextCompat.checkSelfPermission(requireContext(), permission) != PackageManager.PERMISSION_GRANTED) {
            permissionsNeeded.add(permission)
        }
    }
    if (permissionsNeeded.isNotEmpty()) {
        ActivityCompat.requestPermissions(requireActivity(), permissionsNeeded.toTypedArray(), REQUEST_PERMISSIONS)
    }
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_PERMISSIONS) {
        // 可添加权限拒绝后的处理逻辑
    }
}

3. 使用存储访问框架(SAF)访问文件

Android 10(API 29)及以上推荐使用SAF访问公共目录文件,避免直接操作文件路径:

load.setOnClickListener {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" // 指定.xlsx类型
    }
    startActivityForResult(intent, 1002)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 1002 && resultCode == Activity.RESULT_OK) {
        data?.data?.let { uri ->
            requireContext().contentResolver.openInputStream(uri)?.use { inputStream ->
                Excel.workbook = Workbook(inputStream)
                // 保存文件时同样建议通过SAF获取写入URI
            }
        }
    }
}

4. 前置文件存在性检查

加载文件前先判断文件是否存在,避免因文件不存在引发异常:

val filePath = "${Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS)}/${editText.text.toString()}.xlsx"
val file = File(filePath)
if (!file.exists()) {
    // 提示用户文件不存在
    return@setOnClickListener
}
// 后续加载文件逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 04:25:32