无法从手机存储加载PDF至Activity,求WebView加载本地PDF方案
问题分析与修正方案
你的代码存在几个关键问题,导致PDF无法正常加载,以下是具体问题和修复后的实现:
存在的问题
- loadData的MIME类型错误:你加载的是包含iframe的HTML内容,但指定的MIME是
application/pdf,WebView无法正确解析。 - Base64编码包含换行符:
Base64.DEFAULT会自动插入换行,破坏data URI的格式,导致iframe无法识别PDF内容。 - InputStream读取方式不安全:依赖
available()获取文件大小,大文件时会导致读取不完整或者OOM。 - WebView缺少必要配置:部分WebView设置未开启,影响PDF渲染的兼容性。
修复后的代码
webView.settings.apply { javaScriptEnabled = true builtInZoomControls = true domStorageEnabled = true // 开启DOM存储,部分PDF渲染依赖 allowFileAccess = true allowContentAccess = true } webView.webViewClient = object : WebViewClient() { override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) Log.d("PDF_LOAD", "页面加载完成") } override fun onReceivedError( view: WebView?, request: WebResourceRequest?, error: WebResourceError? ) { super.onReceivedError(view, request, error) val errorMsg = error?.description?.toString() ?: "未知错误" Log.e("PDF_LOAD", "加载失败: $errorMsg") // 可添加Toast提示用户 // Toast.makeText(view?.context, "PDF加载失败: $errorMsg", Toast.LENGTH_SHORT).show() } } // 加载assets中的PDF文件 try { assets.open("test.pdf").use { inputStream -> // 安全读取文件内容,避免依赖available() val byteArray = inputStream.readBytes() val base64 = android.util.Base64.encodeToString(byteArray, android.util.Base64.NO_WRAP) val mimeType = "application/pdf" val html = """ <iframe src='data:$mimeType;base64,$base64' width='100%' height='100%' style='border: none;'></iframe> """.trimIndent() // 加载HTML内容,MIME类型设为text/html,编码用UTF-8 webView.loadDataWithBaseURL(null, html, "text/html", "utf-8", null) } } catch (e: Exception) { e.printStackTrace() Log.e("PDF_LOAD", "加载异常: ${e.message}") }
额外说明
- 改用
loadDataWithBaseURL替代loadData:loadData对特殊字符处理有限,loadDataWithBaseURL更稳定,适合加载包含data URI的HTML。 - 使用
use函数自动关闭InputStream:避免手动关闭时的遗漏,代码更安全。 - 补充WebView关键配置:
domStorageEnabled、allowFileAccess等配置能提升不同Android版本下PDF渲染的兼容性。 - 增强错误日志输出:方便快速定位加载失败的原因。
内容的提问来源于stack exchange,提问作者Salman Developer
相关产品推荐
相关产品推荐

