实际显示视图时的 WKWebView 通知
Posted
技术标签:
【中文标题】实际显示视图时的 WKWebView 通知【英文标题】:WKWebView notification when view is actually shown 【发布时间】:2015-09-18 19:55:35 【问题描述】:我想截取WKWebView
的屏幕截图。在 Web 视图完成加载后,我立即调用方法 drawViewHierarchyInRect
(屏幕更新设置为 true
)——为此,我观察了 Web 视图的 loading
属性。但是,我注意到,当 web 视图通知我加载完成时,它实际上并没有在屏幕上显示自己。这就是为什么屏幕截图总是只有白色的。当我在加载后 0.5 秒截取屏幕截图时(显然太长了),屏幕截图显示了所需的结果。我的问题是:我不知道网络视图何时实际显示在屏幕上,我可以将延迟设置为 0.05,但我不能 100% 确定它每次都能正常工作。因此,我的问题是:如何在实际显示 Web 视图并准备好截屏时通知我。
提前致谢!
顺便说一句:我正在使用 Swift 2.0 和 ios 9 以及 Xcode 7(正式版本)
【问题讨论】:
【参考方案1】:因为我刚刚在这方面工作,所以请告诉我我尝试了什么以及我是如何解决的。我尝试了几件事,首先,一个 WKUserScript
let webViewUserScript = WKUserScript(
source: "window.onload = function() webkit.messageHandlers.status.postMessage(\(wkwebView.hashValue)) ",
injectionTime: WKUserScriptInjectionTime.AtDocumentEnd,
forMainFrameOnly: true
)
在“状态”命名空间上。这个理论上是等待所有内容加载完毕,然后调用WKScriptMessageHandler
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage)
通过以下方式注册时
wkwebView.configuration.userContentController.addScriptMessageHandler(self, name: "status")
我以为一切都准备好了。有时有效,但并非总是如此。
和你一样,我也尝试过添加 WKNavigationDelegate 并使用
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!)
同样,这没有用。另外,为estimatedProgress 值添加一个观察者
wkwebView.addObserver(self, forKeyPath: "estimatedProgress", options: .New, context: nil)
然后尝试在
内制作屏幕截图override func observeValueForKeyPath(keyPath: String?, ofObject: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>)
没用。
但是,有效的是定期检查 webView 的内容大小。我在由 WKUserScript 调用的 userContentController 函数中执行了此操作 - 但您也可以在 didFinishNavigation 函数中执行此操作,然后只需更改要再次调用的函数。代码如下:
let _contentSize = webview.scrollView.contentSize;
if (_contentSize.height == 0)
dispatch_after(createDispatchTime(0.01), dispatch_get_main_queue())
self.userContentController(userContentController, didReceiveScriptMessage: message)
return
这实质上是检查 contentSize 高度属性,如果它为零,它将每 0.01 秒再次调用该方法,直到设置该属性为止。这是我用于创建屏幕截图的函数
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
我已经在设备和模拟器上对其进行了测试,并且可以正常工作。
编辑
这里是创建调度时间的函数
private func createDispatchTime(seconds: Double) -> dispatch_time_t
let delay = seconds * Double(NSEC_PER_SEC)
return dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
编辑#2
我创建了一个要点,它展示了我认为更好的方式 https://gist.github.com/christopherhelf/1640454bcace39a87c93#file-wkwebviewplus-swift
我替换了 webviews UIScrollview 的 setContentSize 函数,并通知父类发生了变化。
【讨论】:
我尝试了你的 swizzle 方法实现。甚至在 webView 实际呈现非常快的网页(如 Wikipedia)之前,它也会被触发 您还可以观察 contentSize 属性,而不是触发延迟函数或覆盖 setContentSize。这似乎适用于检测大小变化,但它似乎也可以在常规动画周期中触发,尽管没有变化。 这绝对是最好的答案之一。 iOS WebView didFinishLoad 在加载主要内容时调用,但 iOS WebKit 没有任何可靠的 javascript 控件。问题就在这里。主要内容已加载,但一些 javascript 仍在工作(加载、重定向等)并且 WebKit 无法跟踪它。解决方案是控制 javascript Web 内容并在加载所有数据时调用脚本消息。我正在使用 [github.com/marcuswestin/WebViewJavascriptBridge] (WebViewJavascriptBridge)。 现在有一个isLoading()
方法返回一个布尔值,您可以检查它而不是检查 contentsize 高度。
@peacer212 可以找到 avplayer 在 WKWebView 中显示的时间,如果有任何解决方案,请参见 ***.com/questions/55377677/…以上是关于实际显示视图时的 WKWebView 通知的主要内容,如果未能解决你的问题,请参考以下文章