WKWebView notification when view is actually shown

心已入冬 提交于 2019-11-30 08:48:24

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.

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