When developing a Hybrid App on iOS, there are two WebViews to choose from. UIWebView & WKWebView.

The two WebView controls can interact with OC & JS using only the framework of iOS.

  1. Use javaScriptCore UIWebView.
  2. Use WKUserContentController WKWebView.

UIWebView’s native interaction principle uses a JSContext to get UIWebView’s JS execution context. Then, through this context, the OC & JS two-way interaction takes place.

_jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; _jsContext. ExceptionHandler = ^ (JSContext * context, JSValue * exception) {NSLog (@ "% @" @ "failed to get the WebView JS execution environment!" ); };Copy the code

WKWebView native interaction principle

Register the JS execution functions you want to observe with the userContentController. Then, through a protocol method, all the parameters executed by the registered JS functions are passed to this protocol method.

Register the JS execution functions that you want to observe

 [webView.configuration.userContentController addScriptMessageHandler:self name:@"jsFunc"];
Copy the code

Call this function in JS and pass the parameter data

Window. Its. MessageHandlers. JsFunc. PostMessage ({name: "bill", the age: 22});Copy the code

OC complies with the WKScriptMessageHandler protocol.

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message 
Copy the code

The WKScriptMessage in this protocol method has name and body attributes. The name can be used to determine which JSFunc call is being made. Body is the argument that JSFunc passes to OC.


WebViewJavaScriptBridge

WebViewJavaScriptBridge is used for OC and JS interaction in WKWebView & UIWebView. Its basic principles are:

Register OC’s methods with the bridge and let JS call them. Register JS methods in the bridge and let OC call them.

Basic principles of WebViewJavascriptBridge

Register yourself and call it.


Webview Basic steps used by javascriptBridge

  1. Import it first in your projectWebViewJavaScriptBridge framework.
Pod 'WebViewJavascriptBridge'Copy the code
  1. Import header file#import <WebViewJavascriptBridge.h>
  2. Establish the relationship between WebView javascriptBridge and WebView.
_jsBridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
Copy the code
  1. In the HTML file, copy and paste the two JS functions.
function setupWebViewJavascriptBridge(callback) { if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); } if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); } window.WVJBCallbacks = [callback]; // Create an array of WVJBCallbacks global properties and insert callback into the array. var WVJBIframe = document.createElement('iframe'); // Create an iframe element wvjbiframe.style. display = 'none'; SRC = 'wvjbscheme://__BRIDGE_LOADED__'; / / set the iframe SRC attribute document. The documentElement. The appendChild (WVJBIframe); // Add iframe to the current text navigation. SetTimeout (function () {document. DocumentElement. RemoveChild (WVJBIframe)}, 0)} / / here will call JS method is mainly registered OC. setupWebViewJavascriptBridge(function(bridge){ });Copy the code

At this point, the basic preparatory work has been done. Now it’s time to inject OC methods and JS functions into the bridge.


Inject OC methods and JS functions into the bridge

Inject the OC method into the bridge.

