UIWebView:什么时候页面真的完成加载?

Seb*_*ian 28 iphone uiwebview

我需要知道,当UIWebView完全加载网页时.我的意思是,非常完全,当所有重定向完成并且动态加载的内容准备就绪时.我尝试注入javascript(查询document.readyState == 'complete'),但这似乎不太可靠.

也许,来自私人api的事件会给我带来结果吗?

Fed*_*lau 46

我一直在寻找答案,我从塞巴斯蒂安的问题中得到了这个想法.不知何故,它对我有用,也许对那些遇到这个问题的人来说.

我将一个委托设置为UIWebView,在webViewDidFinishLoad中,我通过执行Javascript来检测webview是否真正完成了加载.

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    if ([[webView stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {
        // UIWebView object has fully loaded.
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 根据我的理解,webViewDidFinishLoad仅在每次页面加载时被调用一次.因此,当UIWebView认为加载完成时,document.readyState不是"完整".不会再次调用此委托方法.所以基本上我们在这个if块中获取死代码. (21认同)
  • 如果你的答案有效,那么看起来我已经看到了堆栈溢出的最佳答案.但是在这里的3年里没有人投票给这个答案,所以我怀疑......我会试一试. (2认同)
  • 对于所有六个'OnPageFinished'调用,状态已完成.所以它对我来说不适合作为检测最后一个页面加载事件的方法. (2认同)

tgf*_*tgf 22

我的解决方案

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    if (!webView.isLoading) {
        // Tada
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 加载大量`iframe或发生错误时,`UIWebView.isLoading`有时不可靠. (2认同)

Gru*_*kes 10

UIWebView执行Javascript的能力与页面是否已加载无关.它可能会使用stringByEvaluatingJavaScriptFromString:在您首先调用在UIWebView中加载页面之前执行Javascript,或者根本不加载页面.

因此,我无法理解这个链接中的答案是如何被接受的:webViewDidFinishLoad:过早开火? 因为调用任何 Javascript都没有告诉你任何东西(如果他们正在调用一些有趣的Javascript,例如监视dom,他们没有提到它,如果有的话,因为它很重要).

你可以调用一些Javascript,例如,检查dom的状态或加载的页面的状态,并将其报告回调用代码,但是如果它报告页面尚未加载,那么你做了什么? - 稍后你将不得不再次调用它,但是稍后,多久,何时,何地,多久......,轮询通常永远不是一个好的解决方案.

唯一的方法是知道页面何时完全加载并且准确并且能够确切地知道它自己在做什么 - 将JavaScript事件监听器附加到正在加载的页面中并让它们调用你的shouldStartLoadWithRequest:使用一些专有的网址.例如,你可以创建一个JS函数来监听窗口加载或dom ready事件等,具体取决于你是否需要知道页面何时加载,或者只是dom已经加载等等.这取决于你的需要.

如果网页不是您的网页,那么您可以将此javascript放入文件中并将其插入到您加载的每个页面中.

如何创建javascript事件监听器是标准的javascript,没有什么特别与iOS有关,例如这里是用于检测dom何时加载的形式的JavaScript,可以从UIWebView中注入到加载页面然后导致对shouldStartLoadWithRequest的调用:(这将调用shouldStartLoadWithRequestwhen:dom已完成loadeding,这是在显示整页内容之前,检测到这只是更改事件监听器).

var script = document.createElement('script');  
script.type = 'text/javascript';  
script.text = function DOMReady() {
    document.location.href = "mydomain://DOMIsReady";
}

function addScript()
{        
    document.getElementsByTagName('head')[0].appendChild(script);
    document.addEventListener('DOMContentLoaded', DOMReady, false);
}
addScript();
Run Code Online (Sandbox Code Playgroud)


kon*_*owy 5

didFinish当 DOM 的 readState 为 时,WKWebView 会调用delegate interactive,这对于加载了 javascript 的网页来说还为时过早。我们需要等待complete状态。我创建了这样的代码:

func waitUntilFullyLoaded(_ completionHandler: @escaping () -> Void) {
    webView.evaluateJavaScript("document.readyState === 'complete'") { (evaluation, _) in
        if let fullyLoaded = evaluation as? Bool {
            if !fullyLoaded {
                DDLogInfo("Webview not fully loaded yet...")
                DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
                    self.waitUntilFullyLoaded(completionHandler)
                })
            } else {
                DDLogInfo("Webview fully loaded!")
                completionHandler()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

进而:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    DDLogInfo("Webview claims that is fully loaded")

    waitUntilFullyLoaded { [weak self] in
        guard let unwrappedSelf = self else { return }

        unwrappedSelf.activityIndicator?.stopAnimating()
        unwrappedSelf.isFullLoaded = true
    }
}
Run Code Online (Sandbox Code Playgroud)