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

大兔子大兔子 提交于 2019-12-28 11:51:50

问题


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....

Note: Also, I believe that the root cause of this issue is what also makes it impossible to save ALL content of the WKWebView as an image. There used to be some techniques that one could use with a UIWebView to save the entire on and offscreen content of WebView to an image. I've not yet found a working solution.


回答1:


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)
        }
    }
}



回答2:


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.




回答3:


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.




回答4:


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)


来源:https://stackoverflow.com/questions/33319295/how-does-one-print-all-wkwebview-on-and-offscreen-content-osx-and-ios

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