The perfect solution for WKWebView to interact with js

_As H5 becomes more powerful, guys who haven't done mixed development are shy about saying they can do it on their own iOS app development for iOS7 operating system Below, the common native, JS interaction frameworks are easy-js, WebView JavascriptBridge, and a framework that combines javaScriptCore.Easy-js is an early framework that has not been maintained for several years. There are many hidden deep pits in it. If new people have not used it, they are advised not to use it anymore.It is mainly JS that creates a new hidden iframe and interacts by intercepting the url.The WebView JavascriptBridge is a popular interactive library on the web and uses a lot of people, but the bottom level is not very well understood for small js-based partners.The bottom level, like easy-js, interacts by creating a hidden iframe by intercepting the url.The shortcomings are not mentioned here for the moment, they are not used much and they are not deep enough to understand.Hey.JSExport in javaScriptCore interacts in a way that is easy to understand and that I personally recommend.If the app's minimum operating system is a companion to iOS7, it is recommended that you search for relevant knowledge points yourself.But WKWebView can't interact with javaScriptCore, is it really grotesque?(
_Due to last year's strong drive, our series of app minimum operating systems started with iOS8 this year, so today I would like to share with you how I interact with js in WKWebView.(
js sends messages to native by:
Method 1,

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

It is mainly the js method message that calls the native method.

native calls the js method to pass parameters mainly through the following methods:
Method 2

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


    }];
  •  

I believe that these two methods have been seen many times on the web. It seems that they can solve the problem of interaction with js. However, they do not really help us solve the problem of interaction.Because when JS sends a message to natives, sometimes it is necessary to get the corresponding information through callbacks. It is not possible to just rely on the above two methods, or there may be a little partner who says, Isn't it good to send a message natives through method 1 above, and then send a message to JS using method 2 again? No, in this case, when JS calls the natives, it will be better to use the native method.When sending a message, there is no time-in-sequence agreement, and there is no guarantee that when JS gets the relevant return value, it will get the value.(
_I've been wondering how there can be a callback associated with js calling the native function.Gongfu pays off. I happened to see H5, DOM can bind events. Later, I thought it was possible to bind custom events. After a search, I can refer to the blog as follows:
http://www.zhangxinxu.com/wordpress/2012/04/js-dom Custom Events/
Following this line of thought, every time a js method calls a native method, I bind a corresponding callBack method for this js method. In this case, I also tell native in the sent message that callbacks are needed. After the native method can execute the related method, it calls back the corresponding callBack method directly and carries the relevant parameters, so that it can be delivered perfectlyMutually.Here I have mainly written a js class of JKEventHandler, the script is as follows:

var JKEventHandler ={

callNativeFunction:function(functionString,params,callBack){

    var methodName = (functionString.replace(/function\s?/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: This function is mainly called when js calls the native method.If there are callbacks, they need to be written out in the parameters passed in.(
callBack: Mainly used to trigger the corresponding js method callBack function.

removeAllCallBacks: Called primarily when all callback events are to be destroyed.(
Take my demo for example

<!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;">Show you how to use H5 and OC Interact,And put H5 The input is displayed on the current controller</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="Click Trigger JS Method(callJsConfirm)" onclick="callJsConfirm()"></div><br/>
    </div>
    <br/>
    <div>
      <div><input type="button" value="Click Trigger JS Input Method(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', 'Please enter your name:');
      document.getElementById('jsParamFuncSpan').innerHTML = response;
      alert (response);

    }

    function cleanAllCallBacks(){

    JKEventHandler.removeAllCallBacks();

    }
      </script>
  </body>
</html>
  •  

Calling getInfoFromNative in js can send parameters to and get parameters from native
Specific implementation:

 function getInfoFromNative(){

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


    }

At the same time, through the JKEventHandler transformation, there is a function with the same name in the JKEventHandler+Demo.m file, but the parameters are different:

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

}
  •  

In this way, I can get the parameters passed by js in the native method, and I can also pass the parameters to js through callBack.(
Additionally, in the JKEventHandler file, I wrote an event distribution function to solve the problem of multiple js methods interacting.Interested little buddies can see my demo.(
It is also important to note that when the ViewController where WKWebView is located is about to be destroyed, that is, when WKWebView is about to be destroyed, it is important to remember to call the following method to destroy all callback events:

 [_webView evaluateJavaScript:@"JKEventHandler.removeAllCallBacks();" completionHandler:^(id _Nullable data, NSError * _Nullable error) {


    }];//Delete all callback events
  •  

As the saying goes, code is the best teacher for programmers. I won't say much here. Demo Address 
How to use cocoapod, you can:

pod "JKWKWebViewHandler"

Keywords: iOS Javascript

Added by slug58 on Mon, 01 Jul 2019 00:41:10 +0300