UIWebView 如何获取网页加载进度
2016-04-22 本文已影响2073人
dadage456
当UIWebView加载网页时,可能引起多次请求(有重定向、或包含iframe引起多次请求,并多次执行UIWebView 委托事件)
根据NJKWebViewProgress开源库的分析,获取UIWebView的加载进度主要根据以下几点:
- 请求开始时,初始化进度值。
- 加载请求过程,计算进度值。
- 加载完成,结束进度。
一、请求开始时,初始化进度值
UIWebview加载一个网页时,在
webView:shouldStartLoadWithRequest:navigationType
委托方法中,初始化进度值。
初始化进度值的条件:
- 判断该请求是主请求
- 判断该请求是http、https、file协议
- 判断该请求不是跳转位置请求
//判断该请求是否为跳转位置链接
BOOL isFragmentJump = NO;
if (request.URL.fragment) {
NSString *nonFragmentURL = [request.URL.absoluteString stringByReplacingOccurrencesOfString:[@"#" stringByAppendingString:request.URL.fragment] withString:@""];
isFragmentJump = [nonFragmentURL isEqualToString:webView.request.URL.absoluteString];
}
//判断该请求是否为主请求链接
BOOL isTopLevelNavigation = [request.mainDocumentURL isEqual:request.URL];
//判断该请求是http、https、file协议
BOOL isHTTPOrLocalFile = [request.URL.scheme isEqualToString:@"http"] || [request.URL.scheme isEqualToString:@"https"] || [request.URL.scheme isEqualToString:@"file"];
if (!isFragmentJump && isHTTPOrLocalFile && isTopLevelNavigation) {
//满足条件,初始化计算进度数据
_maxLoadCount = _loadingCount = 0;
[self setProgress:0.0];
}
二、加载请求过程,计算进度值
-
通过
webViewDidStartLoad
委托方法,计算请求的次数totalCount. -
通过
webViewDidFinishLoad:
、webView:didFailLoadWithError:
委托方法,计算完成请求的次数completeCount,并根据“总的请求次数-totalCount”和“完成的请求次数-completeCount”计算出进度值。 -
进度值的计算方法(重点)
- (void)incrementProgress
{
float progress = self.progress;
float maxProgress = NJKInteractiveProgressValue;// 0.9f
float remainPercent = (float)_loadingCount / (float)_maxLoadCount;
float increment = (maxProgress - progress) * remainPercent;
progress += increment;
progress = fmin(progress, maxProgress);
[self setProgress:progress];
}
三、加载完成,结束进度
如何确定加载完成
- 在
webViewDidFinishLoad:
、webView:didFailLoadWithError:
委托方法中,获取“document.readyState”为“complete” - 在
webView:didFailLoadWithError:
委托方法中,error不为空 - 获取“document.readyState”为“interactive”的情况下,用js创建一个隐藏的iframe包含自定义的url。在
webView:shouldStartLoadWithRequest:navigationType:
委托方法中,识别该自定义的请求url,结束进度加载。
NSString *readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
BOOL interactive = [readyState isEqualToString:@"interactive"];
if (interactive) {
NSString *waitForCompleteJS = [NSString stringWithFormat:@"window.addEventListener('load',function() { var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = '%@://%@%@'; document.body.appendChild(iframe); }, false);", webView.request.mainDocumentURL.scheme, webView.request.mainDocumentURL.host, completeRPCURLPath];
[webView stringByEvaluatingJavaScriptFromString:waitForCompleteJS];
}
BOOL complete = [readyState isEqualToString:@"complete"];
if (complete) {
[self completeProgress];
}