美文网首页
WKWebView与原生的交互以及代理方法

WKWebView与原生的交互以及代理方法

作者: huicuihui | 来源:发表于2017-12-19 17:30 被阅读31次

    项目里面很多地方都是用的h5, h5的处理都放在了一个新的控制器里面,里面很多代理方法,在这里记录一下。
    很多h5的处理,iOS和js的交互都要通过代理方法去处理。
    1、iOS调用js的方法, 例如调用js的跳转方法。
    2、iOS获取js的方法,截取方法然后自己去实现。

    @protocol WKScriptMessageHandler <NSObject>
    
    @required
    
    /*! @abstract Invoked when a script message is received from a webpage.
     @param userContentController The user content controller invoking the
     delegate method.
     @param message The script message received.
     */
    方法中主要是收到JS的回执脚本就会运行一次
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
    
    @end
    

    该代理方法是h5调用js方法的时候,客户端可以获取到并且去做自己的处理。
    点击某个按钮,webview加载完成之后原生可以获取到里面的某些需要的数据去设置。
    h5调原生本地函数

    /**
     当从网页收到脚本消息时调用。
    
     @param userContentController 调用委托方法的用户内容控制器。
     @param message 收到的脚本消息。
     */
    - (void)userContentController:(WKUserContentController *)userContentController
          didReceiveScriptMessage:(WKScriptMessage *)message {
        
        NSDictionary *bodyParam = (NSDictionary*)message.body;
        NSString *func = [bodyParam objectForKey:@"function"];
        
        NSLog(@"MessageHandler Name:%@", message.name);
        NSLog(@"MessageHandler Body:%@", message.body);
        NSLog(@"MessageHandler Function:%@",func);
        
        //本人喜欢只定义一个MessageHandler协议 当然可以定义其他MessageHandler协议
        
        if ([message.name isEqualToString:@"Native"])
        {
            NSDictionary *parameters = [bodyParam objectForKey:@"parameters"];
            //调用本地函数
            if([func isEqualToString:@"modifySuccess"])
            {
                NSLog(@"在这里面去做弹窗提示,为视图设置数据,调用原生的返回等操作");
            }
            else if([func isEqualToString:@"callNativeHomePageBack"])
            {
                NSLog(@"在这里面去做弹窗提示,为视图设置数据,调用原生的返回等操作");
            }
            else if ([func isEqualToString:@"callNativeWebShare"]){
                NSLog(@"调用原生的分享功能");
            }
            else if ([func isEqualToString:@"callNativeWebLoginView"]){
                NSLog(@"跳转到登录页面");
            }
            else if ([func isEqualToString:@"callNativeWebPageShare"]){
                NSLog(@"弹出本地的分享菜单");
            }
            else if ([func isEqualToString:@"callNativeProduct"]){
                NSLog(@"点击立即购买按钮,去购买操作");
            }
            else if ([func isEqualToString:@"keyboardBarShow"]){
                NSLog(@"web要求评论条出现");
            }
            else if ([func isEqualToString:@"keyboardBarHide"]){
                NSLog(@"web要求评论条消失");
            }
            else if ([func isEqualToString:@"callNativeWebviewWithURL"]){
                NSLog(@"跳出新浏览器,创建一个webview去显示新页面");
            }
            else if ([func isEqualToString:@"callNativeWebviewWithURLWithNaviBar"]){
                NSLog(@"跳出新浏览器");
            }
            else if ([func isEqualToString:@"keyboardBarShowUpdateCommentCount"]){
                NSLog(@"刷新评论的数据");
            }
        }
    }
    

    这个是检测收到html的js消息的时候, 我们客户端做的操作。
    上面的就是收到html的修改用户信息、分享、点击客服、收藏等消息。

    原生调用js方法

    例:
    文章详情页面发表评论功能,发评论的内容是客户端控制的,客户端才拥有。
    点击发送按钮,需要调用js方法,告诉h5发表评论的内容。
    点击发送按钮需要调用h5的js方法:

    NSString *contentString = [<#评论的内容#> stringByReplacingOccurrencesOfString:@"\n" withString:@"<br/>"];
    
    [wkWebView evaluateJavaScript:[NSString stringWithFormat:@"keyboardBarCommentReturn('%@')",contentString] completionHandler:^(id _Nullable response, NSError * _Nullable error){
            
        }];
    

    例二:
    点击底部的评论按钮,详情页滚动到评论,需要h5去做,原生告诉h5

    [wkWebView evaluateJavaScript:[NSString stringWithFormat:@"keyboardBarRecordReturn('1')"] completionHandler:^(id _Nullable response, NSError * _Nullable error) {
    
        }];
    
    代理方法

    WKUIDelegate

    - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
        NSLog(@"%s", __FUNCTION__);
        
        [self.wkWebview loadRequest:[self fixRequest:navigationAction.request]];
        return webView;
    }
    
    
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
        
        NSLog(@"%s", __FUNCTION__);
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler();
        }]];
        
        [self presentViewController:alert animated:YES completion:NULL];
    }
    
    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{
        
        NSLog(@"%s", __FUNCTION__);
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS调用confirm" preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(YES);
        }]];
        [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            completionHandler(NO);
        }]];
        [self presentViewController:alert animated:YES completion:NULL];
        
        NSLog(@"%@", message);
    }
    
    - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler{
        
        NSLog(@"%s", __FUNCTION__);
        NSLog(@"%@", prompt);
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS调用输入框" preferredStyle:UIAlertControllerStyleAlert];
        [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
            textField.textColor = [UIColor redColor];
        }];
        
        [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler([[alert.textFields lastObject] text]);
        }]];
        
        [self presentViewController:alert animated:YES completion:NULL];
    
    }
    

    上面的那个是WKUIDelegate, 可以检测到js到弹窗, 然后我们出来我们自己的样式。弹出什么和做什么操作。

    WKNavigationDelegate

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
        NSLog(@"%s", __FUNCTION__);
        
        NSURLRequest *originalRequest = navigationAction.request;
        [self fixRequest:originalRequest];
        [webView evaluateJavaScript:[self jsString:navigationAction.request.URL.absoluteString] completionHandler:^(id _Nullable response, NSError * _Nullable error) {
            if (error == nil) {
                NSLog(@"成功注入");
            }
        }];
        decisionHandler(WKNavigationActionPolicyAllow);
    
    }
    
    //可以在该代理方法中 获取头部信息 包括过期日期 修改日期等
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
        NSLog(@"%s", __FUNCTION__);
        
        NSString *cacheControl = [(NSHTTPURLResponse*)navigationResponse.response allHeaderFields][@"Cache-Control"]; // max-age, must-revalidate, no-cache
        NSArray *cacheControlEntities = [cacheControl componentsSeparatedByString:@","];
    
        for(NSString *substring in cacheControlEntities) {
            
            if([substring rangeOfString:@"max-age"].location != NSNotFound) {
                
                // do some processing to calculate expiresOn
                NSString *maxAge = nil;
                NSArray *array = [substring componentsSeparatedByString:@"="];
                if([array count] > 1)
                    maxAge = array[1];
                
               NSDate * expiresOnDate = [[NSDate date] dateByAddingTimeInterval:[maxAge intValue]];
    
            //保存过期时间
                [[NSUserDefaults standardUserDefaults] setObject:expiresOnDate forKey:kHtml_gqsj];
    
            }
        }
    
        decisionHandler(WKNavigationResponsePolicyAllow);
        
    }
    
    //请求开始的代理方法
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
    {
    }
    //请求结束的代理方法。
    - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
        NSLog(@"%s", __FUNCTION__);
    
    }
    
    - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error{
        NSLog(@"%s", __FUNCTION__);
    
    }
    

    相关文章

      网友评论

          本文标题:WKWebView与原生的交互以及代理方法

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