The mobile terminal development system around is mainly based on Hybrid scheme, but for a long time, Webview container and SDK management and other standards are not unified, the update is not timely. With more and more multi-environment development scenarios such as turning around/looking for beautiful machines/shopping man, adapting to different scenarios greatly affects the efficiency of business iteration. So we decided to redesign the SDK. Before I introduce the scheme. Let’s start with the basics.

JSBridge two-way communication principle

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

I. JS calls Native

There are many ways to implement JS invocation of Native. At present, the mainstream use is to intercept URL Scheme and MessageHandler.

1. Block the URL Scheme

The Web side creates a hidden IFrame for Scheme request. Android and iOS can intercept URL Scheme and resolve Scheme to determine whether to process the corresponding Native code logic.

On Android, Webview provides shouldOverrideUrlLoading method to intercept THE URL Scheme request sent by H5. The code is as follows:

public boolean shouldOverrideUrlLoading(WebView view, String url){
	// Read the url and analyze it
	
	// If false is returned, the WebView processes the linked URL. If true, the WebView executes the URL according to the program
	return true;
}
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 Web communicates with the client by dynamically creating an IFrame

function iosExecute (action, param) {
  param['methodName'] = action
  let iframe = env.createIframe()
  let paramStr = JSON.stringify(param)
  iframe.src = `zznative://zhuanzhuan.hybrid.ios/? infos=The ${encodeURIComponent(paramStr)}`
  document.body.appendChild(iframe)
  setTimeout(() = > iframe.remove(), 300)}Copy the code

2, MessageHandler

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

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

The Web side communicates by calling global variables injected by the client side

window.zhuanzhuanMApplication.executeCmd(action, oriParam)
Copy the code

2. Native calls 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.

[jsContext evaluateJavaScript:@"zhuanzhuanMApplication(ev, data)"]
Copy the code

Open source communication scheme introduction

So that’s how it works. But their own development of a complete and easy to use or more trouble, now we will introduce a better open source solution DSBridge.

Key features of DSBridge:

Android, IOS and Javascript are easy to use, lightweight and powerful, secure and robust.

  1. Both synchronous and asynchronous calls are supported
  2. Supports centralized management of apis in a class manner
  3. Support for API namespaces
  4. Support for debug mode
  5. Support API presence detection
  6. Support for progress callback: one call, multiple returns
  7. Supports Javascript to close the page event callback
  8. Support for Javascript modal/modeless dialog boxes
  9. Support Tencent X5 kernel

There is one more point I can introduce. DsBridge if used with fly.js. You can use the client’s communication capabilities directly. As we know, in browsers, Ajax requests are restricted by the same origin policy and cannot request resources across domains. However, one powerful feature of fly.js is that it supports request redirection: Redirect Ajax requests to the backend via any Javascript bridge, and fly.js provides a dsBridge adapter that can be easily used in conjunction with dsBridge. Since there is no same-origin policy on the end, fly.js can request resources from any domain. Another typical use scenario is in hybrid apps, where developers can implement unified request management, certificate verification, cookie management, access control, and so on, since fly.js can forward all Ajax requests to the end.

Turn around the problem

Having covered the fundamentals and good open source solutions, let’s take a look at the problems we face.

1. Communication protocols are not unified

You use a custom communication solution with 200 apis, and you use a dsbrige communication solution with 100 apis

2. The meanings of URL parameters are inconsistent with those of UA

There are many URL parameters and UA parameters on both ends, and there is no unified specification

3. Webiview is divided into old and new versions

While looking for beautiful machines to merge into the rotation, we did tech stack unification. The Webview around the migration to find beautiful machine, but find beautiful machine business is a lot of use of the old Webview, so in order to ensure the normal operation of the old business, can only keep two sets of Webview in parallel use

4. There are two sets of documentation, not a very good find API

5. SK document maintenance problems

Check the SDK documentation for accuracy and maintenance. Design the SDK as an object. If a new SDK needs to be added, inform the maintenance personnel to add it. Then the release can still be used, documentation and use of the test Demo written by the maintenance staff. But this makes the SDK bigger and bigger. And when students on the client find a document error, they can not directly modify the document, they need to feedback the problem, and can also modify. In summary, SDK document maintenance costs are huge.

Based on this, we and the client team set up a standard Webview group to build around the standard Webview container.

Turn around solution

1. Standardization related: client Cookie management, Url Query management, UA specification and communication format specification

We sorted out all the cookies, urls, UA, communication schemes and formulated specifications

The standard of UA

The UA of App is divided into two levels:

Public UA: Add a Key Value in the form of zz{Key}/{Value}. The Key starts with an uppercase letter, is separated by a space, and does not contain a space at the end.

