如何准确判断 WebView 加载完成

原文

正常情况下我们把处理网页加载完毕的代码放在 - (void)webViewDidFinishLoad:(UIWebView *)webView里。但 WebViewDidFinishLoad 时网页真的加载完了吗?

官方文档并没有说明 WebViewDidFinishLoad 到底在什么时候被调用,但事实证明在某些情况下 WebViewDidFinishLoad 可能不是你想要的时机。

网页重定向

当网页重定向发生时,网址被重定向几次,WebViewDidFinishLoad 就会被调用几次。所以如果你只想在最后加载完成时调用某些代码,可以通过webView.isLoading来判断。当 WebViewDidFinishLoad 时如果 webView.isLoading == YES 那么说明网页可能发生了重定向。

1
2
3
4
5
- (void)webViewDidFinishLoad:(UIWebView *)webView {
     if  (!webView.isLoading) {
         [self webViewDidFinishLoadCompletely];
     }
}

加载内嵌资源

除了原生方法外,网页的 readyState 属性也可以返回当前加载状态,共有5种。

1.uninitialized : 还没开始加载

2.loading : 加载中

3.loaded : 加载完成

4.interactive : 结束渲染,用户已经可以与网页进行交互。但内嵌资源还在加载中

5.complete : 完全加载完成

WebViewDidFinishLoad 被调用时,readyState 可能处在 interactive 和 complete 两种状态。当我们需要对网页中的元素进行修改时,最好在 complete 状态进行,不然我们的修改可能被重置。例如百度登录页(http://wappass.baidu.com/passport)在iPad上打开时,WebViewDidFinishLoad 的 readyState 就是 interactive,这时假设想要在输入框里自动填写账号密码并修改输入框背景为黄色,我们的修改将会在 complete 状态时被重置。

为了解决这个问题,我们可以在 WebViewDidFinishLoad 判断 readyState 的状态,如果不是 complete,则重写 window.onload 或者 document.onreadystatechange 两个方法,他们都可以准确判断内嵌资源加载完毕的时机。然后通过 JSExport 回调 Objective-C 代码(如果是 WKWebView 则通过 MessageHandler 回调)。对 JSExport 还不熟悉可以参考这篇博客 来简单了解 JSExport 的使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
- (void)webViewDidStartLoad:(UIWebView *)webView {
     _jsContext = [_webView valueForKeyPath:@ "documentView.webView.mainFrame.javaScriptContext" ];
     _jsContext[@ "xfNewsContext" ] = _jsExport;
}
 
- (void)webViewDidFinishLoad:(UIWebView *)webView {
     if  (!webView.isLoading) {
         NSString *readyState = [webView stringByEvaluatingJavaScriptFromString:@ "document.readyState" ];
         BOOL complete = [readyState isEqualToString:@ "complete" ];
         if  (complete) {
             [self webViewDidFinishLoadCompletely];
         else  {
             NSString *jsString =
             @ "window.onload = function() {"
             @ "    xfNewsContext.onload();"
             @ "};"
             @ "document.onreadystatechange = function () {"
             @ "    if (document.readyState == \"complete\") {"
             @ "        xfNewsContext.documentReadyStateComplete();"
             @ "    }"
             @ "};" ;
             [_webView stringByEvaluatingJavaScriptFromString:jsString];
         }
         NSLog(@ "%@" , NSStringFromSelector(_cmd));
     }
}
 
- (void)onload {
     [self webViewDidFinishLoadCompletely];
     NSLog(@ "%@" , NSStringFromSelector(_cmd));
}
 
- (void)documentReadyStateComplete {
     [self webViewDidFinishLoadCompletely];
     NSLog(@ "%@" , NSStringFromSelector(_cmd));
}
 
- (void)webViewDidFinishLoadCompletely {
     [self displayContent];
}

在普通网页加载时打印结果是:

1.documentReadyStateComplete

2.onload

3.webViewDidFinishLoad:

而本例中打印结果则是:

1.webViewDidFinishLoad:

2.documentReadyStateComplete

3.onload

不管 webViewDidFinishLoad 在何时调用,webViewDidFinishLoadCompletely 都保证在加载完成的时候触发。

http://www.cocoachina.com/ios/20170314/18881.html

https://github.com/xiaofei86/XFBlogDemo


在网页本身存在约束情况下出现一直变大的BUG,iOS8.0后改用WKWebView

// 页面加载完调用

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation

{

    WeakSelf

    

    //获取内容实际高度(像素)@"document.getElementById(\"content\").offsetHeight;"

    [webView evaluateJavaScript:@"document.body.scrollHeight" completionHandler:^(id _Nullable result,NSError * _Nullable error) {

        // 此处js字符串采用scrollHeight而不是offsetHeight是因为后者并获取不到高度,看参考资料说是对于加载html字符串的情况下使用后者可以(@"document.getElementById(\"content\").offsetHeight;"),但如果是和我一样直接加载原站内容使用前者更合适

        //获取页面高度,并重置webview的frame

        NSLog(@"result此处就是实际高度  %@",result);

 

    }];

}


猜你喜欢

转载自blog.csdn.net/yyjjyysleep/article/details/70049805