在开发过程中,iOS 中实现加载 web 页面主要有两种控件,UIWebView 和 WKWebview,两种控件对应具体的实现方法不同。WKWebView是苹果公司在iOS8系统推出的,这里主要概述WebKit中更新的WKWebView控件的新特性与使用方法,以及小编在开发过程中踩的坑。
一、相比于UIWebView的优势:
- 在性能、稳定性、占用内存方面有很大提升;
- 允许JavaScript的Nitro库加载并使用(UIWebView中限制)
- 增加加载进度属性:estimatedProgress,不用在自己写假进度条了
- 支持了更多的HTML的属性
二、WKWebview的常用属性
@property (nullable, nonatomic, readonly, copy) NSString *title;
@property (nullable, nonatomic, readonly, copy) NSURL *URL;
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
//加载进度
@property (nonatomic, readonly) double estimatedProgress;
三、WKWebview的常用方法
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL API_AVAILABLE(macosx(10.11), ios(9.0));
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL API_AVAILABLE(macosx(10.11), ios(9.0));
四、WKNavigationDelegate代理的方法
#pragma mark - WKNavigationDelegate
/* 页面开始加载 */
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
NSLog(@"页面开始加载");
}
/* 开始返回内容 */
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
NSLog(@"开始返回内容");
}
/* 页面加载完成 */
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSLog(@"页面加载完成");
}
/* 页面加载失败 */
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{
NSLog(@"页面加载失败");
}
/* 在发送请求之前,决定是否跳转 */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
//允许跳转
decisionHandler(WKNavigationActionPolicyAllow);
//不允许跳转
//decisionHandler(WKNavigationActionPolicyCancel);
}
/* 在收到响应后,决定是否跳转 */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSLog(@"%@",navigationResponse.response.URL.absoluteString);
//允许跳转
decisionHandler(WKNavigationResponsePolicyAllow);
//不允许跳转
//decisionHandler(WKNavigationResponsePolicyCancel);
}
五、小编的实例Demo
首先遵守协议:
<WKUIDelegate, WKNavigationDelegate>
其次创建一个WKWebView
#pragma mark - 创建webView
- (void)createWebView{
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.selectionGranularity = WKSelectionGranularityDynamic;
config.allowsInlineMediaPlayback = YES;
WKPreferences *preferences = [WKPreferences new];
//是否支持JavaScript
preferences.javaScriptEnabled = YES;
//不通过用户交互,是否可以打开窗口
preferences.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preferences;
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.webView];
/* 加载服务器url的方法*/
NSString *url = @"https://www.baidu.com";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[self.webView loadRequest:request];
self.webView.navigationDelegate = self;
self.webView.UIDelegate = self;
}
这样就可以在webView中正常加载百度首页了。
不过,在开发中有时遇到网络不佳的时候,想给用户显示一个加载网页的进度,加载完成后,想再navigation中显示网页的标题,就需要对WKWebView的"estimatedProgress"和
"title"进行监听了。
首先创建一个进度条
- (void)createProgressView{
self.progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 88, SCREEN_WIDTH, 2)];
self.progressView.progressViewStyle = UIProgressViewStyleDefault;
self.progressView.tintColor = [UIColor blueColor];
self.progressView.trackTintColor = [UIColor greenColor];
[self.view addSubview:self.progressView];
}
让webView对“进度”和“标题”进行监听
[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
[self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
最后,完成对KVO的回调
#pragma mark - KVO回馈
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"estimatedProgress"]) {
double progress = _webView.estimatedProgress;
self.progressView.alpha = 1.0f;
[self.progressView setProgress:progress animated:YES];
if(progress >= 1){
[UIView animateWithDuration:0.25 delay:0.25 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.progressView.alpha = 0.0f;
} completion:^(BOOL finished) {
[self.progressView setProgress:0.0f animated:NO];
}];
}
if ([change[@"new"] floatValue] <[change[@"old"] floatValue]) {
return;
}
if ([change[@"new"]floatValue] == 1.0) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});
}
}
else if ([keyPath isEqualToString:@"title"]){
self.title = change[@"new"];
}
}
这样就实现了对加载进度的显示了。