[_jsBridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback) {NSLog(@"dataFrom JS: %@",data[@"data"]); www.baidu.com"); }];Copy the code

What this code means:

  1. ScanClick is an alias for OC Block.
  2. The block itself is the block of code that JS executes when it calls scanClick in some way.
  3. Data. Since OC is called by JS, data is the data transferred from JS.
  4. ResponseCallback Indicates the data passed to the JS end after the OC block has completed execution.

Inject JS functions into the bridge.

OC method, injected in OC. JS methods therefore need to be injected in JS. How does the JS method inject into the bridge?

Previously, in preparation, there were two pieces of JS code. You need to inject the JS function in the second section of JS code.

// Register the JS method that OC will call. SetupWebViewJavascriptBridge (function (bridge) {/ / OC need to call the JS method declaration. Bridge. RegisterHanlder ('testJavaScriptFunction',function(data,responseCallback){// ResponseCallback = responseCallback ("JS called by OC "); ResponseCallback ({data: "js ",from: "js "}); })});Copy the code

What this code means:

  1. TestJavaScriptFunction is an alias for the JS functions injected into the bridge. To be called by the OC side.
  2. The data callback function. Since JS functions are called by OC, data is the data passed by OC.
  3. ResponseCallback. The data that the JS call passes to the OC after it is called.

Basically:

OC registers OC methods and OC calls JS functions. The JS side registers JS functions and the JS side calls OC methods.

scenario

JS -> OC interaction

In the HTML, there’s a button that you can click to change the color of the NavigationBar.

  1. At the OC side, inject a block to the bridge that changes the color of the NavigationBar.
  2. On the JS side, this block is called to indirectly change the color.

First, in OC, register a Block that changes the color of the navigationBar via WebViewJavascriptBridge.

[_jsBridge registerHandler:@"colorClick" handler:^(id data, WVJBResponseCallback responseCallback) { self.navigationController.navigationBar.barTintColor = [UIColor ColorWithRed :arc4random_uniform(256) / 255.0 Green :arc4random_uniform(256) / 255.0 Blue :arc4random_uniform(256) / 255.0 ResponseCallback (@" color changed!");}];Copy the code

And then in JS, somehow call the OC block.

WebViewJavascriptBridge. CallHandler (' colorClick ', function (dataFromOC) {alert (" JS invoked the OC register colorClick method "); document.getElementById("returnValue").value = dataFromOC; })Copy the code

Here in some way is to use WebViewJavascriptBridge. CallHandler (‘ block alias in the OC, the callback) to call.

OC -> JS interaction

There is a UIButton on the OC, click here and change the color of the HTML body to orange.

First, inject a JSFunction into the bridge that modifies the HTML body color.

// Declare OC requires active invocation of JS methods. setupWebViewJavascriptBridge(function(bridge) { bridge.registerHandler('changeBGColor',function(data,responseCallback){ // alert('aaaaaa'); document.body.style.backgroundColor = "orange"; document.getElementById("returnValue").value = data; }); });Copy the code

This changeBGColor is then called on the OC side through the bridge.

[_jsBridge callHandler:@"changeBGColor" data:@" Change HTML background color to orange!!!!"] ;Copy the code

Execution effect:


supplement

There are three cases in which OC calls JS.

// Simply call JSFunction, passing no arguments to JS, and not requiring the return value of JSFunction. [_jsBridge callHandler:@"changeBGColor"]; // Call JSFunction and pass the argument to JS, but do not need the return value of JSFunciton. [_jsBridge callHandler:@"changeBGColor" data:@" Change HTML background color to orange!!!!"] ; // Call JSFunction and pass the argument to JS, also need the return value of JSFunction. [_jsBridge callHandler:@"changeBGColor" data:@" responseCallback:^(id responseData) {NSLog(@"JS return value: %@",responseData); }];Copy the code

Three cases of JS calling OC.

/ / JS simple call OC block WebViewJavascriptBridge. CallHandler (' scanClick '); / / JS calls OC block, and pass parameters of JS WebViewJavascriptBridge. CallHandler (' scanClick ', "JS parameters"); // JS calls the OC block, passing the JS argument, and accepting the return value of the OC. WebViewJavascriptBridge.callHandler('scanClick',{data : },function(dataFromOC){alert("JS called OC's scan method!" ); document.getElementById("returnValue").value = dataFromOC; });Copy the code

You can choose an appropriate method according to the actual situation.

Note about injecting blocks into Bridges in OC.

Remember to remove the OC block injected into the bridge when the current controller disappears. Otherwise, the controller may fail to release.

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [_jsBridge removeHandler:@"scanClick"];
    [_jsBridge removeHandler:@"colorClick"];
    [_jsBridge removeHandler:@"locationClick"];
    [_jsBridge removeHandler:@"shareClick"];
    [_jsBridge removeHandler:@"payClick"];
    [_jsBridge removeHandler:@"goBackClick"];
}
Copy the code

Conclusion:

  1. UIWebView & JavaScriptCore is equal to the native JS & OC interaction scheme.
  2. WKWebView & userContentController is equal to the native JS & OC interaction scheme.
  3. WebViewJavascriptBridge can be combined with UIWebView & WKWebView for OC & JS interaction.
  4. WebViewJavascriptBridge uses core, OC to inject OC methods and let JS call. JS injects JS functions for OC to call.
  5. There are four prerequisites for using WebViewJavaScriptBridge.