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

