1
import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate{
    
    @IBOutlet weak var webVw: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Load a URL
        if let url = URL(string: "https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_print") {
            let request = URLRequest(url: url)
            webVw.load(request)
        }
    }
}

enter image description here

"Print this page" button not showing anything but loading the same url in safari and clicking the same button showing the print page option.

enter image description here

Ben Rockey
  • 920
  • 6
  • 23

1 Answers1

2

Sorry I misunderstood you earlier.

So, we need a workaround. We'll employ JavaScript injection using WKUserScript to catch the window.print() function call within the WKWebView. This is possible due to the interoperability of Swift with JavaScript within WKWebView.

Now, let's dissect the code:

  1. Creating the print script: We construct a WKUserScript object with a JavaScript code snippet that redefines the window.print() function. In our version, it sends a message using the WebKit message handler, window.webkit.messageHandlers.printHandler.postMessage('print').
let printScript = WKUserScript(
    source: "window.print = function(){window.webkit.messageHandlers.printHandler.postMessage('print')};",
    injectionTime: .atDocumentEnd,
    forMainFrameOnly: true
)
  1. Injecting the script: We need to inject this script into the WKWebView via its configuration, which contains a user content controller. We also add a message handler for 'printHandler', which is going to catch the message we've set up in our JavaScript.
let config = WKWebViewConfiguration()
config.userContentController.addUserScript(printScript)
config.userContentController.add(self, name: "printHandler")
  1. Setting up WKWebView: Now, initialize the WKWebView with the configuration. However, the earlier warning arises due to the WebView being assigned to a weak property, which leads to its immediate deallocation. Hence, we're going to leverage the already set WKWebView from the storyboard, which is managed by ARC.

  2. URL Loading: Here, we load the URL as usual.

  3. Handling the script message: WKScriptMessageHandler protocol implementation helps us handle the receipt of the print message. When we receive the "printHandler" message, we call a native function printPage().

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    if message.name == "printHandler" {
        printPage()
    }
}
  1. Print Functionality: We use the UIPrintInteractionController to present the system print dialog in the printPage() function.
private func printPage() {
    let printInfo = UIPrintInfo(dictionary: nil)
    printInfo.jobName = webVw.url?.absoluteString ?? "Document"
    printInfo.outputType = .general

    let printController = UIPrintInteractionController.shared
    printController.printInfo = printInfo
    printController.printFormatter = webVw.viewPrintFormatter()

    printController.present(animated: true, completionHandler: nil)
}

This solution is somewhat a bridge between the webpage's JavaScript environment and our native code.

Now, if window.print() function isn't being called as expected, you should inspect the JavaScript code running on the webpage. It's possible that the window.print() function is being defined after the page load, overriding your custom function. You can use polling to consistently check for the definition of window.print() function, and replace it with your custom function if it's been overwritten.

Finally, this solution assumes that the webpage is executing the window.print() function to initiate printing. If the page uses a different mechanism, this solution won't work, and we'd need to inspect the page's JavaScript further.

KFDoom
  • 772
  • 1
  • 6
  • 19
  • still its not working. – Ben Rockey Aug 03 '23 at 03:41
  • @BenRockey Is it important that the print button actually is in the web page? Could it be in the native UI outside of the webview? I think KFDoom is correct that you need to print with native code. alert(), confirm(), prompt() and other javascript function is the same, at least in the old UIWebView. – Johan Nordberg Aug 03 '23 at 06:21
  • @Johan Nordberg yes because its a web page showing after booking process. – Ben Rockey Aug 03 '23 at 06:47
  • @BenRockey If you want to keep the print functionality within the web page and the JavaScript window.print() function is not working with WKWebView, you can use another workaround. You can replace the JavaScript window.print() function with your own function that sends a message to your native code. This will trigger the native print dialog. The idea is the same as before, but instead of catching the `window.print()` function, you're now replacing it with your own function. – KFDoom Aug 03 '23 at 10:47
  • @BenRockey try this and let me know how it goes https://gist.github.com/Jxrgxn/f3530cce401f33628c97b48853078c86 – KFDoom Aug 03 '23 at 10:48
  • webVw = WKWebView(frame: .zero, configuration: config) this line shows a warning Instance will be immediately deallocated because property 'webVw' is 'weak' and nothing displays on screen – Ben Rockey Aug 03 '23 at 12:16
  • webVw.configuration.userContentController.addUserScript(printScript) webVw.configuration.userContentController.add(self, name: "printHandler") fixed by adding this but not working print – Ben Rockey Aug 03 '23 at 12:29
  • The problem at hand is the handling of JavaScript's window.print() functionality in WKWebView. WKWebView doesn't support it out-of-the-box, unlike the Safari web browser, where the print dialog box appears automatically on calling window.print(). So, we need a workaround. We'll employ JavaScript injection using WKUserScript to catch the window.print() function call within the WKWebView. This is possible due to the interoperability of Swift with JavaScript within WKWebView. – KFDoom Aug 03 '23 at 15:29
  • @BenRockey I have time this weekend to play with this if you stil need help – KFDoom Aug 04 '23 at 22:19