前言
现在多数项目中会有使用webView的情况,过去往往使用UIWebView解决问题,但是由于其各种不便,给开发者带来了很多麻烦。现在项目中有所使用,所以写一篇总结,方便以后用到了查找和使用也为了方便其他同行。
正文
基础使用
构建和配置
WKWebView是继承自UIView的,因此构建方式还是很老套的,通常
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
这个方法就够用了,第一个参数不多说,按照通常的使用就可以,第二个参数是对webView的配置对象,里面有很多属性可以使用,但是这里我只进行最简单使用的说明。
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init];
configuration.preferences.minimumFontSize = 10;//设置最小字体
configuration.preferences.javaScriptEnabled = YES;//是否可以使用JavaScript
configuration.preferences.javaScriptCanOpenWindowsAutomatically = NO;//JS是否可以自动打开页面
以上配置就足够正常使用,其他的如果项目还有需要,请自己根据需要添加。然后是对WKWebView的基本设置,
self.webView.scrollView.bounces = NO;
self.webView.navigationDelegate = self;
设置了取消弹性和代理,需要说明的是由于我们使用的是需要和JS进行交互的webView,所以需要在ViewController中声明两个代理WKNavigationDelegate,WKScriptMessageHandler,前者是用来处理webView加载视图的各种情况的,后者是主要用来处理交互事件的。最后通过addSubView添加视图到父视图上面就可以了,这个时候应该是没有加载任何页面的webView。而主要功能加载web网页,需要使用以下方法:
@property (nonatomic, strong) NSURLRequest *resetUrlRequest;
self.resetUrlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"你所需要加载的网址"]];
当然考虑项目中可能会对网址进行拼接,如拼接token,因此强烈建议,将后面的URL构建部分挪到顶上分出来写。
基本代理相关
常用的有:
//开始加载
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
//加载完成
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
//页面跳转失败
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
//加载报错,通常来说如果页面出现不存在等问题,会走这里,如果需要对空白页面进行处理,在这里处理
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
//请求之前,决定是否要跳转:用户点击网页上的链接,需要打开新页面时,将先调用这个方法。
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
//允许页面跳转
// NSLog(@"%@=========tw============",navigationAction.request.URL);
//如果是跳转一个新页面
if (navigationAction.targetFrame == nil) {
[webView loadRequest:navigationAction.request];
}
decisionHandler(WKNavigationActionPolicyAllow);
}
//接收到相应数据后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
if (((NSHTTPURLResponse *)navigationResponse.response).statusCode == 200) {
decisionHandler (WKNavigationResponsePolicyAllow);
}else {
decisionHandler(WKNavigationResponsePolicyCancel);
}
}
还有这些可能需要的
// 主机地址被重定向时调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation;
// 如果需要证书验证,与使用AFN进行HTTPS证书验证是一样的
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler;
//9.0才能使用,web内容处理中断时会触发
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0);
到此,基础的使用结束。
限制用户选择以及长按操作
有时候,我们会遇到一个比较头疼的问题,我们不想让用户长按选择或者有弹窗,那么这时我们需要添加两行代码来禁止这一系列行为。
//WKWebview 禁止长按(超链接、图片、文本...)弹出效果
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil];
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';" completionHandler:nil];
值得注意的是,这里其实是通过调用webView直接使用JS代码实现的操作,如果有需要还可以实现别的功能,而且这个方法最后有一个执行完毕之后的block,可以实现很多操作。
添加进度条
@property (nonatomic, strong)UIProgressView *progressView;
//添加进度条
self.progressView = [[UIProgressView alloc]initWithFrame:CGRectMake(0, 2, self.view.frame.size.width, self.view.frame.size.height)];
self.progressView.tintColor = UIColorWithRGB(254, 79, 109);
[self.webView addSubview:self.progressView];
[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
监听
#pragma mark - 进度条
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) {
[self.progressView setAlpha:1.0f];
[self.progressView setProgress:self.webView.estimatedProgress animated:YES];
if (self.webView.estimatedProgress >= 1.0f) {
[UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.progressView setAlpha:0.0f];
} completion:^(BOOL finished) {
[self.progressView setProgress:0.0f animated:YES];
self.progressView.hidden = YES;
}];
}
}else{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
代理中操作
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
self.progressView.hidden = NO;
self.progressView.transform = CGAffineTransformMakeScale(1.0, 1.5);
[self.view bringSubviewToFront:self.progressView]; // 将progress放到最前面
}
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
self.progressView.hidden = YES;
self.title = self.webView.title;
//WKWebview 禁止长按(超链接、图片、文本...)弹出效果
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil];
// [self.webView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';" completionHandler:nil];
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
NSLog(@"%@---------------",error);
self.progressView.hidden = YES;
}
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
NSLog(@"%@-------------------",error);
//加载本地的一个空页面的操作
//[self sk_loadErrorPage];
}
返回上级以及popViewController
if ([[self.webView.backForwardList currentItem].title isEqualToString:@"首页"]) {
[self.navigationController popViewControllerAnimated:YES];
}
if ([self.webView canGoBack]) {
//控制订单列表中的较多界面折回
if ([[self.webView.backForwardList currentItem].title isEqualToString:@"订单列表"] &&
[[self.webView.backForwardList backItem].title isEqualToString:@"订单列表"]) {
[self.webView goToBackForwardListItem:[self.webView.backForwardList backList].firstObject];
}else{
[self.webView goBack];
}
}else{
[self.navigationController popViewControllerAnimated:YES];
}
可以对H5页面的标题进行判断来决定是否跳转。
重点:JS交互
WKWebView的交互方法和之前的UIWebView其实本质上没有什么太大的差别,都是通过发送方法名找到对应的方法执行对应的操作。我的具体操作如下:
-(void)viewWillAppear:(BOOL)animated{
// self.navigationController.navigationBar.hidden = NO;
if (self.webView) {
if (self.webView.configuration.userContentController.userScripts.count>0) {
//移除所有的监听
[self removeAllScriptMsgHandle];
}
//对JS调用的方法进行监听,最好集中处理
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"mjxLogin"];
}
}
-(void)viewWillDisappear:(BOOL)animated{
[self removeAllScriptMsgHandle];
}
- (void)dealloc{
//移除监听和代理
[self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
[self.webView setNavigationDelegate:nil];
[self.webView setUIDelegate:nil];
}
-(void)removeAllScriptMsgHandle{
//移除监听,不移除一定会报错
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"mjxLogin"];
}
对监听的处理的代理
//用来接收js调用本地方法的拦截器
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
// NSLog(@"%@------mes------",message.body);
//分享,多参数的情况
if ([message.name isEqualToString:@"mjxShare"]) {
NSDictionary *messageDic = message.body;
[self shareGoodsWithTitle:messageDic[@"title"] withContent:messageDic[@"content"] withUrl:messageDic[@"url"] withImage:messageDic[@"img"]];
}
//申请试用,带一个参数的情况
if ([message.name isEqualToString:@"mjxApply"]) {
NSDictionary *messageDic = message.body;
[self requestApplyGoods:messageDic[@"trade_sn"]];
}
//弹出错误信息
if ([message.name isEqualToString:@"errorAlert"]) {
[SKHUD showErrorWithStatus:message.body];
}
//保存二维码
if ([message.name isEqualToString:@"codeImg"]) {
[SVProgressHUD show];
NSDictionary *messageDic = message.body;
NSURL *url = [NSURL URLWithString:messageDic[@"codeImgUrl"]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img;
img = [UIImage imageWithData:data];
UIImageWriteToSavedPhotosAlbum( img, self,@selector(imageSavedToPhotosAlbum:didFinishSavingWithError:contextInfo:) , NULL);
}
}
到此,相关使用全部结束,希望喜欢活有用的话,能够点赞或者评论支持,谢谢。