首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS中WKWebView交互使用总结

iOS中WKWebView交互使用总结

作者头像
iOSSir
发布2019-06-14 11:20:30
2.8K0
发布2019-06-14 11:20:30
举报

前言

现在多数项目中会有使用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);
    }
    
}

到此,相关使用全部结束,希望喜欢活有用的话,能够点赞或者评论支持,谢谢。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOSSir 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 构建
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档