美文网首页
iOS WKWebView的使用

iOS WKWebView的使用

作者: 光之盐汽水 | 来源:发表于2018-07-24 14:55 被阅读0次

    在开发过程中,iOS 中实现加载 web 页面主要有两种控件,UIWebView 和 WKWebview,两种控件对应具体的实现方法不同。WKWebView 是苹果在iOS 8中引入的新组件,目的是提供一个现代的支持最新Webkit功能的网页浏览控件,摆脱过去 UIWebView的老、旧、笨,特别是内存占用量巨大的问题。它使用与Safari中一样的Nitro JavaScript引擎,大大提高了页面js执行速度。

    相比于UIWebView的优势:

    在性能、稳定性、占用内存方面有很大提升;
    允许JavaScript的Nitro库加载并使用(UIWebView中限制)
    增加加载进度属性:estimatedProgress,不用在自己写假进度条了
    支持了更多的HTML的属性。

    使用方法:

    1、导入头文件:#import <WebKit/WebKit.h>

    2、创建WKWebView:

    @property (nonatomic, strong) WKWebView *webView;
    
    #pragma mark - webView
    - (WKWebView *)webView {
        if (!_webView) {
            _webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
            _webView.backgroundColor = [UIColor whiteColor];
            _webView.navigationDelegate = self;
            _webView.UIDelegate = self;
            self.webView.allowsBackForwardNavigationGestures = YES;
        }
        return _webView;
    }
    

    3、设置代理<WKNavigationDelegate, WKUIDelegate>

    // 页面开始加载时调用
    -(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
        self.progressView.hidden = NO;
    }
    // 当内容开始返回时调用
    - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
    }
    // 页面加载完成之后调用
    - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{//这里修改导航栏的标题,动态改变
        self.navigationTitleLab.text = webView.title;
        self.progressView.hidden = YES;
        if (webView.backForwardList.backList.count > 0 && self.closeButton.hidden == YES) {
            //作判断,显示与隐藏关闭按钮
            self.closeButton.hidden = NO;
        }
        
    //    //获取网页中的图片
    //    static  NSString * const jsGetImages = @"function getImages(){\
    //    var objs = document.getElementsByTagName(\"img\");\
    //    var imgScr = '';\
    //    for(var i=0;i<objs.length;i++){\
    //    imgScr = imgScr + objs[i].src + '+';\
    //    };\
    //    return imgScr;\
    //    };";
    //    [webView evaluateJavaScript:jsGetImages completionHandler:nil];
    //    [webView evaluateJavaScript:@"getImages()" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
    //        NSArray *urlArray = [NSMutableArray arrayWithArray:[result componentsSeparatedByString:@"+"]];
    //        //urlResurlt 就是获取到得所有图片的url的拼接;mUrlArray就是所有Url的数组
    //        NSLog(@"--%@",[urlArray firstObject]);
    //    }];
    }
    // 页面加载失败时调用
    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{
        self.progressView.hidden = YES;
    }
    // 接收到服务器跳转请求之后再执行
    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{
    }
    // 在收到响应后,决定是否跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
        
        WKNavigationResponsePolicy actionPolicy = WKNavigationResponsePolicyAllow;
        //这句是必须加上的,不然会异常
        decisionHandler(actionPolicy);
    }
    // 在发送请求之前,决定是否跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
        
        //调起微信等(有些网页点击某个按钮会在微信、QQ或者appStore中打开,在这里监听跳转)
        NSString *url = [navigationAction.request.URL.absoluteString stringByRemovingPercentEncoding];
        if ([url containsString:@"weixin://"] ||
            [url containsString:@"itms-appss://"] ||
            [url containsString:@"mqq://"]) {
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
        }
        
        //需要判断targetFrame是否为nil,如果为空则重新请求
        if (navigationAction.targetFrame == nil) {
            [webView loadRequest:navigationAction.request];
        }
    
        WKNavigationActionPolicy actionPolicy = WKNavigationActionPolicyAllow;
        
        if (navigationAction.navigationType == WKNavigationTypeBackForward) {//判断是返回类型
            //同时设置返回按钮和关闭按钮为导航栏左边的按钮 这里可以监听左滑返回事件,仿微信添加关闭按钮。
            //可以在这里找到指定的历史页面做跳转
        }
        //这句是必须加上的,不然会异常
        decisionHandler(actionPolicy);
    }
    

    4、JS和OC的互相调用

    设置代理:<WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler>

    4.1、JS调用OC方法

    配置环境:

        WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];
        userContentController =[[WKUserContentController alloc]init];
        configuration.userContentController = userContentController;
        
        //注册方法
        WKDelegateController * delegateController = [[WKDelegateController alloc]init];
        delegateController.delegate = self;
        [userContentController addScriptMessageHandler:delegateController  name:@"sayhello"];
    
        webView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:configuration];
        [self.view addSubview:webView];
        webView.UIDelegate = self;
        webView.navigationDelegate = self;
        [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.test.com"]]];
    
    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        
        if (_webView) {
             //这里需要注意,前面增加过的方法一定要remove掉。
            [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"sayhello"];
            _webView.UIDelegate = nil;
            _webView.navigationDelegate = nil;
            
            [_webView removeFromSuperview];
            _webView = nil;
        }
    }
    - (void)dealloc{
    }
    #pragma mark - WKScriptMessageHandler
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    
    // 这里实现原生的方法
    if ([message.name isEqualToString:@"sayhello"]) {
            // message.body就是h5传递给原生的参数,这里可以是nil,可以是字符串,可以是数组,可以是字典
        }
    }
    

    message.body的类型(h5传值类型):

    message.body的类型(h5传值类型)
    PS:若参数为空的话,h5调用原生的方法里面一定要传一个‘null’,不然,调不到原生方法。
    4.2、OC调用JS方法
    - (void)webView:(WKWebView *)tmpWebView didFinishNavigation:(WKNavigation *)navigation{
        //test()是JS方法名,completionHandler是异步回调block
        [webView evaluateJavaScript:@"test()" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            NSLog(@"%@",result);
        }];
        
    }
    

    5、使用过程中遇到的问题

    5.1、当用户点击webView上的链接无反应。(在浏览器中点击该网页上的链接,需要打开一个新的页面)

    分析:在- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler方法中,参数 WKNavigationAction 中有两个属性:sourceFrame和targetFrame,分别代表这个action的出处和目标。类型是 WKFrameInfo 。WKFrameInfo有一个 mainFrame 的属性,正是这个属性标记着这个frame是在主frame里还是新开一个frame。
    如果 targetFrame 的 mainFrame 属性为NO,表明这个 WKNavigationAction 将会新开一个页面。
    解决方法:

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    
        //需要判断targetFrame是否为nil,如果为空则重新请求
        if (navigationAction.targetFrame == nil) {
            [webView loadRequest:navigationAction.request];
        }
    
        WKNavigationActionPolicy actionPolicy = WKNavigationActionPolicyAllow;
        //这句是必须加上的,不然会异常
        decisionHandler(actionPolicy);
    }
    

    相关文章

      网友评论

          本文标题:iOS WKWebView的使用

          本文链接:https://www.haomeiwen.com/subject/zcnemftx.html