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

如何在WebView中嵌入显示带JWT权限验证的PDF文件?

可行实现方案

方案1:带签名的临时URL + iframe(推荐)

解决Android WebView无法加载直接路径、避免JWT暴露的问题。

后端(PHP 8.2)实现:

  • 新增/api/pdf/token接口,接收请求头Authorization: Bearer {token},验证用户身份与角色权限。
  • 验证通过后,生成包含文件ID、过期时间(如10分钟)、HMAC签名的临时URL(用服务器密钥签名参数,防止篡改),返回给前端。
  • 新增/pdf/access接口,校验请求中的file_id、exp和sign:确认签名有效且未过期后,输出PDF文件流并设置响应头:
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="document.pdf"');
readfile('/path/to/stored/pdf/123.pdf');
exit;

前端/WebView配置:

  • 前端拿到临时URL后,用iframe嵌入:
<iframe src="临时URL" width="100%" height="100%" frameborder="0"></iframe>
  • Android WebView调整配置:
webView.settings.apply {
    javaScriptEnabled = true
    allowFileAccess = true
    mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW // 正式环境建议用MIXED_CONTENT_NEED_USER_ACTION
    loadWithOverviewMode = true
    useWideViewPort = true
}
  • iOS WKWebView默认支持iframe加载PDF,确保临时URL为HTTPS(正式环境)即可。

方案2:后端返回PDF Base64 + PDF.js加载

解决之前PDF.js加载失败的问题,核心是确保WebView配置与后端数据格式正确。

后端(PHP)实现:

  • 接口验证JWT后,读取PDF文件转为Base64返回:
$pdfPath = '/path/to/stored/pdf/123.pdf';
$pdfBase64 = base64_encode(file_get_contents($pdfPath));
echo json_encode(['pdf_base64' => $pdfBase64]);

前端/WebView实现:

  • 将PDF.js的viewer.html及相关脚本部署到自己的Web服务器(避免CDN跨域问题)。
  • 前端获取Base64后转为Uint8Array,调用PDF.js渲染:
const pdfData = atob(res.pdf_base64);
const uint8Array = new Uint8Array(pdfData.length);
for (let i = 0; i < pdfData.length; i++) {
    uint8Array[i] = pdfData.charCodeAt(i);
}

pdfjsLib.getDocument(uint8Array).promise.then(pdf => {
    pdf.getPage(1).then(page => {
        const canvas = document.getElementById('pdf-canvas');
        const context = canvas.getContext('2d');
        const viewport = page.getViewport({ scale: 1.5 });
        canvas.height = viewport.height;
        canvas.width = viewport.width;
        page.render({ canvasContext: context, viewport: viewport });
    });
});
  • WebView必须开启JavaScript:
    • Android:webView.settings.javaScriptEnabled = true,并设置allowFileAccess = true。
    • iOS:确保WKWebViewConfiguration.preferences.javaScriptEnabled = true。

方案3:WebView调用原生能力加载PDF

利用移动端原生PDF渲染能力,规避Web端兼容性问题。

实现流程:

  1. 前端Web页面触发事件,调用原生方法(如window.android.loadPDF(fileId)或iOS的消息发送)。
  2. 移动端原生携带JWT令牌(从本地存储读取或前端传入),调用后端接口获取PDF流。
  3. 原生将PDF流保存到本地临时目录(Android用getCacheDir(),iOS用NSTemporaryDirectory())。
  4. 通知WebView加载本地PDF路径:
    • Android:webView.loadUrl("file://" + localFilePath)
    • iOS:webView.loadFileURL(localFileURL, allowingReadAccessTo: localFileURL.deletingLastPathComponent())

关键代码示例:

  • Android(Kotlin):
webView.addJavascriptInterface(object {
    @JavascriptInterface
    fun loadPDF(fileId: String) {
        val request = Request.Builder()
            .url("https://your-backend/api/pdf/$fileId")
            .addHeader("Authorization", "Bearer $jwtToken")
            .build()
        OkHttpClient().newCall(request).enqueue(object : Callback {
            override fun onResponse(call: Call, response: Response) {
                response.body?.byteStream()?.let { inputStream ->
                    val file = File(cacheDir, "temp.pdf")
                    FileOutputStream(file).use { outputStream ->
                        inputStream.copyTo(outputStream)
                    }
                    runOnUiThread {
                        webView.loadUrl("file://${file.absolutePath}")
                    }
                }
            }
            override fun onFailure(call: Call, e: IOException) { /* 错误处理 */ }
        })
    }
}, "android")
  • iOS(Swift):
let configuration = WKWebViewConfiguration()
configuration.userContentController.add(self, name: "loadPDF")
let webView = WKWebView(frame: view.bounds, configuration: configuration)

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if message.name == "loadPDF", let fileId = message.body as? String {
        var request = URLRequest(url: URL(string: "https://your-backend/api/pdf/\(fileId)")!)
        request.addValue("Bearer \(jwtToken)", forHTTPHeaderField: "Authorization")
        URLSession.shared.dataTask(with: request) { data, _, _ in
            guard let data = data else { return }
            let tempPath = NSTemporaryDirectory() + "temp.pdf"
            try? data.write(to: URL(fileURLWithPath: tempPath))
            DispatchQueue.main.async {
                let fileURL = URL(fileURLWithPath: tempPath)
                self.webView.loadFileURL(fileURL, allowingReadAccessTo: fileURL.deletingLastPathComponent())
            }
        }.resume()
    }
}

之前问题的补充说明:

  • Android WebView无法加载直接路径:多因WebSettings未配置(如未开启文件访问、混合内容模式),或路径为本地绝对路径而非Web可访问URL。
  • Google Docs Viewer暴露JWT:存在泄露风险,不建议使用,临时URL方案更安全。
  • PDF.js加载失败:可能是后端未正确返回PDF数据、WebView未开启JS,或PDF.js资源路径配置错误(如viewer.html找不到对应脚本)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 14:32:38