HybridAPP 通过JSBridge提供调用Native功能的接口,让混合开发中的『前端部分』可以方便地使用地址位置、摄像头甚至支付等 Native 功能。它的核心是 构建 Native 和非 Native 间消息通信的通道,而且是 双向通信的通道。
JSBridge的实现原理
js调用Native
注入api/对象
原理:通过WebView提供的接口向js的context(window)注入一个对象或者方法,js调用时,直接执行对应的Native代码逻辑
iOS
UIWebVIew(iOS2+)和WKWebView(iOS8+)的调用方式有所区别
//假设ios客户端约定方法名为nativeBridge
//UIWebView
window.nativeBridge(message);
//WKWebView
window.webkit.messageHandlers.nativeBridge.postMessage(message);
Android
原理:通过WebView提供的addJavascriptInterface
方法给浏览器window
注入一个命名空间,然后给Web增加一些可以操作Java的反射。
// addJavascriptInterface
mWebView.addJavascriptInterface(new Class(), 'android');
//@JavascriptInterface
public class Class(){
@JavascriptInterface
public void method(){
}
}
// js 代码
window.android.method();
在 4.2 之前,Android 注入 JavaScript 对象的接口是 addJavascriptInterface,但是这个接口有漏洞,可以被不法分子利用,危害用户的安全,因此在 4.2 中引入新的接口 @JavascriptInterface(上面代码中使用的)来替代这个接口,解决安全问题。
拦截URL scheme
iOS
在UIWebView内发起的所有网络请求,都可以通过delegate函数在Native层得到通知。这样,我们就可以在UIWebView内发起一个自定义的网络请求,通常是这样的格式:jsbridge://methodName?param1=value1¶m2=value2
于是Native 拦截的请求中,我们只要发现是jsbridge://开头的地址,就不进行内容的加载,转而执行相应的调用逻辑。
缺点:
- 使用 iframe.src 发送 URL SCHEME 会有 url 长度的隐患。
- 创建请求,需要一定的耗时,比注入 API 的方式调用同样的功能,耗时会较长。
即使URL scheme链接有以上缺点,但因为它 支持 iOS6,所以为了实现兼容很多方案会使用这种方式
Android逻辑与iOS相似
改写浏览器原有对象
使用prompt,console.log,alert方式,在android webview这一层可以重写这些方法。
一般常使用prompt,因为这个在js里使用的不多,用来和native通讯副作用比较少。
prompt简单举例说明,Web页面通过调用prompt()
方法,安卓客户端通过监听onJsPrompt
事件,拦截传入的参数,如果参数符合一定协议规范,那么就解析参数,扔给后续的Java去处理。这种协议规范,最好是跟iOS的协议规范一样,这样跨端调起协议是一致的,但具体实现不一样而已。比如:hybrid://action?arg1=1
这样的协议,而其他格式的prompt
参数,是不会监听的,即除了hybrid://action?arg1=1
这样的规范协议,prompt
还是原来的prompt
。
Native调用JS
Native调用js实际就是执行拼接js字符串,从外部调用对应方法,返回js执行结果。因此js方法必须放在全局的Window上
iOS
是通过UIWebView
组件的stringByEvaluatingJavaScriptFromString
方法来实现的,该方法返回js脚本的执行结果。
//UIWebView
result = [uiWebview stringByEvaluatingJavaScriptFromString:javaScriptString];
//WKWebView
[wkWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
Android
在 Kitkat(4.4)之前是使用webview的loadUrl
进行调用的:
webView.loadUrl("javascript:JSBridge.trigger('webviewReady')");
而 Kitkat 之后的版本,也可以用 evaluateJavascript 方法实现:
webView.evaluateJavascript(javaScriptString, new ValueCallback<String>() {
@Override
publicvoidonReceiveValue(String value){
}
});
参考:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。