Android WebView如何显示.js文件(如pdf.js)中的PDF内容?
Android WebView加载Asset内JS存储PDF内容的解决方案
我之前恰好处理过几乎一模一样的场景——当你的Android WebView加载Asset目录里的网页,其他内容都正常,唯独嵌在.js文件(比如pdf.js)里的PDF内容显示不出来,常规的PDF渲染方案完全不适用,因为那些方案都是针对单独的.pdf文件的。结合你给出的具体情况(Asset里有html、fonts、pdf文件夹,用mWebview.loadUrl("file:///android_asset/appFolder/html5/index.html")加载),给你几个实用的解决思路:
1. 先把WebView的基础配置拉满
既然PDF内容是靠JS渲染的,首先得确保WebView给JS足够的运行权限:
- 必须开启JavaScript:
webSettings.setJavaScriptEnabled(true); - 开启DOM存储(很多JS驱动的内容依赖这个):
webSettings.setDomStorageEnabled(true); - 允许访问本地文件:
webSettings.setAllowFileAccess(true); - 如果你遇到跨域或者本地资源加载的问题,还要加上:
webSettings.setAllowUniversalAccessFromFileURLs(true);(注意Android 11+对这个API有调整,需要适配目标版本)
2. 适配JS里的PDF内容渲染逻辑
大多数情况下,JS里的PDF内容要么是base64编码的字符串,要么是二进制数组。你需要确保网页里的JS能正确解析这些数据并调用PDF.js的渲染API:
- 先检查你的pdf.js文件里的PDF存储格式:如果是base64,要确认WebView的JS引擎支持
atob()解码(低版本Android可能需要兼容),可以替换成兼容的解码函数; - 如果是二进制数据直接嵌入JS,要把它转换成Blob对象再传给PDF.js。比如你可以在index.html里添加或修改这段逻辑:
// 假设pdfContent是js文件里存储的PDF数据(base64字符串或二进制数组) let pdfData; if (typeof pdfContent === 'string') { // base64转Uint8Array pdfData = Uint8Array.from(atob(pdfContent), c => c.charCodeAt(0)); } else { pdfData = pdfContent; } // 调用PDF.js渲染到页面的canvas上 pdfjsLib.getDocument({data: pdfData}).promise.then(pdf => { return pdf.getPage(1); // 渲染第一页,你可以扩展成多页逻辑 }).then(page => { const canvas = document.getElementById('pdf-container'); const context = canvas.getContext('2d'); const viewport = page.getViewport({scale: 1.5}); // 调整缩放比例 canvas.height = viewport.height; canvas.width = viewport.width; // 渲染页面到canvas page.render({ canvasContext: context, viewport: viewport }); });
- 要是你的WebView版本很低(Android 5.0以下),记得引入ES6 API的polyfill,比如Blob、Uint8Array这些的兼容库。
3. 自定义WebViewClient拦截资源加载
有时候WebView会拦截JS里的特殊资源请求,你可以手动处理这些请求,提取JS里的PDF内容并返回正确的资源响应:
webView.setWebViewClient(new WebViewClient() { @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { String url = request.getUrl().toString(); // 这里替换成你识别PDF资源请求的标识,比如URL里的特定参数或路径 if (url.contains("embedded-pdf-from-js")) { try { // 从Asset读取pdf.js文件 InputStream is = getAssets().open("appFolder/html5/js/pdf.js"); String jsContent = new String(readInputStream(is)); // 提取JS里的base64格式PDF内容(根据你的实际存储格式调整) String pdfBase64 = extractPdfBase64(jsContent); // 返回PDF类型的资源响应 byte[] pdfBytes = Base64.decode(pdfBase64, Base64.DEFAULT); return new WebResourceResponse("application/pdf", "UTF-8", new ByteArrayInputStream(pdfBytes)); } catch (IOException e) { e.printStackTrace(); } } return super.shouldInterceptRequest(view, request); } }); // 辅助方法:读取输入流为字节数组 private byte[] readInputStream(InputStream is) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { baos.write(buffer, 0, len); } is.close(); return baos.toByteArray(); } // 辅助方法:从JS内容里提取PDF的base64字符串 private String extractPdfBase64(String jsContent) { // 示例:假设JS里是var pdfContent = "data:application/pdf;base64,xxxxxx"; int startMarker = "data:application/pdf;base64,".length(); int startIndex = jsContent.indexOf("data:application/pdf;base64,") + startMarker; int endIndex = jsContent.indexOf("\"", startIndex); return jsContent.substring(startIndex, endIndex); }
这个方法需要你清楚JS里PDF内容的具体存储格式,才能准确提取。
4. 升级WebView或用Chrome Custom Tabs兜底
如果上面的方法都不奏效,可能是系统WebView的JS引擎太老,对PDF.js的支持不足:
- 可以引导用户升级系统WebView(在应用里提示用户去Google Play更新Chrome/WebView);
- 或者集成Chrome Custom Tabs,不过要注意Chrome Custom Tabs不能直接访问Asset资源,你需要先把Asset里的网页内容复制到外部存储,再用file://URL加载。
内容的提问来源于stack exchange,提问作者U.A.Hameed
相关产品推荐
相关产品推荐