User-defined UA: user-defined format within the APP.

There is no order between a public UA and a custom UA, but the zzApp field in a public UA must be the last.

ZzVersion/Client version zzT/ client terminal value zzDevice/ Whether the top bar penetration is supported _ Status bar height _ Device Pixel Ratio zzApp/App identifiers are as follows: ZzVersion / 8.18.20 zzT / 16 zzDevice / 1 _44. 0 _3. 0 58 zhuanzhuan zzApp /Copy the code

The standard of the Cookie

Background of Cookie: Because HTTP protocol is stateless, the website stores data to the user’s local terminal in order to identify the user’s identity, which is Cookie.

Therefore, from the perspective of Cookie design, it is designed to solve the problem of server saving data on the client side. The initiative of the storage container should be on the server side. The client should not interfere too much, even though the client has the API to modify Cookie, but unless the user can use cookie.clear() method when clearing the cache, You are not advised to modify cookies in other cases.

Second, cookies are attached to every HTTP request that can be carried.

Therefore, if the client wants to send values to H5, it is not recommended to use cookies, because these cookies will be carried to the server unchanged, occupying the size of the request header, resulting in traffic waste.

Based on the above consideration and research, we developed the standard of Cookie

  • The client theoretically no longer adds new cookies to the WebView

  • Cookies are written only to urls that have passed the Cookie whitelist

  • Cookie If an entry does not exist or the value of the entry is empty or an empty string, the entry shall be regarded as invalid. The invalid entry on the client may be any of the above three forms

  • When a client starts a WebView page, a Cookie is written before the first Url is requested and overwritten if the Cookie entry already exists

Url Query criteria

Url Query is mainly to solve H5 before the implementation of JS methods in this period of time, the page style, ability problems. For example, when loading the H5 page, you want the page background to be black. If you rely on Api implementation, the page will be non-black before executing the Api, which is not ideal.

After H5 fails to be loaded, the container layer can also set some configuration items. (It is not recommended to support a large number of configuration items on the failed page. Only a small number of configuration items are required on the failed page.) Example: H5 even if the load fails, the page can also slide closed.

Based on the above consideration and investigation, we developed the STANDARD of Url Query

  • Other problems that can be solved by relying on the Api are not recommended in THE Url Query.

  • The Url Query Name specification, which is defined in camel form but read by clients in a case-insensitive manner.

  • The Url Query matching specification complies with the Url standard specification. Parameters following # should not be identified.

  • For example, if key = 13 is not used for string matching, key = 1 will be mismatched.

Communication format specification

The previous communication protocol was not very standard, so we used the previous Api as V1, and then used V2 for the new Api. The communication format is divided into V1 version and V2 version. V1 and V2 are incompatible. Apis developed according to V1 standards will not be upgraded to V2 version, and V1 and V2 standards will coexist for a long time.

The protocol is divided into two layers: the framework layer and the business layer. Ordinary business development does not need to pay attention to the state part of the framework layer. State is the field that SDK communicates with the client to show some exceptions, such as the client does not have this method, etc. Other logic such as the field of the framework layer is transparent to the business layer. Code is used to judge the state, MSG is the prompt message, and data is the returned data.

callback('state'.'{code: "", msg: "", data: {}}')
Copy the code

Frame layer fields (v1 uses natural number style, V2 uses HTTP status code style)

Business layer common fields

Value (String) instructions
0 Business success
– 1 Business failure
– 1001. Invalid parameter (e.g. missing required parameter)

2. SDK reconstruction to realize the communication layer and bid farewell to frequent releases

It is easy to keep only the communication layer, but if the compatibility with the history of 300 apis is a more difficult problem, our solution is to keep the old or keep, all the new use the new Api communication solution, slowly migrate the old non-standard Api to the new communication solution

3. SDK document management background ensures timely update of documents

The document is generated using VuePress. Edit data through the admin background, and then generate MD documents dynamically. Run VuePress commands. Upload documents online using the scaffold command.

Based on the above optimization, we set up a mobile development platform website to facilitate FE to quickly find relevant documents

Looking forward to

After doing the above things, we still have a lot of challenges left to do.

1. Further standardization of SDK

The old Api capabilities were not standard. Sharing, for example, has five different apis that we need to consolidate into one full share. Standardizing all apis is a huge amount of work, so it has to be done bit by bit by the later specifications.

2. Complete user link monitoring

Now SDK monitoring is done separately from the front-end and client. We’re going to do full link monitoring

3. Precipitate Webview performance optimization scheme, reduce access cost, and cover a large range of business

There are many ways to optimize performance. But the cost of access is better. You need to change the code. Prepare to reduce access costs later.