Android 11 Base64转PDF时出现open failed: EACCES权限错误如何解决?
Android 11写入公共目录PDF权限错误解决方案
问题根因
Android 11及以上版本采用分区存储机制,原有READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE权限无法直接对公共Download目录执行写入操作,即使动态申请了权限也会被系统拦截,触发EACCES (Permission denied)错误。
可选解决方案
方案1:使用应用专属外部存储(最推荐,无需额外权限)
直接将PDF写入应用专属的外部私有目录,该目录默认授予应用完整读写权限,且你已配置的FileProvider已经适配该路径,修改getFilePath方法即可:
private fun getFilePath(filename: String): String { // 应用专属外部下载目录,无需申请存储权限即可读写 val file = File(requireContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") if (!file.exists()) { file.mkdirs() } return file.absolutePath + "/" + filename + ".pdf" }
如果需要让用户可在系统下载列表中查看该PDF,后续可再通过MediaStore将文件同步插入公共下载目录。
方案2:使用MediaStore写入公共Download目录(无需敏感权限)
如果必须将文件存储到公共Download目录,可通过MediaStoreAPI写入,适配分区存储规则,无需申请特殊权限:
// 替换原有的FileOutputStream写入逻辑 private fun savePdfToPublicDownload(decodedBytes: ByteArray, fileName: String) { val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, "$fileName.pdf") put(MediaStore.MediaColumns.MIME_TYPE, "application/pdf") put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS) } val uri = requireContext().contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues) uri?.let { requireContext().contentResolver.openOutputStream(it)?.use { outputStream -> outputStream.write(decodedBytes) } } }
方案3:申请所有文件访问权限(不推荐,仅适用于文件管理类应用)
如果你的应用有合理的全存储访问需求,可在AndroidManifest.xml中补充权限配置:
<!-- Android 11-12 全存储访问权限 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13+ 媒体文件读取权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
运行时需要引导用户跳转到系统设置页开启「所有文件访问权限」,权限通过后即可正常写入公共目录。
代码优化点
原有generatePDFFromBase64方法未做空参数校验,建议补充校验逻辑避免空指针异常:
private fun generatePDFFromBase64(base64: String?, fileName: String?) { // 提前校验空参数 if (base64.isNullOrEmpty() || fileName.isNullOrEmpty()) { return } try { val decodedBytes: ByteArray = Base64.decode(base64, Base64.DEFAULT) // 后续写入逻辑 } catch (e: IOException) { Log.e("TAG", "Faild to generate pdf from base64: ${e.localizedMessage}") } }
内容的提问来源于stack exchange,提问作者Mario Muresean
相关产品推荐
相关产品推荐

