Hybrid App Basics (iv) Principles of->jsbridge

Source: Internet
Author: User
Tags string format unique id hasownproperty

Description

Jsbridge Implementation principle

Directory
    • Objective
      • Reference sources
      • Front-facing technical requirements
      • Wedge
    • Principle Overview
      • Brief introduction
      • URL Scheme Introduction
    • Implementation process
      • Implementation ideas
      • First step: Design a global bridge object with native and JS interaction
      • Step two: JS how to call native
      • Step three: Native how to know the API is called
      • Fourth step: Analyze the format of url-parameters and callbacks
      • Fifth step: Native how to Invoke JS
      • Sixth step: Registration and format of API methods in H5
    • Further perfecting the Jsbridge plan
      • Ideas
      • Realize
      • Attention
    • The Complete Jsbridge
      • Full Call flowchart
      • Another implementation: Not using the URL scheme method
    • Implementation examples
      • Example description
      • Realize the source code
Preface reference Source

Walnuts, background shade, this article references the following sources

    • Github-webviewjavascriptbridge
    • Jsbridge-web Interactive iOS with native
    • Ios Android Hybrid app with Js Bridge
    • Hybrid App Architecture Design Ideas
    • "Android" How to write a Jsbridge
    • Use of the URL scheme for iOS
    • Marcuswestin/webviewjavascriptbridge
Front-facing technical requirements

Before reading this article, it is recommended to read the following articles first

    • Hybrid App Basics (iii)->hybrid app native and H5 page interaction principle
Wedge

This article briefly describes the Jsbridge, and why to use the Jsbridge, this paper details its implementation principle

Introduction to Principle overview

Jsbridge is a communication bridge between the native code and the JS code. One of the current unified scenarios is: H5 trigger URL scheme->native capture URL scheme-> native Analysis, execute---native call H5. Such as

URL Scheme Introduction

