如何利用WKWebView的printFormatter打印指定iFrame内容?
刚好我之前处理过类似的需求,结合WKWebView的特性,给你梳理两个靠谱的方案,解决用printFormatter打印iFrame内容的问题:
方案1:提取iFrame内容到临时WKWebView打印
这个思路很直接——先拿到iFrame里的完整HTML(包括样式),把它加载到一个隐藏的临时WKWebView里,再用这个临时WebView的printFormatter触发系统打印。
具体步骤:
- 先在主WebView里注入JS,获取目标iFrame的内容(假设你的iFrame有
id="printFrame"):
// 执行JS获取iFrame的完整HTML webView.evaluateJavaScript("document.getElementById('printFrame').contentDocument.documentElement.outerHTML") { result, error in guard let iframeHTML = result as? String, error == nil else { print("拿iFrame内容失败:\(error?.localizedDescription ?? "未知错误")") return } // 新建临时WKWebView,用来加载iFrame内容 let tempWebView = WKWebView() tempWebView.tag = 999 // 加个标记,后面代理里好区分是临时WebView还是主WebView tempWebView.navigationDelegate = self // 用主页面的URL作为baseURL,保证iFrame里的相对路径样式能正常加载 tempWebView.loadHTMLString(iframeHTML, baseURL: webView.url) }
- 实现WKNavigationDelegate的方法,等临时WebView加载完成后触发打印:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // 确认是我们的临时WebView guard webView.tag == 999 else { return } let printFormatter = webView.viewPrintFormatter() let printController = UIPrintInteractionController.shared printController.printFormatter = printFormatter // 弹出系统打印界面 printController.present(animated: true) { _, completed, error in if let error = error { print("打印出问题了:\(error.localizedDescription)") } // 打印完成后可以把临时WebView销毁,避免内存占用 webView.removeFromSuperview() } }
方案2:拦截window.print()定向到iFrame内容
如果你之前已经有拦截主页面window.print()的逻辑,可以直接修改注入的JS,让它在捕获打印请求时,主动把iFrame的内容传给Native层,再走打印流程。
- 注入JS覆盖原生的
window.print方法:
// 自定义window.print,把iFrame内容通过消息发给Native let printOverrideJS = """ window.print = function() { const targetIframe = document.getElementById('printFrame'); const iframeFullHTML = targetIframe.contentDocument.documentElement.outerHTML; // 通过WKScriptMessageHandler传递内容 window.webkit.messageHandlers.printTrigger.postMessage(iframeFullHTML); }; """ // 把脚本添加到WebView配置 let userScript = WKUserScript(source: printOverrideJS, injectionTime: .atDocumentEnd, forMainFrameOnly: false) webView.configuration.userContentController.addUserScript(userScript) // 注册消息监听,接收JS传过来的内容 webView.configuration.userContentController.add(self, name: "printTrigger")
- 实现WKScriptMessageHandler协议,处理JS传来的打印内容:
extension YourViewController: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard message.name == "printTrigger", let iframeHTML = message.body as? String else { return } // 这里就和方案1一样,用临时WebView加载并打印 let tempWebView = WKWebView() tempWebView.tag = 999 tempWebView.navigationDelegate = self tempWebView.loadHTMLString(iframeHTML, baseURL: webView.url) } }
几个关键提醒
- 样式别丢了:iFrame里的样式如果是相对路径,一定要把
baseURL设为主页面的URL,不然临时WebView找不到CSS,打印出来的内容会乱。 - 关于iOS Safari:没错,iOS Safari底层就是基于WKWebView的,所以你在Safari里能用的JS逻辑,在WKWebView里基本都能跑,但Native层的打印必须用
viewPrintFormatter,不能直接靠JS的window.print()触发系统打印(除非你拦截它转成Native逻辑)。 - 跨域坑要注意:如果iFrame的内容和主页面不同域,直接拿
contentDocument会被浏览器拦截,这种情况得让iFrame所在的页面配合——比如在iFrame内部调用window.print(),然后Native拦截这个请求,或者让iFrame通过postMessage把打印内容传给主页面再处理。
内容的提问来源于stack exchange,提问作者user747594
相关产品推荐
相关产品推荐

