This article was first published on the blog of the front end team of zhengzhengyun: Xiaobai Must see, Preliminary study of JSBridge

The origin of JSBridge

In recent years, mobile terminals are becoming more and more popular. It has been a hot topic whether to choose Native or H5 in the development process. Native and H5 both have their own advantages and disadvantages. In order to meet the needs of the business, the company often integrates the two to carry out Hybrid development in the development process of actual projects. Native and H5 are located in two places, so it seems that they can not be connected. Then how can they realize functions together?

Cordova comes to mind. Cordova provides a set of device-specific apis that were used in the early days of JAVASCRIPT to invoke native code to implement native functionality. However, JSBridge’s widespread use in China is due to the popularity of the mobile Internet.

JSBridge is a JS implemented Bridge that connects Native and H5 at both ends of the Bridge. It conveniently allows Native to call JS in APP, and JS calls Native, which is a two-way communication channel. JSBridge mainly provides the ability of JS to call Native code to realize Native functions such as viewing local photo albums, opening camera, fingerprint payment, etc.

Comparison between H5 and Native

name H5 Native
The stability of Call system browser kernel, poor stability Use native kernel, more stable
flexibility Version iteration fast, flexible online Iterations are slow, app store reviews are required, and the launch speed is limited
Affected by network speed larger smaller
fluency Sometimes the load is slow, giving the user the feeling of “lag” Fast loading speed, more smooth
The user experience Features are limited by browsers and the experience is sometimes poor Native system API rich, can realize more functions, better experience
portability Compatible with cross-platform cross-system, such as PC and mobile terminal, iOS and Android Low portability, need to maintain two sets of code for iOS and Android

JSBridge two-way communication principle

  • JS call Native

There are many ways to implement JS invocation of Native, mainly including URL Scheme interception, prompt rewriting, API injection and other methods.

Intercept the URL Scheme

Both Android and iOS can intercept URL Scheme and parse Scheme to decide whether to process the corresponding Native code logic.

For Android, Webview provides shouldOverrideUrlLoading method to provide the URL Scheme request sent by Native interceptor H5. The code is as follows:

public class CustomWebViewClient extends WebViewClient {
  @Override
  public boolean shouldOverrideUrlLoading(WebView view, String url) {...// Scenario 1: Intercepting requests and receiving Schemes
    if (url.equals("xxx")) {

      // handle.// callback
      view.loadUrl("javascript:setAllContent(" + json + ");")
      return true;
    }
    return super.shouldOverrideUrlLoading(url); }}Copy the code

The iOS WKWebview can perform operations based on the intercepted URL Scheme and corresponding parameters. The code is as follows:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    if ([navigationAction.request.URL.absoluteString hasPrefix:@"xxx"]) {
        [[UIApplication sharedApplication] openURL:navigationAction.request.URL];
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}
Copy the code

The advantages of this method are that there is no vulnerability problem, the use of flexible, can achieve seamless switching between H5 and Native pages. For example, in the case of a page that needs to go online quickly, develop the H5 page first. A certain link is filled with H5 link. It will jump to H5 page before the corresponding Native page is developed. After the development of the Native page, it will intercept and jump to the Native page, and there is no need to modify the H5 link. However, using iframe.src to send URL Scheme requires the control of URL length, which is complicated and slow to use.

Override native JS methods such as prompt

Before Android 4.2, the interface for injecting objects was addJavascriptInterface, but it has been phased out for security reasons. This is typically done by modifying part of the browser’s Window object. It mainly intercepts four methods: Alert, Confirm, prompt and console.log, which are respectively monitored by onJsAlert, onJsConfirm, onConsoleMessage and onJsPrompt of Webview. Where onJsPrompt listens to the following code:

public boolean onJsPrompt(WebView view, String origin, String message, String 		defaultValue, final JsPromptResult result) {
  String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message,			 defaultValue);
  xxx;
  return true;
}
Copy the code

