Printing WKWebView to PDF in macOS 11.0+

As WKWebView contents can finally be printed out in macOS 11+, I'm trying to replace my old WebView dependencies.

However, with the HTML correctly loaded in WKWebView, creating PDF files using NSPrintJobDisposition: NSPrintSaveJob produces blank, empty documents. They have the correct page count and sizing, but remain empty. Using the same code without NSPrintSaveJob works just fine.

This is how I'm printing the contents:

NSPrintInfo *printInfo = NSPrintInfo.sharedPrintInfo;	
[printInfo.dictionary addEntriesFromDictionary:@{
		NSPrintJobDisposition: NSPrintSaveJob,
		NSPrintJobSavingURL: url
}];

NSPrintOperation *printOperation =[(WKWebView*)_webView printOperationWithPrintInfo:printInfo];
printOperation.view.frame = NSMakeRect(0,0, printInfo.paperSize.width, printInfo.paperSize.height);
	
printOperation.showsPrintPanel = NO;
printOperation.showsProgressPanel = YES;
	
[printOperation runOperation];

Setting showsPrintPanel as true and uncommenting the dictionary produces traditional prints, and the results look completely normal. In both cases, I'm calling the runOperation only after navigation has actually finished.

I'm confused about what I am doing wrong, or is printing from WKWebView still this buggy?

Sample project:https://www.dropbox.com/s/t220cn8orooorwb/WebkitPDFTest.zip?dl=1

The issue was [printOperation runOperation] / printOperation.runOperation(), which simply does not work.

Instead, you need to call the strangely named runOperationModalForWindow. Although the method name refers to a modal window, you don't need to display the modal. This method makes the print operation run asynchronously (?) which modern WebKit likes more.

Apple, please, please, please document this somewhere.

// Create print operation
NSPrintOperation *printOperation = [webView printOperationWithPrintInfo:printInfo];

// Set web view bounds - without this, the operation will crash
printOperation.view.frame = NSMakeRect(0,0, printInfo.paperSize.width, printInfo.paperSize.height);

// Print it out
[printOperation runOperationModalForWindow:self.window delegate:self didRunSelector:@selector(printOperationDidRun:success:contextInfo:) contextInfo:nil];

You also need to have a handler method to catch the results:

- (void)printOperationDidRun:(id)operation success:(bool)success contextInfo:(nullable void *)contextInfo {
    // Do something with your print
}
Printing WKWebView to PDF in macOS 11.0+
 
 
Q