iOS中WKWebView交互使用总结

2019-06-14 11:20:30 浏览数 (1)

前言

现在多数项目中会有使用webView的情况,过去往往使用UIWebView解决问题,但是由于其各种不便,给开发者带来了很多麻烦。现在项目中有所使用,所以写一篇总结,方便以后用到了查找和使用也为了方便其他同行。

正文

基础使用


构建和配置

WKWebView是继承自UIView的,因此构建方式还是很老套的,通常

代码语言:javascript复制
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration

这个方法就够用了,第一个参数不多说,按照通常的使用就可以,第二个参数是对webView的配置对象,里面有很多属性可以使用,但是这里我只进行最简单使用的说明。

代码语言:javascript复制
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init];
configuration.preferences.minimumFontSize = 10;//设置最小字体
configuration.preferences.javaScriptEnabled = YES;//是否可以使用JavaScript
configuration.preferences.javaScriptCanOpenWindowsAutomatically = NO;//JS是否可以自动打开页面

以上配置就足够正常使用,其他的如果项目还有需要,请自己根据需要添加。然后是对WKWebView的基本设置,

代码语言:javascript复制
self.webView.scrollView.bounces = NO;
self.webView.navigationDelegate = self;

设置了取消弹性和代理,需要说明的是由于我们使用的是需要和JS进行交互的webView,所以需要在ViewController中声明两个代理WKNavigationDelegate,WKScriptMessageHandler,前者是用来处理webView加载视图的各种情况的,后者是主要用来处理交互事件的。最后通过addSubView添加视图到父视图上面就可以了,这个时候应该是没有加载任何页面的webView。而主要功能加载web网页,需要使用以下方法:

代码语言:javascript复制
@property (nonatomic, strong) NSURLRequest *resetUrlRequest;
self.resetUrlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"你所需要加载的网址"]];

当然考虑项目中可能会对网址进行拼接,如拼接token,因此强烈建议,将后面的URL构建部分挪到顶上分出来写。

基本代理相关

常用的有:

代码语言:javascript复制
//开始加载
-(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);
    }
}

还有这些可能需要的

代码语言:javascript复制
// 主机地址被重定向时调用
- (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);

到此,基础的使用结束。

限制用户选择以及长按操作


有时候,我们会遇到一个比较头疼的问题,我们不想让用户长按选择或者有弹窗,那么这时我们需要添加两行代码来禁止这一系列行为。

代码语言:javascript复制
//WKWebview 禁止长按(超链接、图片、文本...)弹出效果
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';" completionHandler:nil];
[self.webView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';" completionHandler:nil];

值得注意的是,这里其实是通过调用webView直接使用JS代码实现的操作,如果有需要还可以实现别的功能,而且这个方法最后有一个执行完毕之后的block,可以实现很多操作。

添加进度条


构建

代码语言:javascript复制
@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];

监听

代码语言:javascript复制
#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];
    }
}

代理中操作

代码语言:javascript复制
-(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

代码语言:javascript复制
  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其实本质上没有什么太大的差别,都是通过发送方法名找到对应的方法执行对应的操作。我的具体操作如下:

代码语言:javascript复制
-(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"];
   
}

对监听的处理的代理

代码语言:javascript复制
//用来接收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);
    }
    
}

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

0 人点赞