在开放 Web 上,window.print() 会唤起浏览器打印面板,用户可保存为 PDF 或发送到打印机。在 WebView 里,这个调用静默无作为。Android 只通过宿主侧 API 暴露打印,iOS WKWebView 则完全忽略该调用。宿主自有 runtime 桥接打印与 PDF 导出——同一个 API,在每种引擎上都能产出真实文档。
Android:打印是宿主专属 API
Android 官方文档写得很清楚:要在 WebView 里打印,必须调用 webView.createPrintDocumentAdapter(jobName) 并交给系统 PrintManager,页面自身无法触发 window.print()。文档还列了硬性限制:不能用 JavaScript 触发打印、同一 WebView 实例一次只能跑一个打印任务、带横屏等 CSS 打印属性的 HTML 不被支持。于是,在 Chrome 里能打印票据的结算页,在 App 的 WebView 里按钮毫无反应。开发者必须持有 WebView 实例、构造适配器、弹出系统打印面板——PDF 导出走的也是同一条路,页面无法自行发起。
iOS:window.print() 被静默忽略
在 WKWebView 里,window.print() 不会弹出打印面板。社区通行的做法是注入一段脚本,把 window.print 覆写为向 WKScriptMessageHandler 发消息,再由原生侧驱动 UIPrintInteractionController。即便如此,iOS 也没有桌面等价的「纯 Web 静默打印」:打印控制器必须呈现一个用户可见的打印界面供确认,网页无法触达无头打印管线。PDF 导出同理——桥必须活在 App 里。
打印失效时,什么会崩
- 票据与行程单出不来。 在 Safari 能用的「打印 / 存 PDF」按钮,在 WebView 里毫无反应。
- 发票与报表无法导出。 依赖浏览器打印转 PDF 的财务与 SaaS 流程丢失了出口。
- 物流与零售小票打印失败。 拣货单、面单、POS 小票都无法在 App 内生成。
- 内置浏览器更糟。 微信、抖音等内置 WebView 几乎不暴露任何打印面,桌面 QA 时问题被掩盖。
runtime 解法
宿主自有 runtime 桥接打印与导出层。页面调用统一 API——runtime.print() 或 runtime.exportPdf()——宿主通过 Android 原生 PrintManager 与 iOS 原生 UIPrintInteractionController 渲染。页眉、页脚、页码、横竖屏由原生统一处理。一次集成,每种引擎,同一文档格式。
| 维度 | WebView | 宿主自有 runtime |
|---|---|---|
| 触发 | window.print() 无作为 | 统一 runtime.print() |
| Android 路径 | 宿主须接适配器 + PrintManager | 原生 PrintManager |
| iOS 路径 | window.print() 被忽略 | 原生 UIPrintInteractionController |
| JS 触发打印 | 平台拦截 | 原生桥 |
| PDF 导出 | 页面无法发起 | 单一 API |
| 一致性 | 因引擎而异 | 统一 |
原生 App 能在每台设备上打印小票,裸 WebView 几乎一台都打不了。runtime 给页面一个打印面——最终产出真实的 PDF。
参考来源
- Android Developers — 打印 HTML 文档 —
createPrintDocumentAdapter+PrintManager,以及限制:不能用 JS 触发打印、每 WebView 仅一个任务、不支持横屏等 CSS 打印属性。 - Stack Overflow — 在 Android 中从 WebView 生成 PDF — 从 API 19 起用 PrintManager 把 WebView 转成 PDF。
- Exchangetuts — 在 WKWebView 中捕获 window.print() — 把
window.print覆写为WKScriptMessageHandler再调UIPrintInteractionController的变通。 - 博客园 — iOS Safari/WKWebView 无等价静默 Web 打印 — 结构性限制:iOS WebView 无桌面等价静默打印。
- MDN — window.print() — WebView 静默丢弃的 Web API。