zoukankan      html  css  js  c++  java
  • iOS WKWebView OC 与 JS 交互学习

    我写WKWebView 想让 服务端相应 一个 方法但是不响应,根据 UIWebView 用 JSContext就能拿到响应的处理经验是不是服务端 也需要 对 WKwebView有兼容的一个写法??? 特此学习 WKWebView 记录

    一 .WKWebView 代理协议

    (1)WKScriptMessageHandler :

    OC在JS调用方法时做的处理。如果需要调用对话窗口就会先执行(3)协议再执行 (1)协议

    好处:传递给OC的参数直接在字典里面,不用再在url里面拼凑后的结果去截取解析。

    必须实现

    - (void)userContentController:(WKUserContentController *)userContentController
          didReceiveScriptMessage:(WKScriptMessage *)message

    (2)WKNavigationDelegate:

    处理页面跳转和载入过程。

    #pragma mark -- 进行页面跳转
    
    // 接收到服务器跳转请求之后再执行
    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
    // 在发送请求之前,决定是否跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler ;
    // 在收到响应后,决定是否跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler ;
    #pragma mark -- 追踪加载过程
    
    // 页面开始加载时调用
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
    
    // 当内容开始返回时调用
    - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation;
    // 页面加载完成之后调用
    - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;
    // 页面加载失败时调用
    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
    
    //好多协议 按需添加。。。

    (3)WKUIDelegate

    这个协议主要用于WKWebView处理web界面的三种提示框(警告框、确认框、输入框) 的网页交互

    #pragma mark - WKUIDelegate
    //警告
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
    //确认
    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
    // 输入框
    - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;

    二.协议使用

    (1)WKScriptMessageHandler ,关键在当前页面销毁后要注销协议保证无强引用,当前页面也无法销毁,发生内存泄漏。

    //注册协议
        self.userContentController = [[WKUserContentController alloc] init];
        //注册方法
        WKDelegateController *delegateController = [[WKDelegateController alloc]init];
        delegateController.delegate = self;
        
        // 通过JS与webview内容交互
        config.userContentController = self.userContentController;
        // 注入JS对象名称HFAlert,HFConfirm,HFPrompt当JS通过HFAlert,HFConfirm,HFPrompt来调用时,
        // 我们可以在WKScriptMessageHandler代理中接收到
        [config.userContentController addScriptMessageHandler:delegateController name:HFAlert];
        [config.userContentController addScriptMessageHandler:delegateController name:HFConfirm];
        [config.userContentController addScriptMessageHandler:delegateController name:HFPrompt];
        [config.userContentController addScriptMessageHandler:delegateController name:HFShare];
    //注销协议
    - (void)dealloc
    {
        [self.userContentController removeScriptMessageHandlerForName:HFAlert];
        [self.userContentController removeScriptMessageHandlerForName:HFConfirm];
        [self.userContentController removeScriptMessageHandlerForName:HFPrompt];
        [self.userContentController removeScriptMessageHandlerForName:HFShare];
    }
    //实施协议
    - (void)userContentController:(WKUserContentController *)userContentController
          didReceiveScriptMessage:(WKScriptMessage *)message {
        NSLog(@"%@", message.body);
        if ([message.name isEqualToString:HFAlert]) {
            // 打印所传过来的参数,只支持NSNumber, NSString, NSDate, NSArray,
            // NSDictionary, and NSNull类型
            NSDictionary *dictionary = message.body;
            if (![dictionary isKindOfClass:[NSDictionary class]]) {
                return;
            }
            NSLog(@"%@",dictionary[@"body"]); //服务端传值 log
            dispatch_async(dispatch_get_main_queue(), ^{
                //主线程操作UI
            });
        } else if ([message.name isEqualToString:HFConfirm]) {
            
        } else if ([message.name isEqualToString:HFPrompt]) {
            
        } else if ([message.name isEqualToString:HFShare]) {
        
        }
    }
    设置代理 WKDelegateController 重写成代理控制器性质,保证设置代理后,可移除 的关键!!!
    //
    //  WKDelegateController.m
    //  SectionDemo
    //
    //  Created by HF on 2017/6/22.
    //  Copyright © 2017年 HF-Liqun. All rights reserved.
    //
    
    #import "WKDelegateController.h"
    
    @interface WKDelegateController ()
    
    @end
    
    @implementation WKDelegateController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    }
    
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
        if ([self.delegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]) {
            [self.delegate userContentController:userContentController didReceiveScriptMessage:message];
        }
    }
    @end
    ////////
    //
    //  WKDelegateController.h
    //  SectionDemo
    //
    //  Created by HF on 2017/6/22.
    //  Copyright © 2017年 HF-Liqun. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    #import <WebKit/WebKit.h>
    
    @protocol WKDelegate <NSObject>
    
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
    
    @end
    
    @interface WKDelegateController : UIViewController <WKScriptMessageHandler>
    
    @property (weak , nonatomic) id < WKScriptMessageHandler > delegate;
    
    @end

    (2)WKNavigationDelegate,举例子和UIWebView shouldStart  方法一样,在请求前判断要不要继续执行

    // 在发送请求之前,决定是否跳转
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        NSString *hostname = navigationAction.request.URL.host.lowercaseString;
        if (navigationAction.navigationType == WKNavigationTypeLinkActivated
            && ![hostname containsString:@".baidu.com"]) {
            // 对于跨域,需要手动跳转
            [[UIApplication sharedApplication] openURL:navigationAction.request.URL];
            
            // 不允许web内跳转
            decisionHandler(WKNavigationActionPolicyCancel);
        } else {
            self.progressView.alpha = 1.0;
            decisionHandler(WKNavigationActionPolicyAllow);
        }
        NSLog(@"%s", __FUNCTION__);
    }

    (3)WKUIDelegate  参考代码

    #pragma mark - WKUIDelegate 这个协议主要用于WKWebView处理web界面的三种提示框(警告框、确认框、输入框) 的网页交互/**
     *  web界面中有弹出警告框时调用
     *
     *  @param webView           实现该代理的webview
     *  @param message           警告框中的内容
     *  @param frame             主窗口
     *  @param completionHandler 警告框消失调用 无回调
     */
    
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
        NSLog(@"%s", __FUNCTION__);
        //completionHandler(@"空回调");
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert" message:[NSString stringWithFormat:@"JS调用alert message:%@",message] preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler();
        }]];
        
        [self presentViewController:alert animated:YES completion:NULL];
        NSLog(@"%@", message);
    }
    
    
    /**
     确认框
     
     @param webView 实现该代理的webview
     @param message 确认窗口内容
     @param frame 主窗口
     @param completionHandler 警告框消失调用 回传布尔变量
     */
    - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
        NSLog(@"%s", __FUNCTION__);
        
        //completionHandler(@"可以直接回传布尔变量");
        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);
    }
    
    
    /**
     输入框
     
     @param webView web
     @param prompt 文本
     @param defaultText 默认输入文本
     @param frame frame
     @param completionHandler completionHandler  回传 字符串
     */
    - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
        
        //completionHandler(@"可以直接回传字符串");
        //可以根据回传参数来判断 是否必要展示 弹框,也可以隐式处理 根据当前参数判断回传指定逻辑参数
        NSLog(@"%s", __FUNCTION__);
        NSLog(@"%@", prompt);
        if ([prompt isEqualToString:HFPrompt]) {
            completionHandler(@"guess");
            return;
        }
        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];
    }

    三.OC JS 互相调用

    (1)  OC 调用 JS 代码(OC注入JS)

            NSString *js = @"alertName('我是参数')";//可以向js传参数
    //NSString *js = @"callJsAlert()";//无参数方法 [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) { NSLog(@"response: %@ error: %@", response, error); NSLog(@"call js alert by native"); }];

    (2) JS 调用 OC方法:关键是按照约定方法名和注册名

    关键代码: 

    //name 为注册名 HFAlert HFPrompt ...  messageBody 为传递参数集合 和 UIWebView的 调用OC 方法 是不一样的!!!!!
    window.webkit.messageHandlers.<name>.postMessage(<messageBody>);

    参考示例:

    <!DOCTYPE html>
    <html>
      <head>
        <title>iOS and Js</title>
        <style type="text/css">
          * {
            font-size: 40px;
          }
        </style>
      </head>
      
      <body>
        
        <div style="margin-top: 100px">
          <h1>Test how to use objective-c call js</h1><br/><br/>
          <div><input type="button" value="call shareButton" onclick="shareClick()"></div>
          <br/><br/>
          <div><input type="button" value="call js alert" onclick="callJsAlert()"></div>
          <br/>
          <div><input type="button" value="Call js confirm" onclick="callJsConfirm()"></div><br/>
        </div>
        <br/>
        <div>
          <div><input type="button" value="Call Js prompt " onclick="callJsInput()"></div><br/>
          <div>Click me here: <a href="http://www.baidu.com">Jump to Baidu</a></div>
        </div>
        
        <br/>
        <div id="SwiftDiv">
          <span id="jsParamFuncSpan" style="color: red; font-size: 50px;"></span>
        </div>
        
        <script type="text/javascript">
          //JS执行window.webkit.messageHandlers.Share.postMessage(<messageBody>)
          function callJsAlert() {
            //WKUIDelegate 空回调 警告框代理被触发
            alert('Objective-C call js to show alert');
            // HFAlert是我们所注入的对象
            window.webkit.messageHandlers.HFAlert.postMessage({body: 'call js alert in js'});
          }
        
          function callJsConfirm() {
            //WKUIDelegate 布尔回调 选择确认框代理被触发
            if (confirm('confirm', 'Objective-C call js to show confirm')) {
            document.getElementById('jsParamFuncSpan').innerHTML
            = 'true';
          } else {
            document.getElementById('jsParamFuncSpan').innerHTML
            = 'false';
          }
          
          //HFConfirm是我们所注入的对象
          window.webkit.messageHandlers.HFConfirm.postMessage({body: 'call js confirm in js'});
        }
        
        function callJsInput() {
          //WKUIDelegate 字符串回调 输入框代理被触发
          var response = prompt('HFPrompt', 'Please input your name:');
          document.getElementById('jsParamFuncSpan').innerHTML = response;
          
           //HFPrompt是我们所注入的对象
          window.webkit.messageHandlers.HFPrompt.postMessage({body: response});
        }
        
        function shareClick() {
            var response = prompt('Hello');
            window.webkit.messageHandlers.HFShare.postMessage({body:response ,title:'测试分享的标题',content:'测试分享的内容',url:'https://github.com/maying1992'});
        }
    
        function alertName(msg) {
            document.getElementById('jsParamFuncSpan').innerHTML = 'name' + msg + ', nice to meet you';
        }
          </script>
      </body>
    </html>

    end

    参考 

    (1) http://www.tuicool.com/articles/qQRrMzY

    (2)http://www.cocoachina.com/ios/20160906/17487.html

    (3)http://www.jianshu.com/p/4fa8c4eb1316

    (4)http://blog.csdn.net/u011619283/article/details/52135988

     
  • 相关阅读:
    [置顶] windows player,wzplayerV2 for windows
    wzplayer 近期将会支持BlackBerry和WinPhone8
    wzplayerEx for android(真正硬解接口,支持加密的 player)
    ffmpeg for ios 交叉编译 (支持i686 armv7 armv7s) 包含lame支持
    ffmpeg for ios 交叉编译 (支持i686 armv7 armv7s) 包含lame支持
    编译cegcc 0.59.1
    wzplayer 近期将会支持BlackBerry和WinPhone8
    wzplayerEx for android(真正硬解接口,支持加密的 player)
    windows player,wzplayerV2 for windows(20140416)更新
    编译cegcc 0.59.1
  • 原文地址:https://www.cnblogs.com/someonelikeyou/p/6890587.html
Copyright © 2011-2022 走看看