'Save a PDF from a WKWebView

This questions pertains to macOS, not iOS.

Note that this question is being reported as a duplicate of this question. The answers on that page pertain either to iOS (irrelevant) or uses the deprecated WebView as a solution, which is exactly what my question is about in the first place.

So Apple has deprecated WebView in favor of WKWebView, but I'm not seeing a working solution for being able to export (or print) a PDF from the new view type. I've tried the following (and more) from within the delegate method webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)

1.

    let pdfData = webView.dataWithPDF(inside: webView.frame)
    try? pdfData.write(to: URL(fileURLWithPath: "/filepath/to/test.pdf"))

This resulted in a literal blank pdf file.

2.

webView.takeSnapshot(with: nil) { (image, error) in
    if let error = error {
        print("Error: \(error)")
        return
    }
    guard let image = image else {
        print("No image")
        return
    }
    try? image.tiffRepresentation?.write(to: URL(fileURLWithPath: "/path/to/test.tif"))
}

And while this got actual content in the image, it was a (giant) rendered bitmap image having lost all of its textual/string data, which also only showed what was visible on screen, nothing beyond the edges of the window.

Meanwhile, following the numerous examples available on the web, using WebView works well and as expected. Am I to believe that Apple released a half baked replacement for a deprecated framework, or am I doing something wrong?



Solution 1:[1]

This is now possible with WKWebView's createPDF method: https://developer.apple.com/documentation/webkit/wkwebview/3650490-createpdf

Here's an example:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
  let config = WKPDFConfiguration()
      
  //Set the page size (this can match the html{} size in your CSS
  config.rect = CGRect(x: 0, y: 0, width: 792, height: 612)
      
  //Render the PDF
  webView.createPDF(configuration: config){ result in
    switch result{
      case .success(let data):
        try! data.write(to: URL(fileURLWithPath: "/path/file.pdf"))
      case .failure(let error):
        print(error)
    }
  }
}

I have it working on both macOS and iOS. Hopefully this helps.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Clifton Labrum