如何将bytearray转为PDF并通过ACTION_VIEW intent打开,解决文件损坏问题
PDF文件损坏问题修复方案
核心问题排查及修复步骤:
1. 清理Base64字符串前缀
绝大多数损坏是因为传入的Base64串携带了Data URI协议前缀(比如data:application/pdf;base64,),直接解码会将前缀内容也写入PDF文件导致损坏。解码前先清理前缀:val cleanBase64 = base64String.substringAfterLast(",", base64String) val byteArray = Base64.decode(cleanBase64, Base64.DEFAULT) // 可增加校验:正常PDF文件至少几百字节,解码后长度过短直接判定解码失败 if (byteArray.size < 100) { // 抛出异常或提示数据错误 return }2. 给第三方应用授予文件读取权限
你当前的Intent只配置了FLAG_ACTIVITY_NO_HISTORY,没有给跳转的PDF阅读器授予你FileProvider提供的URI的读取权限,第三方应用读取不到完整文件内容就会提示损坏。补充权限标记:val intent = Intent(Intent.ACTION_VIEW) intent.setDataAndType(uri, "application/pdf") intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 必须添加读权限 intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) // 可选:校验是否有PDF应用可以处理该Intent,避免崩溃 if (intent.resolveActivity(requireContext().packageManager) != null) { startActivity(intent) } else { // 提示用户安装PDF阅读器 }3. 优化文件写入逻辑
你当前手动关闭流的方式如果中间发生异常会导致流未正常关闭、文件写入不完整。使用Kotlin的use扩展自动管理流的关闭,避免IO异常导致的文件损坏:FileOutputStream(file).use { fos -> fos.write(byteArray) }4. 修正文件创建逻辑
原有createFile方法中使用的Environment.getExternalStorageDirectory()在Android 10及以上系统已经废弃,直接写入会有权限限制,同时可能出现MimeTypeMap无法正确映射PDF后缀的问题,优化后的实现:fun createFile(context: Context, mimeType: String): File { val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) val fileName = "TMP_${timeStamp}_" // 兜底PDF后缀,避免MimeType映射失败 val suffix = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)?.let { ".$it" } ?: ".pdf" // 优先使用App私有缓存目录,不需要申请存储权限,FileProvider可正常访问 val docDir = File(context.cacheDir, "Documents").apply { if (!exists()) mkdirs() } return File.createTempFile(fileName, suffix, docDir) }5. 校验FileProvider配置
检查你项目中res/xml/file_paths.xml的配置,确保你存储文件的目录已经被正确声明:
如果你用了上面优化后的缓存目录,需要添加:<cache-path name="cache_docs" path="Documents/" />如果你仍用原有
getExternalFilesDir存储,需要添加:<external-files-path name="external_docs" path="Documents/" />
内容的提问来源于stack exchange,提问作者Mehdi Satei
相关产品推荐
相关产品推荐

