plan

  • WKWebView – Intercepts urls
  • WKWebView – MessageHandler

MessageHandler scheme is more elegant, but considering the compatibility with Android, we adopt WKWebView-intercepting URL scheme.

Usage scenarios/requirements

After clicking the button on the H5 page of scene A, the App only needs to complete the operation.

After the button is clicked on the H5 page of scene B, the App will notify H5 of the operation result when it needs to operate.

Scenario A and SCENARIO B both involve communication between H5 and App, but scenario B has A callback operation. A callback is basically an App calling a JS function

App H5 communication basics

App notify JS

var js = "App.callJS()"
webView.evaluateJavaScript(js) { (response, error) in    
}
Copy the code

JS notify App

var iframe = document.createElement("IFRAME");    
iframe.setAttribute("src"."");    
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
Copy the code

imagine

H5 sends the command to take a picture, and the App receives it and takes the picture. After taking the picture, it sends the picture to H5. So this is how we use the H5 page

// This parameter can be left blank
App.takePicture("Parameters".function(data) {
    // Success, display the image
}, function(data) {
    // Failed, error message
});
Copy the code

Train of thought

H5 identifies the uniqueness of an instruction with an ID, which is associated with the name, parameter, and callback of the current instruction. The App uses the ID to get the name, the parameter, and the callback.

Get the callback function by ID and use setTimeout to complete the JS function call.

// Execute the function with the same effect
setTimeout("App.callJS()".0);
App.callJS()
Copy the code

implementation

H5 core code

var AppServer = {
  
  ID_COUNTER: 0.COMMAND_NAME_SET: {},
  COMMAND_ARGS_SET: {},
  COMMAND_SUCCESS_COMPLETION_SET: {},
  COMMAND_FAIL_COMPLETION_SET: {},
  
  // JS calls App
  callNative: function (cmd_name, cmd_args, cmd_success, cmd_fail) {

    var key = this.ID_COUNTER++;     // The unique identifier of the directive
    this.COMMAND_NAME_SET[key] = cmd_name;
    this.COMMAND_ARGS_SET[key] = cmd_args;
    if (typeofcmd_success ! ='undefined') this.COMMAND_SUCCESS_COMPLETION_SET[key] = cmd_success;
    if (typeofcmd_fail ! ='undefined') this.COMMAND_FAIL_COMPLETION_SET[key] = cmd_fail;
    
    var iframe = document.createElement("IFRAME");    
    iframe.setAttribute("src"."DEMO://AppServer? id=" + key);    
    document.documentElement.appendChild(iframe);
    iframe.parentNode.removeChild(iframe);
    iframe = null;
  },
  
  // Directive name
  getCommandName: function(key) {
    return this.COMMAND_NAME_SET[key];
  },
    
  // Command parameters
  getCommandArgs: function(key) {
    return this.COMMAND_ARGS_SET[key];
  },

  // App calls JS
  callJS: function (key, args) {

    if (typeof args == "undefined") {
      args = JSON.stringify({});
      args = JSON.parse(args);
    }  

    var data = args.data;
    try {
      data = JSON.stringify(data);
    } catch(e) {
      alert(e.message);
    }
    
    / / callback
    var status = args.status;
    if (status == 1) {
      / / success
      if (typeof this.COMMAND_SUCCESS_COMPLETION_SET[key] == "undefined") return;
      setTimeout("AppServer.COMMAND_SUCCESS_COMPLETION_SET['" + key + "'] ('" + data + "')".0);
    }
    else if (status == 0) {
      / / fail
      if (typeof this.COMMAND_FAIL_COMPLETION_SET[key] == "undefined") return;
      setTimeout("AppServer.COMMAND_FAIL_COMPLETION_SET['" + key + "'] ('" + data + "')".0); }}};Copy the code

App core code

// Directive name
func getCommandName(_ commandID: String) {
    
    let JS = "AppServer.getCommandName(\"\(commandID)\")"
    webView.evaluateJavaScript(JS) { (response, error) in}}// Command parameters
func getCommandArguments(_ commandID: String)  {
    
    let JS = "AppServer.getCommandArgs(\"\(commandID)\")"
    webView.evaluateJavaScript(JS) { (response, error) in}}// App calls JS
func callJS(_ commandID: String.data: String) {
    
    let JS = "AppServer.callJS(\"\(commandID)\"," + data  + ")"
    webView.evaluateJavaScript(JS) { (response, error) in}}Copy the code

Implementation effect

Demo

Demo use

Feel good, star once 🌟

The H5 used by App is packaged and compiled, and the H5 project is under the my-project directory. For actual project use, H5 only needs to introduce appServer. js file and agree instruction name and parameters with App.

supplement

If you want to test custom instructions, you can modify the H5 project yourself. H5 Demo using Vue to write, modify directly compiled package. After Xcode has been cleaned (Shift + Command + k), rerunning will see the changes.