UIWebView: when did a page really finish loading?

后端 未结 11 1195
轮回少年
轮回少年 2020-11-29 00:09

I need to know, when a web page has completely been loaded by UIWebView. I mean, really completely, when all redirects are done and dynamically loaded content is ready. I tr

相关标签:
11条回答
  • 2020-11-29 00:40

    I have been looking for the answer for this, and I got this idea from Sebastian's question. Somehow it works for me, maybe it will for those who encounter this issue.

    I set a delegate to UIWebView and in the webViewDidFinishLoad, I detect if the webview has really finished loading by executing a Javascript.

    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        if ([[webView stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {
            // UIWebView object has fully loaded.
        }
    }
    
    0 讨论(0)
  • 2020-11-29 00:40

    My solution:

    - (void)webViewDidFinishLoad:(UIWebView *)webView
    {
        if (!webView.isLoading) {
            // Tada
        }
    }
    
    0 讨论(0)
  • 2020-11-29 00:43

    You could also use the accepted answer here: UIWebView - How to identify the "last" webViewDidFinishLoad message?...

    Basically, use the estimatedProgress property and when that reaches 100, the page has finished loading... See this guide for help.

    Although it does use a private framework, according to the guide there are some apps in the App Store that use it...

    0 讨论(0)
  • 2020-11-29 00:44

    WKWebView calls didFinish delegate when DOM's readyState is interactive, which is too early for webpages havy loaded with javascripts. We need to wait for complete state. I've created such code:

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

    and then:

    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
        }
    }
    
    0 讨论(0)
  • 2020-11-29 00:44

    Here's a simplified version of @jasonjwwilliams answer.

    #define JAVASCRIPT_TEST_VARIBLE @"window.IOSVariable"
    #define JAVASCRIPT_TEST_FUNCTION @"IOSFunction"
    #define LOAD_COMPLETED @"loaded"
    
    // Put this in your init method
    // In Javascript, first define the function, then attach it as a listener.
    _javascriptListener = [NSString stringWithFormat:
        @"function %@() {\
             %@ = '%@';\
        };\
        window.addEventListener(\"load\", %@, false);",
            JAVASCRIPT_TEST_FUNCTION, JAVASCRIPT_TEST_VARIBLE, LOAD_COMPLETED, JAVASCRIPT_TEST_FUNCTION];
    
    // Then use this:
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView;
    {
        // Only want to attach the listener and function once.
        if (_javascriptListener) {
            [_webView stringByEvaluatingJavaScriptFromString:_javascriptListener];
            _javascriptListener = nil;
        }
    
        if ([[webView stringByEvaluatingJavaScriptFromString:JAVASCRIPT_TEST_VARIBLE] isEqualToString:LOAD_COMPLETED]) {
            NSLog(@"UIWebView object has fully loaded.");
        }
    }
    
    0 讨论(0)
提交回复
热议问题