I'm trying to export an html file as a pdf using the answer here which uses a WKWebView
to load an html string and then draw a PDF from that. I also need it to work on Catalyst, which is why I'm using this approach.
What's happening is that the WKWebView
is never calling it's navigationDelegate
methods. I've put a bunch of print()
statements in a bunch of delegate methods but the only output I get is:
::::: SET WEBVIEW
Loaded
I can't figure out what is making the WKWebView
not call it's delegate methods. I've also tried loading a URL like https://google.com and it fails the same way. I've even observed loading progress from the webview, and it is loading the content, just not calling the delegate.
I'd appreciate any help, I need this to work.
class ReportsRenderer: NSObject {
var webView: WKWebView? = nil {
didSet {
print("::::: SET WEBVIEW")
}
}
var completion: PDFCompletion!
typealias PDFCompletion = (Result<NSData, Error>) -> Void
func exportPDF(html: String, completion: @escaping PDFCompletion) throws {
self.completion = completion
webView = WKWebView()
webView?.navigationDelegate = self
let baseURL = URL(fileURLWithPath: NSTemporaryDirectory())
webView?.loadHTMLString(html, baseURL: baseURL)
print("Loaded")
}
func createPDF(_ formatter: UIViewPrintFormatter) {
print("Creating PDF")
let printPageRenderer = UIPrintPageRenderer()
printPageRenderer.addPrintFormatter(formatter, startingAtPageAt: 0)
let paperRect = CGRect(x: 0, y: 0, width: 595.2, height: 841.8)
let padding: CGFloat = 20
let printableRect = paperRect.insetBy(dx: padding, dy: padding)
printPageRenderer.setValue(printableRect, forKey: "printableRect")
printPageRenderer.setValue(paperRect, forKey: "paperRect")
printPageRenderer.footerHeight = 70
printPageRenderer.headerHeight = 20
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, .zero, nil)
for i in 0..<printPageRenderer.numberOfPages {
UIGraphicsBeginPDFPage();
printPageRenderer.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext();
self.completion?(.success(pdfData))
}
}
extension ReportsRenderer: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("::::: WEBVIEW NAVIGATED")
let viewPrintFormatter = webView.viewPrintFormatter()
createPDF(viewPrintFormatter)
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("::::: WEBVIEW ERROR")
print(error.localizedDescription)
}
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
print("::::: WEBVIEW DIDCOMMIT NAVIGATION")
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("::::: WEBVIEW didStartProvisionalNavigation")
}
}
I'm calling it in my ViewController like:
do {
try ReportsRenderer().exportPDF(html: string) { (result) in
switch result {
case .success(let pdfData):
// ---- This is never called -----
print("Made the pdf data!")
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let pdfFilename = paths[0].appendingPathComponent("\(UUID().uuidString).pdf")
pdfData.write(to: pdfFilename, atomically: true)
case .failure(let error):
// ---- This is also never called -----
print("::::: Error")
print(error.localizedDescription)
}
}
} catch {
// There isn't an error here either
print("::::: Error")
print(error)
}