Compared with single client development, Hybrid Hybrid development has the advantages of short development cycle and fast iteration, but the pages developed in Hybrid mode have some defects, such as performance problems and lack of client capability. JSBridge is a bridge to achieve client capabilities, giving Hybrid applications stronger terminal capabilities.



As a communication bridge between the client and H5, JSBridge can undertake the following capabilities:

  • Authentication JSBridge invocation authentication, whitelist, and blacklist
  • Glue ability JSBridge compatible code, do version control etc calls transparently
  • Test capability Provides test methods to facilitate testing
  • Scope(configuration) capabilities can produce compact and target versions of JSBridge based on configuration

The following uses The Android code as an example to describe the implementation of JSBridge.

Js call Native

Js calls to Native usually have the following schemes:

  • Intercept requests (shouldOverrideUrlLoading/shouldInterceptRequest)
  • Intercept specific methods (prompt/alert/ Confirm)
  • Client injection JSBridge(addJavascriptInterface)

Intercept request

WebViewClient can be set when Android initializes Wevview. The main function of WebViewClient is to deal with Webview loading notification and request events. Through the rewrite WebViewClient shouldOverrideUrlLoading/shouldInterceptRequest can intercept the h5 request so as to realize the ability to call. The implementation idea is as follows:

  • Define JSBridge to implement Jsb methods
  • Define JSBManager to manage calls to Jsb
  • Implement the override of the interceptor method
  • H5 side call

Define the JSBridge method class

Public class JSBridge {public void showToast(JSONObject JSONObject) {try { Toast.makeText(MainActivity.context, jsonObject.getString("content"), Toast.LENGTH_LONG).show(); } catch(Exception e) { } } }Copy the code

Define JSBManager to manage calls to Jsb

Public class JsbManager {public static Map<String, Method> methodMap = new HashMap<>(); public static Map<String, Method> methodMap = new HashMap<>(); public void init() { Method[] methods = JSBridge.class.getDeclaredMethods(); for(Method method : methods) { methodMap.put(method.getName(), method); }}}Copy the code

Implement the override of the interceptor method

The following is an example of overwriting the shouldOverrideUrlLoading method. The communication protocol defined in the example is myjsb://method? Params. The logic to invoke the corresponding client method is implemented by parsing the request in the intercepting method.

public class CustomWebViewClient extends WebViewClient { private JsbManager jsbManager = new JsbManager(); private JSBridge jsBridge = new JSBridge(); Public void initJsb() {// Initial jsbManager and jsBridge instances jsbManager.init(); jsBridge = new JSBridge(); } @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest Request) {// Only the URL of the JSB protocol is intercepted to handle the JSB protocol. String scheme = uri.getScheme(); If (scheme.equals(new String("myjsb"))) {String methodName = uri.getauthority (); String query = uri.getQuery(); try { JSONObject jsonObject = new JSONObject(query); Method method = jsbManager.methodMap.get(methodName); // Invoke method. Invoke (jsBridge,jsonObject); } catch(Exception e) { e.printStackTrace(); } } return super.shouldOverrideUrlLoading(view, request); }} public class MainActivity extends AppCompatActivity {@override protected void onCreate(Bundle) savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create WebViewClient CustomWebViewClient WebViewClient = new CustomWebViewClient(); // Call JSBridge initial logic webViewClient.initjsb (); WebView webView = (WebView) findViewById(R.id.webView); // setWebViewClient to handle webviewt notifications, requests, etc. Webview.setwebviewclient (WebViewClient); / / open the debugging webView. SetWebContentsDebuggingEnabled (true); WebSettings webSettings = webView.getSettings(); / / allow the JS webSettings. SetJavaScriptEnabled (true); Webview.loadurl ("file:///android_asset/index.html"); }}Copy the code

H5 side call

<div>this page test JSB</div> <script> function iframeCall(URL) {let iframe = document.createElement('iframe') iframe.src = url iframe.style.display = 'none' document.documentElement.appendChild(iframe) setTimeout(() => { document.documentElement.removeChild(iframe) }) } function callJsb(method, params) { let url = `myjsb://` if(! method) { return } url += `${method}` if(!! params) { url += `? ${encodeURIComponent(JSON.stringify(params))}` } iframeCall(url) } callJsb('showToast', { content: 'xiaohong' }) </script> </body>Copy the code

                                  

If iframe is used to send messages, there will be message loss, parameter restriction and other problems, which can be achieved by message queue and shouldIntercepting Interceptrequest method.

Intercepting specific methods

When initializing WebView, you can set WebChromeClient synchronously. WebChromeClient mainly assists WebView in handling Js dialog box, title and other operations. By intercepting corresponding methods of WebChromeClient, you can also achieve the calling end capability.

Implement WebChromeClient

public class CustomWebChromeClient extends WebChromeClient { @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, Log.d("mesage", message.startswith ("myjsb")+ ""); JsPromptResult result) { if(message.startsWith("myjsb")) { Toast.makeText(MainActivity.context, "PropmtCall", Toast.LENGTH_LONG).show(); Jspromptresult. confirm(result) return True; // If jspromptresult. confirm(result) return true; } else { return super.onJsPrompt(view, url, message, defaultValue, result); } // Set WebChromeClient CustomWebChromeClient WebChromeClient = new CustomWebChromeClient(); webView.setWebChromeClient(webChromeClient);Copy the code

H5 call

    window.prompt('myjsb://')
Copy the code

                                 

JSBridge is injected into the client

AddJavascriptInterface exposes client invocation logic to H5 when initializing the WebView.

Implement JSInterface

public class JsInterface { private Context context; public JsInterface(Context context) { this.context = context; @javascriptInterface public void showToast(String content) {// JsInterface is called by @javascriptInterface public void showToast(String content) { Toast.makeText(this.context, content, Toast.LENGTH_LONG).show(); }} / / at the time of initial WebView injection interface WebView. AddJavascriptInterface (new JsInterface (context), "myjsb");Copy the code

H5 call

    window.myjsb.showToast("Interface")  
Copy the code

                                   

Call Native Js

Nativa calls Js usually have the following schema:

  • loadUrl
  • evaluateJavascript

The following examples define global functions in H5 for Native calls

    function testNativeCall() {
      console.log("nativeCallJs")
      return 'nativeCallJs'
    }
Copy the code

loadUrl

The call can be made via webview.loadURL (” javascript: testNativeCall() “) (waiting for the Js to complete). The loadUrl mode refreshes the page and cannot retrieve the JS callback.

evaluateJavascript

webView.evaluateJavascript("javascript: testNativeCall()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { return; }});Copy the code

                                 

reference

Write a JSBridge from scratch

Welcome to follow my wechat public number – front small bench, study together