4

I am using a technique similar to the question linked below to capture window.print() and trigger printing of a WKWebView. This works fine for the main page.

Capturing window.print() from a WKWebView

What I am hoping to do is print an iFrame in the page, not the page itself. In JavaScript, I focus the iFrame and call window.print(), which works in Safari on iOS (which uses WKWebView?), and various desktop browsers.

Does anybody know how to use the WKWebView printFormatter to print an iFrame of HTML content?

Shivam Tripathi
  • 1,477
  • 3
  • 16
  • 32
user747594
  • 151
  • 1
  • 6

1 Answers1

3

i've been struggling with the exact same issue for the last 3 days, and was desperately looking across the web for a solution, which I didn't find.

But I finally got it running, so here is my solution for this:

  1. Add the following user script to WKWebViewconfig.userContentController:

     WKUserScript *printScript = [[WKUserScript alloc] initWithSource:@"window.print = function() {window.webkit.messageHandlers.print.postMessage('print')}"
                                                  injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];
    
    [webViewConfig.userContentController addUserScript:printScript];
    [webViewConfig.userContentController addScriptMessageHandler:self name:@"print"];
    

=> this is the same as in Capturing window.print() from a WKWebview, with one crucial difference: forMainFrameOnly is set to NO, because we want to inject this in our iframe, and not only in the top window

  1. Define a message handler in the view controller holding your WKWebview:

In the header:

@interface MyViewcontroller : UIViewController <UIGestureRecognizerDelegate, WKNavigationDelegate, WKScriptMessageHandler>

Implementation:

-(void) userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
  1. Use the message handler to retrieve iframe's source (which is your pdf), and use-it as printing item for iOS's PrintController:

    -(void) userContentController:(WKUserContentController     *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
    
    {
     if([message.name isEqualToString:@"print"])
    {
        [self.webView evaluateJavaScript:@"window.document.querySelector(\"iframe\").src" completionHandler:^(NSString *result, NSError *error)
        {
            UIPrintInteractionController    *printController = UIPrintInteractionController.sharedPrintController;
            printController.printingItem = [NSURL URLWithString:result];
    
            UIPrintInteractionCompletionHandler completionHandler = ^(UIPrintInteractionController *printController, BOOL completed, NSError *error)
            {
                if(!completed)
                {
                    if(error != nil) NSLog(@"Print failed: \nDomain: %@\nError code:%ld", error.domain, (long) error.code);
                    else             NSLog(@"Print canceled");
                }
                NSLog(@"Print completed!\nSelected Printer ID: %@", printController.printInfo.printerID);
            };
    
            if(printController != nil)
                [printController presentAnimated:YES completionHandler:completionHandler];
        }];
    }
    
    else
        NSLog(@"Unrecognized message received from web page");    }
    

NOTE: i use window.document.querySelector(\"iframe\") because our iframe does not have an id, otherwise I would have used window.getComponentByID. This important in case you have multiple iframes, which was not my case

I hope this can help you and others as well!

RodKik
  • 41
  • 4