在开发过程中,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"]; } }
这样就实现了对加载进度的显示了。