I want to take a screenshot of a WKWebView
. I call the method drawViewHierarchyInRect
(with screen updates set to true
) right after the web view finished loading - for this purpose I observe the loading
property of the web view. However, I noticed, that at the time the web view notifies me that loading has finished, it doesn't actually display itself on the screen. That's why the screenshot is always only white. When I take the screenshot 0.5 seconds after loading (which is obviously too long) the screenshot shows the desired result. My problem is: I don't know when the web view actually displays itself on the screen, I could set the delay to 0.05 probably but I can't be a 100% sure it works every time. My question is therefore: How can I be notified when the web view is actually displayed an is ready for a screenshot.
Thanks in advance!
BTW: I'm using Swift 2.0 and iOS 9 with Xcode 7 (official release)
as I've just worked on this, let me know what I tried and how I figured it out. I tried a couple of things, first, a WKUserScript
let webViewUserScript = WKUserScript(
source: "window.onload = function() { webkit.messageHandlers.status.postMessage(\(wkwebView.hashValue)) }",
injectionTime: WKUserScriptInjectionTime.AtDocumentEnd,
forMainFrameOnly: true
)
on the "status" namespace. This theoretically waits for all contents to be loaded, and then calls the WKScriptMessageHandler
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage){ }
when registered via
wkwebView.configuration.userContentController.addScriptMessageHandler(self, name: "status")
where I thought everything would be ready. Worked sometimes, but not always.
As you, I've also tried adding a WKNavigationDelegate and using
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { }
Again, this didn't work. Also, adding an observer for the estimatedProgress value
wkwebView.addObserver(self, forKeyPath: "estimatedProgress", options: .New, context: nil)
and then trying to make the screenshot within
override func observeValueForKeyPath(keyPath: String?, ofObject: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) { }
didn't work.
However, what does work is to check upon the webView's content size regularly. I've did this within the userContentController function, which is called by the WKUserScript - but you can also do this within the didFinishNavigation function, and then simply change the function which is to be called again. Here the code:
let _contentSize = webview.scrollView.contentSize;
if (_contentSize.height == 0){
dispatch_after(createDispatchTime(0.01), dispatch_get_main_queue()) {
self.userContentController(userContentController, didReceiveScriptMessage: message)
}
return
}
This essentially checks on the contentSize height property and if it's zero, it will call the method again every 0.01 seconds until the property is set. Here are the functions I used for creating the screenshot
var view : UIView!
if self.useSnapShot {
// Use the snapshot function
view = webView.snapshotViewAfterScreenUpdates(true)
} else {
// Draw the view as UIImage
UIGraphicsBeginImageContextWithOptions(webView.frame.size, false, 0.0)
webView.drawViewHierarchyInRect(webView.frame, afterScreenUpdates: true)
let snapshot = UIGraphicsGetImageFromCurrentImageContext()
view = UIImageView(image: snapshot)
view.frame = webView.frame
}
I've tested it on both device and simulator and it works.
Edit
Here the function for creating the dispatch time
private func createDispatchTime(seconds: Double) -> dispatch_time_t{
let delay = seconds * Double(NSEC_PER_SEC)
return dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
}
Edit #2
I created a gist which shows an even better way I believe https://gist.github.com/christopherhelf/1640454bcace39a87c93#file-wkwebviewplus-swift
I replaced the setContentSize function of the webviews UIScrollview and notify the parent class that a change has been made.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With