Due to the security mechanism of iOS, WKWebView intercepts alert, confirm, Prompt and other methods. If Native and JS interact in this way, three WKUIDelegate agent methods of WKWebView need to be implemented. A code example is as follows:

-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{

  UIAlertController *alertController = [UIAlertController					alertControllerWithTitle:nilmessage:message? : @"" preferredStyle:UIAlertControllerStyleAlert];

  [alertController addAction:([UIAlertAction actionWithTitle:@"Confirm" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

      completionHandler();

  }])];

  [self presentViewController:alertController animated:YES completion:nil];

}
Copy the code

When using this method, you can agree with Android and iOS on the format of parameter transmission. In this way, H5 can directly call Native by passing in different parameters without identifying the client. The rest is left to the client itself to intercept the same methods, identify the same parameters, and perform its own processing logic to achieve multi-endpoint consistency. Such as:

alert("Sure. XXX?"."Cancel"."Sure", callback());
Copy the code

In addition, if the method name, parameter passing and other call protocol specifications can be determined with Native, prompt methods of other formats will not be recognized and can play a role of isolation.

Into the API

With Webview’s capabilities, we can inject objects or methods into the Window. When JS is called through this object or method, corresponding logical operations are performed and Native methods can be directly called. In this way, JS needs to wait for Native to execute the corresponding logic before it can call back the operations inside.

Android Webview provides the addJavascriptInterface method for Android 4.2 and later.

gpcWebView.addJavascriptInterface(new JavaScriptInterface(), 'nativeApiBridge'); 
public class JavaScriptInterface {
	Context mContext;

  JavaScriptInterface(Context c) {
    mContext = c;
  }

  public void share(String webMessage){	    	
    / / Native logic}}Copy the code

Examples of JS calls:

window.NativeApi.share(xxx);
Copy the code

IOS UIWebview provides JavaScriptScore method and supports iOS 7.0 or later. WKWebview provides Windows. Its. MessageHandlers method, system support iOS 8.0 or more. UIWebview was common a few years ago, but it’s not common anymore. The following are examples of creating WKWebViewConfiguration and WKWebView:

WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKPreferences *preferences = [WKPreferences new];
preferences.javaScriptCanOpenWindowsAutomatically = YES;
preferences.minimumFontSize = 40.0;
configuration.preferences = preferences;
    

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"share"];
  	[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"pickImage"];
}
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self.webView.configuration.userContentController 	removeScriptMessageHandlerForName:@"share"];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"pickImage"];
}
Copy the code

Examples of JS calls:

window.webkit.messageHandlers.share.postMessage(xxx);

Copy the code
  • Call Native JS

Native JS invocation is relatively easy, as long as H5 exposes JS methods to the Window for Native invocation.

There are two main ways to do this in Android. Before 4.4, this was done by executing a piece of JS code via the loadUrl method. After 4.4, this can be implemented using the evaluateJavascript method. The loadUrl method is easy and concise to use, but it is inefficient to get results back and refresh the WebView when called. The evaluateJavascript method is efficient and easy to retrieve. It does not refresh the WebView when called, but only supports Android 4.4+. The relevant codes are as follows:

webView.loadUrl("javascript:" + javaScriptString);
webView.evaluateJavascript(javaScriptString, new ValueCallback<String>() {
  @Override
  public void onReceiveValue(String value){
    xxx
  }
});

Copy the code

IOS can pass in WKWebview evaluateJavaScript: javaScriptString, system support iOS 8.0 or more.

// swift
func evaluateJavaScript(_ javaScriptString: String, 
  completionHandler: ((Any? , Error?) -> Void)? = nil)
// javaScriptString Javascript code to invoke
// completionHandler executes the callback

Copy the code
// objective-c
[jsContext evaluateJavaScript:@"ZcyJsBridge(ev, data)"]

Copy the code

