preface
The core of Hybrid architecture is JSBridge interaction, and the premise of realizing this interaction is to make clear the interaction between H5 and Native terminal
This paper mainly introduces the interaction principle between Native terminal (Android/iOS) and H5 terminal (generally refers to the front end).
Native
withH5
Two ways of interacting
There are two ways to interact between native and front-end: url scheme and JavaScriptCore (addJavascriptInterface in Android)
Url Scheme works on all system devices (both lower Versions of Android and iOS)
However, URL scheme is implemented by URL interception after all, which has an impact on mass data transmission and efficiency
The other approach has problems of one kind or another in earlier versions
For example, JavaScriptCore does not support iOS7 or lower, and addJavascriptInterface has vulnerabilities prior to 4.2
Today, of course, the impact of these lower versions has faded
The url scheme interaction
This is the most popular interaction, because when Hybrid first came out, a lot of lower versions were compatible, so it was almost always used
Some concepts:
-
A URL scheme is a link similar to a URL. It is designed to facilitate apps to call each other directly
-
Specifically, you can use the OpenURI of the system to open a link similar to a URL (parameters that can be spelled in), and then the system will judge. If it is the url scheme of the system, open the system application; otherwise, you can check whether there is any app registered with such scheme and open the corresponding APP
-
It should be noted that this scheme will take effect only after the native APP is registered. For example, wechat scheme is (weixin://).
-
-
The URL scheme of mixed development interaction in this paper is a way to imitate the above form
-
Specifically, the front-end page triggers scheme in some way (such as using iframe.src), and then Native captures the corresponding URL triggering event in some way, and then gets the current triggering URL. According to the defined protocol, it analyzes which method is currently triggered, and then executes according to the definition
-
The protocol is similar to: quickhybrid:// XXX
-
Generally, the URL for this interaction does not need to be registered in the native app configuration
-
-
Note ⚠️ : ️ After iOS10, urlScheme must comply with the URL specification; otherwise, an error will be reported.
Basic Principles:
H5 -> triggers a URL (each function represents a different URL) -> Native terminal captures the URL -> Native terminal analyzes which function it belongs to and executes -> Native terminal calls the method in H5 to call back the execution result to H5Copy the code
The diagram below:
Advantages over other schemes:
-
Android4.2,addJavascriptInterface mode has a security leak
-
IOS7 or later,JavaScriptCore cannot be used
Therefore, if you need to be compatible with this type of lower version of the machine, the URL scheme scheme is the best choice
H5 interacts directly with Native
Including Android, iOS H5 and native call each other, summarized as follows:
-
H5 calls Android- natively registered via addJavascriptInterface, then called directly by H5
-
Android calls H5- natively called from loadUrl, 4.4 and above can also be called from evaluateJavascript
-
H5 iOS- Native JavaScriptCore registration (iOS 7 or above), and H5 call directly
-
IOS H5 – through stringByEvaluatingJavaScriptFromString
H5 adjustable Android:
First, a native WebView needs to register JS functions that can be called by the front end
WebSettings webSettings = mWebView.getSettings();
// The Android container allows JAVASCRIPT, which is mandatory
webSettings.setJavaScriptEnabled(true);
// The Android container sets the connection object
mWebView.addJavascriptInterface(getJSBridge(), "JSBridge");
Copy the code
// in Android4.2 or higher, local methods should be annotated with @javascriptinterface, otherwise methods will not be found.
private Object getJSBridge(){
Object insertObj = new Object(){
@JavascriptInterface
public String foo(){
return "foo";
}
@JavascriptInterface
public String foo2(final String param){
return "foo2:"+ param; }};return insertObj;
}
Copy the code
The functions registered in the native can then be called in H5
// Call method one
window.JSBridge.foo(); / / return: 'foo'
// Call method two
window.JSBridge.foo2('test'); / / return: 'foo2: test'
Copy the code
Note:
-
In Android4.2 and above (API 17 post), exposed apis should be annotated with @javascriptinterface, otherwise methods will not be found.
-
Before api17,addJavascriptInterface had the risk that a hacker could decompile Native registered Js objects and then capture sensitive information and corrupt them on the page by reflecting Java’s built-in static classes
Android tuning H5:
Before version 4.4
// The current WebView object
mWebView = new WebView(this);
mWebView.loadUrl("Javascript: method name (' parameter, need to be converted to string ')");
// run in the UI thread
runOnUiThread(new Runnable() {
@Override
public void run() {
mWebView.loadUrl("Javascript: method name (' parameter, need to be converted to string ')"); Toast. MakeText (Activity. This,"Call method...", Toast.LENGTH_SHORT).show(); }});Copy the code
After 4.4 (inclusive)
// Execute the JS code asynchronously and get the return value
mWebView.evaluateJavascript("Javascript: method name (' parameter, need to be converted to string ')".new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
// Where value is the return value of the corresponding JS method}});Copy the code
Note:
-
Before 4.4 Native calls JS methods by loadUrl, only a JS method can be executed, but the return value of this method cannot be obtained
-
4.4 and later, the JS method is invoked asynchronously through evaluateJavascript and the return value is retrieved from onReceiveValue
-
Mwebview.loadurl (“javascript: method name (‘ parameter, need to be converted to string ‘)”); The function needs to run in the UI thread because mWebView is a UI control (but has the disadvantage of blocking the UI thread).
H5 adjustable iOS:
In the case of OC
First, you need to import the JavaScriptCore library
#import <JavaScriptCore/JavaScriptCore.h>
Copy the code
Then the native API needs to be registered
// Set up some js interfaces after the webView is loaded- (void)webViewDidFinishLoad:(UIWebView *)webView{ [self hideProgress]; [self setJSInterface]; } - (void)setJSInterface{
JSContext *context =[_wv valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
// Register an API method named foo
context[@"foo"] = ^ () {// Get parameters
NSArray *args = [JSContext currentArguments];
NSString *title = [NSString stringWithFormat:@"% @",[args objectAtIndex:0]].// Do your own logic
// Returns a value of 'foo:'+title
return [NSString stringWithFormat:@"foo:%@", title];
};
}
Copy the code
Then the front end is ready to call
// Call the method with top to ensure that the call is at the top level, because the iframe needs top to get the top level
window.top.foo('test'); / / return: 'foo: test'
Copy the code
Note:
-
Add the official JavaScriptCore library (available in iOS7), and then bind the API to JSContext (then Html JS is called by default windowed. Top.* (iframe requires top)).
-
Before iOS7, JS cannot call Native directly, only indirectly through urlscheme
IOS adjustable H5:
// We can get the return value of the JS function execution
// Methods must be Html page bound to the topmost window object
/ / such as window. Top. Foo
// Swift
webview.stringByEvaluatingJavaScriptFromString("Method name (parameter)")
// OC
[webView stringByEvaluatingJavaScriptFromString:@"Method name (parameter);"];
Copy the code
Note:
-
When Native calls a JS method, it can get the return value of the JS method
-
When you have an IFrame, you need to get a reference to the top-level window
Back to root
- How to implement a Hybrid framework
The source code
Github implements the framework
quickhybrid/quickhybrid