zoukankan      html  css  js  c++  java
  • iOS(WKWebView)OC与JS交互 之三

     
      随着H5功能愈发的强大,没进行过混合开发的小伙们都不好意思说自己能够独立进行iOS的app开发,在iOS7操作系统下,常用的native,js交互框架有easy-js,WebViewJavascriptBridge,以及结合javaScriptCore的框架。

      easy-js 很早的一个框架了,已经好几年没有人维护了,里面有很多隐藏很深的坑,新人如果没有用过的话,建议不要再用了。主要是js新建一个隐藏的iframe,通过拦截url的形式进行交互。

      WebViewJavascriptBridge是网上很火的一个交互库,使用的人较多,但是对于js基础较弱的小伙伴来说,底层不是太好理解。底层和easy-js一样都是通过创新一个隐藏的iframe通过截取url来进行交互。缺点这里就暂时不说了,用的不多,体会不够深刻。嘿嘿。

      javaScriptCore中JSExport进行交互,这种方式比较简单易懂,也是我个人比较推崇 的一种方式。如果app最低版本操作系统是iOS7的小伙伴,建议自己搜一下相关知识点哦。但是WKWebView不能够利用javaScriptCore交互,是不是很坑爹哦,呜呜。 


       如何实现WKWebView与js交互

    js发送消息给native的代理方法是: 

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

    native调用js方法传递参数主要通过如下方法: 

    [_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) {
    
    }];

    相信这两个方法大家在网上已经看到过很多遍了,貌似可以解决与js交互的问题,实则不然,这两个方法并没有真正的帮我们解决交互的问题。因为在js发送消息给native的时候,有时候需要通过回调来获取相应的信息,仅仅靠上面两个方法是没有办法满足的,也可能会有小伙伴说,先通过上面方法1发送消息个native然后,再使用方法2发送消息给js不就好了么,不行的,这样的话,js调用native方法时,和native发送消息时候并没有时间先后的约定,不能保证,js获取相关返回值的时候,一定能拿到值。 
       我一直在想如何能有一个与js调用native函数相关连的回调呢。功夫不负有心人,偶然看到H5 ,DOM可以绑定事件,后来想能不能绑定自定义事件呢,一搜果然可以,参考博客如下: 
    http://www.zhangxinxu.com/wordpress/2012/04/js-dom自定义事件/ 
    顺着这个思路,每一次js方法调用native方法的时候,我都为这个js方法绑定一个对应的callBack方法,这样的话,同时在发送的消息中告诉native需要回调,native方法就可以执行完相关的方法后,直接回调相应的 callBack方法,并携带相关的参数,这样就可以完美的进行交互了。

    这里我主要写了一个JKEventHandler的js类,脚本内容如下:

    var JKEventHandler ={
    
    callNativeFunction:function(functionString,params,callBack){
    
        var methodName = (functionString.replace(/functions?/mi,"").split("("))[0];
        var callBackName =methodName + 'CallBack';
        var message;
    
        if(!callBack){
    
            message = {'methodName':methodName,'params':params};
            window.webkit.messageHandlers.JKEventHandler.postMessage(message);
    
        }else{
            message = {'methodName':methodName,'params':params,'callBackName':callBackName};
            if(!Event._listeners[callBackName]){
            Event.addEvent(callBackName, function(data){
    
                           callBack(data);
    
                           });
            }
            window.webkit.messageHandlers.JKEventHandler.postMessage(message);
        }
    
    
    },
    
    callBack:function(callBackName,data){
    
        Event.fireEvent(callBackName,data);
    
    },
    
    removeAllCallBacks:function(data){
        Event._listeners ={};
    }
    
    };
    
    
    
    var Event = {
    
    _listeners: {},
    
    
    addEvent: function(type, fn) {
        if (typeof this._listeners[type] === "undefined") {
            this._listeners[type] = [];
        }
        if (typeof fn === "function") {
            this._listeners[type].push(fn);
        }
    
        return this;
    },
    
    
    fireEvent: function(type,param) {
        var arrayEvent = this._listeners[type];
        if (arrayEvent instanceof Array) {
            for (var i=0, length=arrayEvent.length; i<length; i+=1) {
                if (typeof arrayEvent[i] === "function") {
                    arrayEvent[i](param);
                }
            }
        }
    
        return this;
    },
    
    removeEvent: function(type, fn) {
        var arrayEvent = this._listeners[type];
        if (typeof type === "string" && arrayEvent instanceof Array) {
            if (typeof fn === "function") {
                for (var i=0, length=arrayEvent.length; i<length; i+=1){
                    if (arrayEvent[i] === fn){
                        this._listeners[type].splice(i, 1);
                        break;
                    }
                }
            } else {
                delete this._listeners[type];
            }
        }
    
        return this;
    }
    };

    callNativeFunction: 这个函数主要是js调用native方法的时候进行调用的。如果有回调的话,需要在传入的参数中写出来哦。 
    callBack:主要是用来触发对应js方法回调函数的。

    removeAllCallBacks: 主要是在要销毁所有的callback事件时调用的。 


    下面是html 使用 这个js 类的 demo

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8" />
        <title>iOS and Js</title>
        <style type="text/css">
          * {
            font-size: 40px;
          }
        </style>
      </head>
    
      <body>
    
        <div style="margin-top: 100px">
          <h1 style="color: red;">教你如何用H5与OC进行交互,并且把H5输入的内容显示到当前的控制器上</h1><br/>
          <div><input type="button" value="sendInfoToNative" onclick="sendInfoToNative()"></div>
          <br/>
          <div><input type="button"  value="getInfoFromNative" onclick="getInfoFromNative()"></div>
          <br/>
           <div><input type="button" value="cleanAllCallBacks" onclick="cleanAllCallBacks()"></div>
           <br/>
          <div><input type="button" value="点击触发JS方法(callJsConfirm)" onclick="callJsConfirm()"></div><br/>
        </div>
        <br/>
        <div>
          <div><input type="button" value="点击触发JS输入方法(callJsInput) " onclick="callJsInput()"></div><br/>
        </div>
    
        <br/>
        <div id="SwiftDiv">
          <span id="jsParamFuncSpan" style="color: red; font-size: 50px;"></span>
        </div>
    
        <script type="text/javascript">
          function sendInfoToNative() {
    
    
            var params ={'Phone':'13566668888'};
    
           JKEventHandler.callNativeFunction(arguments.callee.toString(),params,null);
    
          }
    
        function getInfoFromNative(){
    
         var params = {'Phone':'13933333333'};
         JKEventHandler.callNativeFunction(arguments.callee.toString(),params,function(data){
                                          alert(data);
                                          });
    
    
        }
    
        function callJsConfirm() {
          if (confirm('confirm', 'Objective-C call js to show confirm')) {
            document.getElementById('jsParamFuncSpan').innerHTML
            = 'true';
          } else {
            document.getElementById('jsParamFuncSpan').innerHTML
            = 'false';
          }
    
        }
    
        function callJsInput() {
          var response = prompt('Hello', '请输入你的名字:');
          document.getElementById('jsParamFuncSpan').innerHTML = response;
          alert (response);
    
        }
    
        function cleanAllCallBacks(){
    
        JKEventHandler.removeAllCallBacks();
    
        }
          </script>
      </body>
    </html>

    在js中调用getInfoFromNative 这个方法既可以发送参数给native,同时也可以从native获取参数 
    具体实现:

     function getInfoFromNative(){
    
         var params = {'Phone':'13933333333'};
                   JKEventHandler.callNativeFunction(arguments.callee.toString(),params,function(data){
                                          alert(data);
          });
    
        }        

    OC里面JKEventHandler类 负责js掉用原生的回调  里面处理js 传过来的参数 然后判断掉用哪些方法 ,在

    OC里面JKEventHandler+Demo.m  通过JKEventHandler用runtime处理 然后调用里面的方法

    - (void)getInfoFromNative:(id)params :(void(^)(id response))callBack{
        NSLog(@"params %@",params);
        NSString *str = @"'Hi Jack!'";
        callBack(str);
    
    }

    就这样,我在native方法里可以获取到js传递来的参数,同时通过callBack我也可以传递参数给js。 

    另外呢在JKEventHandler文件里,我写了一个事件分发函数,主要就是为了解决多个js方法交互的问题。感兴趣的小伙伴可以看看我的demo哦。 
    另外需要大家注意的是,WKWebView所在的ViewController即将被销毁的时候,也就是WKWebView即将被销毁的时候,一定要记得调用如下方法销毁所有的callback事件哦:

     [_webView evaluateJavaScript:@"JKEventHandler.removeAllCallBacks();" completionHandler:^(id _Nullable data, NSError * _Nullable error) {
    
     }];//删除所有的回调事件

    俗话说的话,代码就是程序员最好的老师,这里我就不多说了,Demo地址 

    也可以用pod 加入:

    pod "JKWKWebViewHandler"



  • 相关阅读:
    PAT (Advanced Level) 1114. Family Property (25)
    PAT (Advanced Level) 1113. Integer Set Partition (25)
    PAT (Advanced Level) 1112. Stucked Keyboard (20)
    PAT (Advanced Level) 1111. Online Map (30)
    PAT (Advanced Level) 1110. Complete Binary Tree (25)
    PAT (Advanced Level) 1109. Group Photo (25)
    PAT (Advanced Level) 1108. Finding Average (20)
    PAT (Advanced Level) 1107. Social Clusters (30)
    PAT (Advanced Level) 1106. Lowest Price in Supply Chain (25)
    PAT (Advanced Level) 1105. Spiral Matrix (25)
  • 原文地址:https://www.cnblogs.com/junhuawang/p/8337534.html
Copyright © 2011-2022 走看看