Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
639 views
in Technique[技术] by (71.8m points)

macos - How does one Print all WKWebView On AND Offscreen content OSX and iOS

This question is about printing ALL content (including off screen content) of WKWebView. Currently (still, as of iOS 10.2 or OSX 10.12) there is NO working solution and none of the supposed solutions on Stackoverflow work. Only provide an answer here if you have verified for yourself that you can print OFF SCREEN CONTENT, and if you did then provide the working example code.

I'm trying to print ALL the content of a WKWebView or WebView on OSX 10.10 or above (Currently running on 10.11.2). For example, a wide html table where columns are out of view and off to the right. Earlier versions of OSX would automatically paginate and correctly print all the html.

I've tried using the solutions available here on Stackoverflow and elsewhere. All essentially say the same thing which is to print the documentView like so:

[[NSPrintOperation printOperationWithView:_webView.mainFrame.frameView.documentView printInfo:pInfo] runOperation];

This stopped working for both WKWebView or WebView in 10.10. If you do this:

    [[NSPrintOperation printOperationWithView:_wkWebView printInfo:pInfo] runOperation];

You get pagination but the printout includes scroll bars WebView, and the other WKWebView gives you blank pages.

I can't find any mention whatsoever in Apple documentation about printing for WKWebView on OSX. Nor can I find any answer that is OSX specific and not iOS.

Does anyone have ANY idea how to print these on OSX?

UPDATE: This is a bug in WebView [Radar:23159060] (still open 2/2018) and WKWebView does not even appear to address printing on OSX. After examining the Open Source for this class on the net, I see that all of the classes that have anything to do with printing are in a conditional compilation block that only supports platform: iOS.

UPDATE Part Deux: Amazingly this ridiculous bug exists in ALL implementations of this class including those on iOS! I find it ridiculous that this is still not fixed at this late date despite the documentation's statement to use this (and only this class) in Apps that support iOS 8 or above. It is now IMPOSSIBLE to print all the on screen and off screen content of a WebView on either iOS or OSX. Fail Apple. Time to FIX THIS! We all know what Steve would've said about it....

UPDATE Part THREE :)- Yet still more amazing is that this issue is NOT resolved as of 10.15.2 and coming up on 4+ YEARS!!! this issue has been floating around (Apple waaaaaake up up up up....). It's kind of amazing considering they're getting very pushy about using WKWebView and over in iOS land even rejecting Apps that don't (unless you're trying to support iOS 7).

UPDATE Part FOUR (2020... can you believe it?!?): As of Big Sur, this is still an issue. I solved it by writing a work around see accepted answer below:

printOperationWithPrintInfo:

DOES NOT print all content which is off screen or scrolled out of view in either the Horizontal or vertical direction. It does however use your Print CSS which is a slight advantage over:

- (void)takeSnapshotWithConfiguration:(WKSnapshotConfiguration *)snapshotConfiguration 
                completionHandler:(void (^)(NSImage *snapshotImage, NSError *error))completionHandler;

To get it to work I did:

NSPrintInfo *pInfo = [[NSPrintInfo alloc] initWithDictionary:printInfoDict];
pInfo.horizontalPagination = NSPrintingPaginationModeAutomatic;
pInfo.verticalPagination = NSPrintingPaginationModeAutomatic;
pInfo.verticallyCentered = YES;
pInfo.horizontallyCentered = YES;
pInfo.orientation = NSPaperOrientationLandscape;
pInfo.leftMargin = 30;
pInfo.rightMargin = 30;
pInfo.topMargin = 30;
pInfo.bottomMargin = 30;

NSPrintOperation *po = [_webView printOperationWithPrintInfo:pInfo];
po.showsPrintPanel = YES;
po.showsProgressPanel = YES;

// Without the next line you get an exception. Also it seems to
// completely ignore the values in the rect. I tried changing them
// in both x and y direction to include content scrolled off screen.
// It had no effect whatsoever in either direction. 
po.view.frame = _webView.bounds; 

// [printOperation runOperation] DOES NOT WORK WITH WKWEBVIEW, use 
[po runOperationModalForWindow:self.view.window delegate:self didRunSelector:@selector(printOperationDidRun:success:contextInfo:) contextInfo:nil];

**Also there is something going on I don't fully understand. It doesn't seem to matter what size your wkWebView is. If I size the App to hide some of the content it still seems to grab as much that IS off screen as will fit on the page specified, but it doesn't seem to know how to paginate content that will not fit on the page size onto other pages. So that appears to be where the issue is. There may be some way around this and if anyone has a clue post it here!!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I've successfully used the SPI -[WKWebView _printOperationWithPrintInfo:] passing the usual [NSPrintInfo sharedPrintInfo]. Note that you CAN'T use -runOperation on the returned NSPrintOperation. You must use -runOperationModalForWindow:.... which is quite similar. The problem resides in the WebKit internals that expects a running runloop and a preview to be made internally to know the number of pages.

It definitely works with offscreen content, if what you mean by offscreen is "not fully displayed on screen". I still have a WKWebView displayed in a window, but it's very tiny and only displays a very short fraction of the entire webview content (21 A4 pages!). Hope this helps!

PS: Tested on 10.12, 10.14 and 10.15. Code is like this:

     SEL printSelector = NSSelectorFromString(@"_printOperationWithPrintInfo:"); // This is SPI on WKWebView. Apparently existing since 10.11 ?
     
     NSMutableDictionary *printInfoDict = [[[NSPrintInfo sharedPrintInfo] dictionary] mutableCopy];
     printInfoDict[NSPrintJobDisposition] = NSPrintSaveJob; // means you want a PDF file, not printing to a real printer.
     printInfoDict[NSPrintJobSavingURL] = [NSURL fileURLWithPath:[@"~/Desktop/wkwebview_print_test.pdf" stringByExpandingTildeInPath]]; // path of the generated pdf file
     printInfoDict[NSPrintDetailedErrorReporting] = @YES; // not necessary         

     // customize the layout of the "printing"
     NSPrintInfo *customPrintInfo = [[NSPrintInfo alloc] initWithDictionary:printInfoDict]; 
     [customPrintInfo setHorizontalPagination: NSPrintingPaginationModeAutomatic];
     [customPrintInfo setVerticalPagination: NSPrintingPaginationModeAutomatic];
     [customPrintInfo setVerticallyCentered:NO];
     [customPrintInfo setHorizontallyCentered:NO];
     customPrintInfo.leftMargin = 0;
     customPrintInfo.rightMargin = 0;
     customPrintInfo.topMargin = 5;
     customPrintInfo.bottomMargin = 5;
  
     NSPrintOperation *printOperation = (NSPrintOperation*) [_webView performSelector:printSelector withObject:customPrintInfo];

     [printOperation setShowsPrintPanel:NO];
     [printOperation setShowsProgressPanel:NO];

//    BOOL printSuccess = [printOperation runOperation]; // THIS DOES NOT WORK WITH WKWEBVIEW! Use runOperationModalForWindow: instead (asynchronous)
     [printOperation runOperationModalForWindow:self.window delegate:self didRunSelector:@selector(printOperationDidRun:success:contextInfo:) contextInfo:nil]; // THIS WILL WORK, but is async

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...