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