It mentions the concept of URL scheme, so what is this?

    • URL scheme is a URL-like link that is designed to make it easier for apps to call each other directly.

      Specifically, you can use the system's Openuri to open a URL-like link (can be put into the parameters), and then the system will be judged, if the system URL scheme, then open the System application, otherwise find out if there is an app to register this scheme, open the corresponding app

      It is important to note that this scheme must be registered by the native app before it takes effect, such as scheme (weixin://)

    • and the URL scheme in this article is a way to imitate the Jsbridge form.

      Specifically, the app does not register the corresponding scheme, but is triggered by the front-end page in some way (such as with IFRAME.SRC), and then native in some way to capture the corresponding URL trigger event, and then get the current trigger URL, according to the well-defined protocol, The analysis currently triggers that method and then executes according to the definition

Implementation process

Based on the above-mentioned principles, we now start to design a Jsbridge implementation

Implementation ideas

To implement Jsbridge, we can perform critical step analysis

    • First step: Design a global bridge object with native and JS interaction
    • Step two: JS how to call native
    • Step three: Native how to know the API is called
    • Fourth step: Analyze the format of url-parameters and callbacks
    • Fifth step: Native how to Invoke JS
    • Sixth step: Registration and format of API methods in H5

Such as:

First step: Design a global bridge object with native and JS interaction

We stipulate that the communication between JS and native must be achieved through a H5 global object Jsbridge, which has the following characteristics

    • The object is named "Jsbridge" and is a property of the Global Object window in the H5 page
      var jsbridge = window. Jsbridge | | (Window. Jsbridge = {});
    • The object has the following methods
      • Registerhandler ( string,function )H5 call Register Local JS method, after registration native can be called through Jsbridge. The method is registered to the local variable after the call messageHandlers
      • Callhandler ( string,json,function )H5 calls the native open API, which is actually triggered by the URL scheme after the call. The callback ID is stored in the local variable when called responseCallbacks
      • _handlemessagefromnative ( JSON )native calls native invoke H5 page registration method, or notifies H5 page to execute callback method
Step two: JS how to call native

In the first step, we define the global bridge object, we can call the native by its Callhandler method, then what kind of process does it have inside? As follows

Callhandler function Internal implementation process

The following steps have been taken internally during the execution of Callhandler:

    • (1) Determine if there is a callback function, if any, generate a callback function ID, and add the ID and corresponding callback into the callback function collection responseCallbacks
    • (2) through a specific parameter conversion method, the incoming data, the method name together, stitching into a URL scheme
      The format of URL SCHEME, such as//basic useful information is the following callbackid,handlername and data//native capture to this SCHEME will be analyzed var uri = custom_protocol_scheme:// Api_name:callbackid/handlername?data
    • (3) Use a hidden iframe that has been created internally to trigger scheme
      Create hidden iframe process var messagingiframe = document.createelement (' iframe '); messagingIframe.style.display = ' none '; Document.documentElement.appendChild (messagingiframe);//trigger schememessagingiframe.src = URI;

      Attention Normally, the effect of initiating a network request can be achieved by window.location.href, but there is a serious problem, that is, if we modify the value of window.location.href multiple times, the native layer can only receive the last request, the previous request will be ignored. So when the JS side initiates a network request, the IFRAME needs to be used so that the problem can be avoided. ---quoted from reference sources

Step three: Native how to know the API is called

In the previous step, we have successfully triggered the scheme on the H5 page, so how does the native capture scheme be triggered?

Depending on the system, Android and iOS have their own way of dealing with each other

Android Capture URL scheme

In Android (Webviewclient), triggered by a shouldoverrideurlloading URL scheme can be captured

public boolean shouldoverrideurlloading (WebView view, String URL) {//read to URL itself for parsing processing//If return false, WebView processes the link URL, If True, represents WebView according to the program to execute Urlreturn true;}

In addition, Android can not be triggered through IFRAME.SRC to trigger scheme,android can be window.prompt(uri, ""); triggered by the scheme, and then native by overriding Webviewclient onJsPrompt to get the URI

iOS capture URL scheme

In iOS, UIWebView has a feature: all network requests initiated within UIWebView can be notified through the delegate function at the native level. In this way, we can capture the trigger of URL scheme in WebView (the principle is to use shouldstartloadwithrequest)

-(BOOL) WebView: (UIWebView *) WebView shouldstartloadwithrequest: (nsurlrequest *) Request Navigationtype: ( Uiwebviewnavigationtype) Navigationtype {    Nsurl *url = [request URL];         NSString *requeststring = [[Request URL] absolutestring];    Get profit URL scheme to process yourself

Then native captures the URL scheme of the JS call, and then the next step is to parse the URL.

Fourth step: Analyze the format of url-parameters and callbacks

In the previous steps, native has received the JS call method, then, the original should be in accordance with the defined data format to parse the data

The format of the URL scheme has been mentioned earlier. After native receives the URL, you can extract the callback parameter ID, API name, and parameters in this format, and then follow the steps below

    • (1) According to the API name, the local search for the corresponding API method, and record the method after the execution of the callback function ID
    • (2) According to the extracted parameters, according to the parameters of the transformation of the well-defined

      If the JSON format requires manual conversion, the string format can be used directly if the

    • (3) Native local execution of corresponding API function method
    • (4) After the function is finished, find the callback function ID for this API call, and then assemble the parameters in a JSON format with the parameter information that needs to be passed.

      The JSON format for callbacks is:{responseId:回调id,responseData:回调数据}

      • Responseid string H5 the ID of the callback function that needs to be executed in the page, generated when the URL scheme is created in H5
      • The ResponseData JSON-type native needs to be passed to the H5 callback data, which is a JSON format:{code:(整型,调用是否成功,1成功,0失败),result:具体需要传递的结果信息,可以为任意类型,msg:一些其它信息,如调用错误时的错误信息}
    • (5) H5 page callback via Jsbridge notification

      Refer to native how to invoke JS

Fifth step: Native how to Invoke JS

In this step, the native through the Jsbridge call H5 js method or notify H5 to make a callback, specifically as follows

Pass the callback message to H5jsbridge._handlemessagefromnative (Messagejson);

As above, it is actually passing data to H5 through Jsbridge's _handlemessagefromnative, where the Messagejson data format differs according to two different types, as follows

Native Notify H5 page for callback

The data format is: Native notification H5 callback JSON format

Native Active call H5 method

When native actively invokes the H5 method, the data format is:{handlerName:api名,data:数据,callbackId:回调id}

    • HandlerName String Type needs to be called, the name of an open API in H5
    • The data JSON type needs to be passed in JSON format (because the first parameter that we receive in the fixed H5 method must be JSON and the second is a callback function)
    • Callbackid string native generated callback function Id,h5 after execution, through URL scheme notify the native API to execute successfully, and pass parameters

Note that in this step, if the API called by native is H5 not registered, there will be a corresponding error on the H5 page.

In addition, H5 call native, native processing finished must promptly notify H5 to make a callback, otherwise this callback function will not be automatically destroyed, many will cause a memory leak.

Sixth step: Registration and format of API methods in H5

As mentioned earlier, native actively calls the API method registered in H5, then how to register the API method for native invocation in h5? What are the formats?

API registered for native invocation in H5
Register a test function Jsbridge.registerhandler (' Testh5func ', function (data,callback) {alert (' Test function received data: ' +json.stringify ); Callback&&callback (' Test callback data ... ');});

If the code above is to register an API for native invocation

API formats registered in H5 note

As the above code, the registered API parameters are(data,callback)

One of the first data is the original, the second callback is internally encapsulated once, the execution of callback will trigger the URL scheme, notify the native fetch callback information

Further perfecting the Jsbridge plan

In the previous article, a set of Jsbridge schemes has been completed, here, how to improve the program under the introduction

Ideas

There is an open source project on GitHub, and its jsbridge approach is further optimized on iOS, so refer to his practice, which is further perfected here. Address Marcuswestin/webviewjavascriptbridge

The general idea is

    • H5 calls native's key step to split, by passing the previous direct URL scheme into a unified URL scheme, and then native proactively gets the passed arguments

      Perfect before: H5 call native-> to assemble all parameters into the URL scheme-> native capture scheme for analysis

      Perfect later: H5 call native-> to trigger a fixed URL by saving all parameters to local array--scheme-> native capture scheme-> native captures analysis using the Jsbridge active acquisition parameter

Realize

This perfect process is different from before, as follows

Jsbridge Object Plots

Jsbridge implementing the complete process

Attention

As the core of this perfect is: native invoke the JS function, and get the return value. Before Android4.4, Android is not this feature, so it is not fully applicable to Android

So generally will do a compatible processing, Android using the previous scheme method, iOS using the perfect after the program (also easy to 4.4 popularity after the completion of the follow-up)

The Complete Jsbridge

The above analysis of the implementation of the Jsbridge process, then the actual project, we should combine the above two, for Android and iOS different situations, unified a complete solution, as follows

Full Call flowchart

For example, a unified Jsbridge scheme is available after combining the above scheme

Another implementation: Not using the URL scheme method

The aforementioned Jsbridge are based on the URL scheme, but in fact, if you do not consider Android4.2 below, iOS7 below, in fact, can also use another set of options, as follows

    • Native Call JS method unchanged
    • JS Call native is no longer triggered by the URL scheme, but with its own interaction, such as

      Android, native through Addjavascriptinterface open a unified API to the JS call, and then the trigger URL scheme step to call this API, the rest of the steps unchanged (equivalent to the URL received parameters, Now becomes API function receive parameter)

      iOS, native through the JavaScriptCore inside the method to register a unified API, the rest of the same as Android (there is no need to actively get parameters, because parameters can be directly received by this function)

Of course, this is only a feasible solution, more than one choice, the specific implementation process please refer to the previous series of articles, this article will not repeat

Implementing the example Sample description

This article includes two examples, one for the basic version of the Jsbridge implementation, and one for the full version of the Jsbridge implementation (including Js,android,ios implementations, etc.)

Implement the source code base version of Jsbridge

Here only to introduce the implementation of JS, specific Android,ios implementation please refer to the full version, the implementation of the following

(function () {(function () {var hasownproperty = object.prototype.hasownproperty;var Jsbridge = window. Jsbridge | | (Window. Jsbridge = {});//jsbridge protocol defines the name var custom_protocol_scheme = ' Customjsbridge ';//outermost API name var api_name = ' Namespace_ Bridge ';//URL scheme iframevar messagingiframe = document.createelement (' iframe '); MessagingIframe.style.display = ' None '; messagingiframe.src = Custom_protocol_scheme + '://' + api_name; Document.documentElement.appendChild (messagingiframe);//The set of callback functions defined, the corresponding callback function will be executed after the native call has completed the corresponding method Idvar Responsecallbacks = {};//Unique ID, used to ensure the uniqueness of each callback function var uniqueId = 1;//Locally registered method collection, native can only invoke locally registered methods, otherwise it will prompt the error var messagehandlers = { };//the object that is actually exposed to the native call var Inner = {/** * @description Register the Local JS method by Jsbridge to native invocation * We stipulate that the native must pass Jsbridge to invoke the H5 method * Note that There are generally some requirements for local functions, requiring that the first parameter be data, the second parameter is callback * @param {String} HandlerName method Name * @param {Function} handler corresponding method */register Handler:function (HandlerName, Handler) {Messagehandlers[handlername] = handler;},/** * @description Call Native Open method * @param { String} HandlErname Method Name * @param {JSON} data parameter * @param {function} callback callback function */callhandler:function (handlerName, data, callback) {//If there is no dataif (arguments.length = = 3 && typeof data = = ' function ') {callback = Data;data = null;} _dosend ({Handlername:handlername,data:data}, callback);},/** * @description native Invoke H5 page registration method, or call callback method * @param {String} Messagejson the details of the corresponding method, you need to manually convert to JSON */_handlemessagefromnative:function (Messagejson) {SetTimeout (_ dodispatchmessagefromnative);/** * @description Handling native Methods */function _dodispatchmessagefromnative () {var message;try { if (typeof Messagejson = = = ' string ') {message = Json.parse (Messagejson);} Else{message = Messagejson;}} catch (e) {//todo handle the Exceptionconsole.error ("Native call H5 method error, incoming parameter error"); return;} The callback function var responsecallback;if (Message.responseid) {//here specifies that the callback function ID is responseidresponsecallback when the native execution method is ready to notify H5 when the callback is executed. = Responsecallbacks[message.responseid];if (!responsecallback) {return;} Executes the local callback function Responsecallback (message.responsedata);d elete responsecallbacks[mEssage.responseid];} else {//otherwise, represents the native active execution of the H5 local function if (message.callbackid) {////First to determine if a local H5 is required to execute the callback function//If a local function is required to perform a callback notification native, register the callback function locally and then call the native// Callback data has H5 function after execution is passed in var Callbackresponseid = Message.callbackid;responsecallback = function (responsedata) {//default is call Ejs The function above the API//and then the native know scheme is invoked to actively obtain this information//so the native should be judged at this time, to determine whether the function executed successfully, and receive data//This time the communication is complete (because H5 does not add callbacks to the callback, so there is no communication) _ Dosend ({handlername:message.handlername,responseid:callbackresponseid,responsedata:responsedata});};} Get var from locally registered function handler = messagehandlers[message.handlername];if (!handler) {//local not registering this function} else {//execute local function, Incoming data and callback handler (Message.data, responsecallback) as required;}}}}};/ * * * @description JS Call the native method, will send here to process * @param {JSON} message call method details, including the method name, parameter * @param {Function} responsecallback call The callback after the method */function _dosend (message, Responsecallback) {if (responsecallback) {///Fetch to a unique callbackidvar Callbackid = Util.getcallbackid ();//callback function added to the collection responsecallbacks[callbackid] = Details of the responsecallback;//method add key identifier of the callback function message[' Callbackid '] = callbackid;} Gets the trigger partyThe URL of the Schemevar uri = Util.geturi (message);//The method of using IFRAME jump scheme messagingiframe.src = URI;} var Util = {Getcallbackid:function () {///If the port cannot be resolved, it can be changed to Math.floor (Math.random () * (1 <<)); return ' cb_ ' + (uniqueId + +) + ' _ ' + new Date (). GetTime ();},//gets the URL scheme//the second parameter is compatible with Android in the practice//android because the primitive cannot get the return value of the JS function, it has to be transmitted via protocol GetURI: function (message) {var uri = Custom_protocol_scheme + ':/' + api_name;if (message) {//callback ID as Port exists var callbackid, method, PA Rams;if (Message.callbackid) {///First: H5 active call Native Callbackid = Message.callbackid;method = Message.handlername;params = Message.data;} else if (Message.responseid) {///second: After the native call H5, the H5 callback//In this case requires native self-analysis of whether the port is its defined callback callbackid = Message.responseid; method = Message.handlername;params = Message.responsedata;} parameter to String params = This.getparam (params);//uri supplemental uri + = ': ' + callbackid + '/' + ' + '? ' + params;} return Uri;},getparam:function (obj) {if (obj && typeof obj = = = ' object ') {return json.stringify (obj);} else {retur N obj | | ‘‘;}}}; for (Var key In Inner) {if (!hasownproperty.call (Jsbridge, key)) {Jsbridge[key] = Inner[key];}}) ();//Register a test function Jsbridge.registerhandler (' Testh5func ', function (data, callback) {alert (' Test function received data: ' + json.stringify ( Data), callback && callback (' Test backhaul data ... '); * ***************************api******************************************** * Open API for external calls * */window.jsapi = {};/** * **app Module * Some special operations */jsapi.app = {/** * @description Test function */testnativefunc:function () {//Call a test function Jsbridge.callhandler (' Te Stnativefunc ', {}, function (res) {callback && callback (res);});}}) ();
Full version of Jsbridge

Because of the content, has been extracted into a separate module, reference Hybrid app Basic (v)->jsbridge implementation Example

Hybrid App Basics (iv) Principles of->jsbridge

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.