The use of JSBridge

  • How to reference

    • The H5 reference

      In the early version of our company’s mobile terminal, we adopted this method, which was called by introducing NPM package locally. This ensures that JSBridge exists and calls Native methods directly. However, if the later implementation of Bridge changes, both parties need to make more compatibility, resulting in high maintenance costs

    • By the Native injection

      This is the way our company chooses for mobile terminal at present. Considering the later business needs, the design is redesigned and Native injection is adopted to reference JSBridge. This is conducive to maintaining the consistency between API and Native, but the disadvantage is that the method and timing of Native injection are limited. JS needs to judge whether JSBridge injection is successful before calling Native

  • Use standard

Pseudocode instances of H5 calling Native methods, such as:

params = {
  api_version: "xxx"./ / API version
  title: "xxx"./ / title
  filename: "xxx".// File name
  image: "xxx".// Image link
  url: "xxx".// Url link
  success: function (res) {
    xxx;	// Execute after successful invocation
  },
  fail: function (err) {
    if (err.code == '2') {
      fail && fail(err);	// Called a version of the API that does not exist in the current client
    } else {
      const msg = err.msg;	// Exception informationToast.fail(msg); }}};window.NativeApi.share(params);

Copy the code

The following is a brief summary of the abstractions of the common approach, which currently basically follows the following specifications for two-terminal communication.

window.NativeApi.xxx({
  api_version:' '.name: "xxx".path: "xxx".id:	"xxx".success: function (res) {
    console.log(res);
  },
  fail: function (err) {
    console.log(err); }});Copy the code

Since H5 Native reference JSBridge was selected in the early version, Native injection was adopted in the later version. The existing H5 needs to be compatible with various situations, and the logical abstraction is as follows:

reqNativeBridge(vm, fn) {
  if(! isApp()) {// If the call is not made in APP
    vm.$dialog.alert({
      message: "This function requires access to the APP."}); }else {
    if (!window.NativeApi) {
      // For early versions
      vm.$dialog.alert({
        message: "Please update to the latest APP to use this feature."}); }else {
      // Only the error "called a version of API that does not exist in the current client" is handled
      // Other types of error messages are handled by specific businesses
      fn && fn((err) = > {
        vm.$dialog.alert({
          message: "Please update to the latest APP to use this feature."}); }); }}}Copy the code

conclusion

The above briefly introduces some of the principles of JSBridge. I hope it will be helpful for those of you who have never seen JSBridge before. If you need a deeper understanding of the principle and implementation of JSBridge, such as the encapsulation implementation of JSBridge interface invocation, the uniqueness of callback when JS calls Native, etc. You can go to more resources, refer to more detailed documentation or other people’s collation.

Recommended reading

Visual Construction System for Front-end Engineering Practice (PART 1)

Probably the most complete collection of text overflow truncation ellipsis schemes

An illustrated guide to unlock the mysteries of single sign-on

, recruiting

ZooTeam, a young passionate and creative front-end team, belongs to the PRODUCT R&D department of ZooTeam, based in picturesque Hangzhou. The team now has more than 50 front-end partners, with an average age of 27, and nearly 30% of them are full-stack engineers, no problem in the youth storm group. The members consist of “old” soldiers from Alibaba and netease, as well as fresh graduates from Zhejiang University, University of Science and Technology of China, Hangzhou Electric And other universities. In addition to daily business docking, the team also carried out technical exploration and practice in material system, engineering platform, building platform, performance experience, cloud application, data analysis and visualization, promoted and implemented a series of internal technical products, and continued to explore the new boundary of front-end technology system.

If you want to change what’s been bothering you, you want to start bothering you. If you want to change, you’ve been told you need more ideas, but you don’t have a solution. If you want change, you have the power to make it happen, but you don’t need it. If you want to change what you want to accomplish, you need a team to support you, but you don’t have the position to lead people. If you want to change the pace, it will be “5 years and 3 years of experience”; If you want to change the original savvy is good, but there is always a layer of fuzzy window… If you believe in the power of believing, believing that ordinary people can achieve extraordinary things, believing that you can meet a better version of yourself. If you want to be a part of the process of growing a front end team with deep business understanding, sound technology systems, technology value creation, and impact spillover as your business takes off, I think we should talk. Any time, waiting for you to write something and send it to [email protected]