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

如何利用WKWebView的printFormatter打印指定iFrame内容?

刚好我之前处理过类似的需求,结合WKWebView的特性,给你梳理两个靠谱的方案,解决用printFormatter打印iFrame内容的问题:

方案1:提取iFrame内容到临时WKWebView打印

这个思路很直接——先拿到iFrame里的完整HTML(包括样式),把它加载到一个隐藏的临时WKWebView里,再用这个临时WebView的printFormatter触发系统打印。

具体步骤:

  1. 先在主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)
}
  1. 实现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层,再走打印流程。

  1. 注入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")
  1. 实现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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:43:44