
developers who have been involved in hybrid development are familiar with frameworks such as ionic and phonegap. these frameworks cover a web-based app in a native layer and then call the local library through the jsbridge technology.
before diving into the details of jsbridge technology, let us briefly explore the traditional implementation process.
calling js in native is relatively simple: you just need to observe the rule of "<code>javascript: method name ('parameter, needed to be converted to string')</code>".
<b>call method before android 4.4:</b>
<b>call method for android 4.4 and newer:</b>
description:
before android 4.4, native calls js method through loadurl. in this approach, only a js method is executed, but the returned value of this method cannot be obtained.
for android 4.4 and newer versions, the js methods are called asynchronously through evaluatejavascript and the returned value is available in onreceivevalue.
this method is not suitable for transmission of large amounts of data (the interface approach is recommended for a large amount of data).
mwebview.loadurl("javascript: the mwebview.loadurl ("javascript:method name ('parameter, needed to be converted to string'")") function needs to be run in the ui thread because mwebview is a ui control.
the call of native in js requires the @javascriptinterface annotation to the webview. there is a loophole, which will be explained later. to make js native, you need to set the following attributes for webview:
here we see <code>getjsbridge()</code>. in native, <code>addjavascriptinterface</code> is used to add an exposed js bridge object, and then the corresponding api method is declared inside the object.
calling the native method in html.
in android 4.2 (api17) and newer versions, the exposed api should carry an <code>@javascriptinterface</code> annotation. otherwise, the method will not be found.
before api17, <code>addjavascriptinterface</code> has a potential security risk. hackers can get the native-registered js object by decompiling and obtaining sensitive information, and then launching attacks by reflecting java's built-in static classes on the page.
js calls native-exposed api and gets the corresponding returned value.
the method to call js in native is relatively simple. native calls the function that html binds to the window through stringbyevaluatingjavascriptfromstring. note the oc and swift writing styles.
when you call js methods in native, you can get the returned value of the js method.
in native, the api can be bound to jscontext through the introduction of the official javascriptcore library (ios7 and above) (and then js can be called in html through window.top. ***).
introduce the official library file
native registers the api function (oc)
calling native methods in js in html
this approach was not available until ios 7. prior to ios7, js could not call native directly. js can call native indirectly only through jsbridge.
js can call the exposed api and get the corresponding returned value.
native ios cannot be called by js, but apis can be made open to js calls by introducing the official third-party "javascriptcore".
as its name implies, jsbridge serves as a bridge between js and native. in fact, jsbridge, also known as the hybrid app technology, is a communication method between js and native. in jsbridge, native calls js only through a fixed bridge object, and vice versa.
the process of jsbridge implementation can be summarized as follows. an h5 page triggers a url in some way and native captures the url for analysis. native then performs the processing and calls the h5 jsbridge object for transfer and callback.
since the native webview/uiwebview controls have already achieved data communication with js, why do we still need jsbridge?
the following list describes the motivations for using jsbridge:
the addjavascriptinterface method has security loopholes in the versions lower than android 4.2.
js is unable to call native in versions lower than ios 7.
the url scheme interaction is a set of existing mature solutions that are perfectly compatible with various versions and with the technology of older versions.
url scheme is a link, like the url, designed to facilitate direct mutual calls between apps. you can open the system application for a system url scheme. otherwise, you can try to find whether an app has registered such a scheme and open that corresponding app.
note: a scheme will be valid only after native app registration is completed.
however, in an actual development scenario, the app does not register the corresponding scheme. instead, the front-end page triggers the scheme (such as iframe.src) in some way. native captures the corresponding url to trigger the event and gets the current triggering url, and then native checks if the method is triggered according to the defined protocol.
to implement jsbridge, we need to analyze the following steps:
step 1: design a global bridge object for native to interact with js
step 2: how js calls native
step 3: how native knows that the api is called
step 4: url-parameter and callback format
step 5: how native calls js
step 6: registration and format of the api method in h5
the figure below shows the complete process of jsbridge:
we stipulate that the communication between js and native must be implemented through an h5 global object – jsbridge. the object has the following characteristics:
the object name is "jsbridge", which is an attribute of the global object window in the h5 page. it is elaborated as:
this object has the following methods:
registerhandler (string, function) h5 call. it registers the local js method, after which native can make the call through jsbridge. after the call, the method is registered in the local variable messagehandlers.
callhandler (string, json, function) h5 call. it calls the native open api, after which the url scheme is triggered locally. during the call, the callback id is stored in the local variable responsecallbacks.
_handlemessagefromnative (json) native call. native calls the method registered on the h5 page, or notifies the h5 page of the execution of the callback method.
after we define the global bridge object, we can use its callhandler method to call the native api.
<b>internal implementation process of the callhandler function</b>
the callhandler execution includes the following internal steps:
1.determine whether a callback function exists. if yes, a callback function id is generated, and the id and the corresponding callback is added to the callback function set responsecallbacks.
2.the input data and method name are spliced into a url scheme through a specific parameter conversion method.
3.a internal hidden which has long been ready iframe is used for triggering the scheme
note: normally it is possible to initiate a network request through window.location.href. however, there is a very serious problem when we change the value of window.location.href several times in succession: the native layer can only receive the last request, while ignoring all the previous ones. to avoid this problem, we need iframe to initiate network requests at the js end.
in our previous step, we successfully triggered the scheme on the h5 page.
our next step is to explore how native captures the scheme triggering event.
android and ios have their respective handling approaches.
in android (in webviewclient), the <code>shouldoverrideurlloading</code> helps to capture the url scheme triggering event.
ios, uiwebview has a unique feature: all the network requests initiated in the uiwebview can be notified to the native layer through the delegate function. in this way, we can capture the url scheme triggering event in webview (the principle is to use <code>shouldstartloadwithrequest</code>).
in previous steps, native has received a js call method. in the next step, native should parse the data according to the defined data formats. native can extract the callback parameter id, api name, and parameters following this format after receiving the url, and then follow the steps below.
search for the corresponding api method locally according to api name, and record the callback function id after the method is executed.
convert the extracted parameters according to the defined parameters.
native executes the corresponding api function method locally.
after function execution, find the corresponding callback function id of this api call, and then assemble the information with the parameter information to be passed into a json format parameter.
notify the h5 page for callback via jsbridge.
in this step, native calls h5 js methods through jsbridge or notify h5 for callback. the messagejson data format in it has two different types.
<b>native notifies h5 page for callback: </b>
as per the data format, native notifies h5 about the callback json format.
<b>native takes the initiative to call the h5 method: </b>
when native takes the initiative to call h5 methods, the data format is: {handlername: the api name, data: data, callbackid: the callback id}:
handlername string type: the open api name to be called in h5
data json type: the data to be passed. its format is fixed to be json (because we fix the format of the first parameter received by methods registered in h5 to json, and the second to a callback function)
callbackid string type: the callback function id generated by native. after h5 execution, the url scheme is used to notify native about the successful execution of the api and to pass the parameter.
previously we mentioned that native takes the initiative to call the api methods registered in h5.
let us now study, how we can register api methods in h5 for the native to call.
as indicated in the code above, the first data is the data passed by the native. the second callback is encapsulated once internally. after the callback is executed, it triggers the url scheme and notifies the native to get the callback information.
the diagram below shows a jsbridge object.
the following diagram illustrates the full process of jsbridge implementation.
in an actual development, how can we develop a unified scheme for different situations in both android and ios?
the jsbridge mentioned above is based on the url scheme. however, if you do not plan to support versions lower than android 4.2 and ios 7, you must consider another scheme.
native calls of js methods remain unchanged
js calls of native are no longer through triggering the url scheme, but through the built-in interaction. specifically, in android, native opens a unified api for js to call through addjavascriptinterface. then the url scheme triggering step is changed to call of the api while the other steps remain the same.
in ios, native registers a unified api through methods in javascriptcore, and the other steps are the same with those in android.
javascript bridge is a unified messaging system that enables easy building of cross-language services that allow you to share data and real-time updates among your servers and clients. this article explores in detail the profiling of jsbridge and its implementation process in both ios and android respectively.