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

淺唱寂寞╮ 提交于 2019-11-28 06:23:43

The solution I use, is to instantiate a good old WebView object, and use the print method of that object.

class WebPrinter: NSObject, WebFrameLoadDelegate {

    let window: NSWindow
    var printView: WebView?
    let printInfo = NSPrintInfo.shared

    init(window: NSWindow) {
        self.window = window
        printInfo.topMargin = 30
        printInfo.bottomMargin = 15
        printInfo.rightMargin = 0
        printInfo.leftMargin = 0
    }

    func printHtml(_ html: String) {
        let printViewFrame = NSMakeRect(0, 0, printInfo.paperSize.width, printInfo.paperSize.height)
        printView = WebView(frame: printViewFrame, frameName: "printFrame", groupName: "printGroup")
        printView!.shouldUpdateWhileOffscreen = true
        printView!.frameLoadDelegate = self
        printView!.mainFrame.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
    }

    func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {
        if sender.isLoading {
            return
        }
        if frame != sender.mainFrame {
            return
        }
        if sender.stringByEvaluatingJavaScript(from: "document.readyState") == "complete" {
            sender.frameLoadDelegate = nil
            let printOperation = NSPrintOperation(view: frame.frameView.documentView, printInfo: printInfo)
            printOperation.runModal(for: window, delegate: window, didRun: nil, contextInfo: nil)
        }
    }
}

This isn't the correct answer because Apple needs to supply the correct answer with a working print method or .evaluateJavaScript("window.print()", completionHandler: nil)

But I have a stupid solution that "works" for me and perhaps it will help other people with a work around until then.

Step 1: Grab the HTML and fixup the <body> tag with <body onload='window.print()'>. If you are fetching the html from someplace and not loading your own, you'll want to use some regular expressions. I won't go into that.

Step 2: Save the html in a file someplace and keep the full path in a variable. In my example: filename

Step 3: Wire your print button to this code:

RunCommand(command: "/usr/bin/open \(filename)")

See code for RunCommand below. This leaves a dumb safari window laying around, but it makes it possible to get something printed without saving to a file and then remembering where you stuck it so you can open it with Safari on your own to do the printing.

func RunCommand(command: String)  -> (success: Bool, result: String) {
        let cc = command.components(separatedBy: " ")
        let process = Process()
        process.launchPath = cc[0]
        var cp: [String] = []
        for i in (1..<cc.count) {
            cp.append(cc[i])
        }
        process.arguments = cp
        let pipe = Pipe()
        process.standardOutput = pipe
        process.launch()
        let data = pipe.fileHandleForReading.readDataToEndOfFile()
        if (data.count > 0) {
            let output = String(data: data, encoding: String.Encoding.utf8)
            // let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
            return (success: true, result: output!)
        }
        return (success: true, result: "")

    }

It would be really nice if Apple could fix this. I have an in-house app that does all its reporting in HTML and reports are something you kind of want to print.

I have exhausted every possible way to print the WKWebView directly with no success. The only workaround I can think of would be to convert the web page to a PDF object and then print said object. I will update with code if I get the workaround to work.

In iOS, I pass UIView.viewPrintFormatter() to UIActivityViewController to allow users to print everything

let myShare = [webView.viewPrintFormatter()]
let avc = UIActivityViewController(activityItems: myShare, applicationActivities: nil)

present(avc, animated: true, completion: nil)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!