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

Swift中使用WKWebView创建PDF触发未知错误求助

macOS下WKWebView生成PDF报错WKErrorDomain Code=1的问题排查

问题场景

照搬示例代码在macOS中使用WKWebView的createPDF方法生成PDF时,始终触发失败回调,错误信息为:

failure(Error Domain=WKErrorDomain Code=1 "An unknown error occurred" UserInfo={NSLocalizedDescription=An unknown error occurred.})

原代码如下:

private func CreatePDF(htmlString: String) {
    let width = ((21/2.54)*72)
    let height = ((29.7/2.54)*72)
    if let downloadDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
        let savePath = downloadDir.appendingPathComponent("swiftPdf").appendingPathExtension("pdf")
        
        let webViewConfiguration = WKWebViewConfiguration()
        
        let webView = WKWebView(frame: .init(x: 0, y: 0, width: width, height: height), configuration: webViewConfiguration)
        
        let pdfConfiguration = WKPDFConfiguration()
        pdfConfiguration.rect = CGRect(x: 0.0, y: 0.0, width: width, height: height)

        webView.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            webView.createPDF(configuration: pdfConfiguration) { result in
                switch result {
                    case .success(let data):
                        do {
                            try data.write(to: savePath)
                            print("Successfully created and saved pdf…")
                        } catch let error {
                            print("Could not _save_ pdf: \(error)")
                        }
                    case .failure(let error): // <<-- always comes out here with error
                        print("Could not create pdf: \(error)")
                }
            }
        }
    }
}

核心问题与解决要点

  • WKWebView必须加入视图层级:macOS平台要求WKWebView必须被添加到有效的视图或窗口中才能完成渲染和PDF生成,iOS支持离线渲染,但macOS不允许无层级的WebView进行渲染操作。
  • 替换固定延迟为加载完成监听:asyncAfter(deadline: .now() + 1)完全不可靠,页面加载时间受内容复杂度影响,必须通过WKNavigationDelegate监听页面加载完成事件,确保HTML完全渲染后再调用createPDF。
  • 确保HTML内容合法完整:传入的htmlString需要是标准HTML结构(包含<html>、<body>等核心标签),不完整或非法的HTML会导致渲染失败。

修改后的示例代码

// 让当前类遵循WKNavigationDelegate协议
class YourClass: NSObject, WKNavigationDelegate {
    private func createPDF(htmlString: String) {
        let width = ((21/2.54)*72)
        let height = ((29.7/2.54)*72)
        guard let downloadDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let savePath = downloadDir.appendingPathComponent("swiftPdf").appendingPathExtension("pdf")
        
        let webViewConfiguration = WKWebViewConfiguration()
        let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: width, height: height), configuration: webViewConfiguration)
        webView.navigationDelegate = self
        
        // 将webView添加到当前视图层级(以NSViewController为例)
        self.view.addSubview(webView)
        webView.isHidden = true // 隐藏临时WebView,避免干扰界面
        
        let pdfConfiguration = WKPDFConfiguration()
        pdfConfiguration.rect = CGRect(x: 0.0, y: 0.0, width: width, height: height)

        webView.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
        // 临时存储PDF生成所需的路径和配置
        self.tempPDFInfo = (savePath, pdfConfiguration)
    }
    
    // 临时存储PDF路径与配置的变量
    private var tempPDFInfo: (URL, WKPDFConfiguration)?
    
    // 监听页面加载完成事件
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        guard let (savePath, pdfConfiguration) = tempPDFInfo else { return }
        webView.createPDF(configuration: pdfConfiguration) { result in
            switch result {
            case .success(let data):
                do {
                    try data.write(to: savePath)
                    print("Successfully created and saved pdf…")
                } catch let error {
                    print("Could not save pdf: \(error)")
                }
            case .failure(let error):
                print("Could not create pdf: \(error)")
            }
            // 生成完成后移除临时WebView
            webView.removeFromSuperview()
            self.tempPDFInfo = nil
        }
    }
    
    // 监听页面加载失败事件
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        print("Page load failed: \(error)")
        webView.removeFromSuperview()
        self.tempPDFInfo = nil
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 12:54:21