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

时间:2012-06-12 11:47:42

标签: iphone uiwebview

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

是否有一个来自私人api的事件会给我带来结果?

11 个答案:

答案 0 :(得分:46)

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

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

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

答案 1 :(得分:22)

我的解决方案:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    if (!webView.isLoading) {
        // Tada
    }
}

答案 2 :(得分:10)

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

因此,我无法理解此链接中的答案是如何被接受的:webViewDidFinishLoad: Firing too soon? 因为调用任何 Javascript根本不告诉你任何事情(如果他们正在调用一些有趣的Javascript,例如监视dom,他们没有提到它,如果有的话因为它的重要性。)

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

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

如果网页不是您的网页,那么您可以将此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();

答案 3 :(得分:4)

Martin H的回答是正确的,但它仍然可以多次被解雇。

您需要做的是将Javascript onLoad侦听器添加到页面并跟踪您是否已插入侦听器:

#define kPageLoadedFunction @"page_loaded"
#define kPageLoadedStatusVar @"page_status"
#define kPageLoadedScheme @"pageloaded"

- (NSString*) javascriptOnLoadCompletionHandler {
    return [NSString stringWithFormat:@"var %1$@ = function() {window.location.href = '%2$@:' + window.location.href; window.%3$@ = 'loaded'}; \
    \
    if (window.attachEvent) {window.attachEvent('onload', %1$@);} \
    else if (window.addEventListener) {window.addEventListener('load', %1$@, false);} \
    else {document.addEventListener('load', %1$@, false);}",kPageLoadedFunction,kPageLoadedScheme,kPageLoadedStatusVar];
}

- (BOOL) javascriptPageLoaded:(UIWebView*)browser {
    NSString* page_status = [browser stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.%@",kPageLoadedStatusVar]];
    return [page_status isEqualToString:@"loaded"];
}


- (void)webViewDidFinishLoad:(UIWebView *)browser {

    if(!_js_load_indicator_inserted && ![self javascriptPageLoaded:browser]) {
        _js_load_indicator_inserted = YES;
        [browser stringByEvaluatingJavaScriptFromString:[self javascriptOnLoadCompletionHandler]];
    } else
        _js_load_indicator_inserted = NO;
}

页面加载完成后,Javascript侦听器将触发URL pageloaded:<URL that actually finished>的新页面加载。然后,您只需更新shouldStartLoadWithRequest即可查找该URL方案:

- (BOOL)webView:(UIWebView *)browser shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if([request.URL.scheme isEqualToString:kPageLoadedScheme]){
        _js_load_indicator_inserted = NO;
        NSString* loaded_url = [request.URL absoluteString];
        loaded_url = [loaded_url substringFromIndex:[loaded_url rangeOfString:@":"].location+1];

        <DO STUFF THAT SHOULD HAPPEN WHEN THE PAGE LOAD FINISHES.>

        return NO;
    }
}

答案 4 :(得分:3)

您也可以在此处使用接受的答案:UIWebView - How to identify the "last" webViewDidFinishLoad message? ...

基本上,使用estimatedProgress属性,当达到100时,页面已完成加载...请参阅this guide寻求帮助。

虽然它确实使用私有框架,但根据the guide,App Store中有一些应用程序使用它...

答案 5 :(得分:2)

使您的View Controller成为UIWebView的委托。 (您可以在Interface Builder中执行此操作,也可以在viewDidLoad方法中使用此代码:

[self.myWebView setDelegate:self];

然后使用接受的答案中描述的方法:webViewDidFinishLoad: Firing too soon?

代码:

-(void) webViewDidFinishLoad:(UIWebView *)webView
{
    NSString *javaScript = @"function myFunction(){return 1+1;}";
    [webView stringByEvaluatingJavaScriptFromString:javaScript];

    //Has fully loaded, do whatever you want here
}

答案 6 :(得分:2)

当DOM的readyState为didFinish时,WKWebView调用interactive委托,这对于加载javascripts的网页havy来说还为时过早。我们需要等待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()
            }
        }
    }
}

然后:

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

答案 7 :(得分:1)

感谢JavaScript,新资源和新图形可以永久加载 - 确定何时加载“完成”,对于一个充分反复的页面,将相当于halting problem的解决方案。你真的不知道什么时候加载页面。

如果可以,只需显示页面或其图像,并使用webViewDidLoad更新图像,并让用户决定何时切断 - 或不切断。

答案 8 :(得分:0)

这是@jasonjwwilliams答案的简化版。

#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.");
    }
}

答案 9 :(得分:0)

由于所有这些答案都比较老旧,webViewDidFinishLoad已被贬值,后来又让我头疼的是,让我解释一下如何确切地知道网页何时快速完成了在Webkit(webview)中的加载4.2

class ViewController: UIViewController, WKNavigationDelegate {

    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!

    override func viewDidLoad() {

        webView.navigationDelegate = self

    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

    // it is done loading, do something!

    }

}

我当然会缺少其他一些默认代码,因此您要添加到现有功能中。

答案 10 :(得分:-1)

尝试类似的东西 https://github.com/Buza/uiwebview-load-completion-tracker 这有助于我加载Google街景

相关问题