jsbridge原理_前端和App开发者都要懂的JSBridge的原理

众所周知,app的一些功能可能会使用到H5开发,这就难免会遇到java与js的相互调用,像android利用WebViewJavascriptBridge实现js和java的交互,这里主要介绍下JsBridge的原理和使用。

626157c2107a4d9c788ef1164799c5ce.png

一、什么是JSBridge

JSBridge主要是给JavaScript提供调用Native功能的接口,让混合开发中的前端部分可以方便地使用Native的功能(例如:地址位置、摄像头)。而且JSBridge的功能不止调用Native功能这么简单宽泛。

JSBridge是一座用JavaScript搭建起来的桥,一端是Web,一端是Native,是Native和Web之间的桥梁。我们搭建这座桥的目的也很简单,让Native可以调用Web的js代码,让Web可以“调用”原生的代码。它的核心是构建Native和Web间消息通信的通道,而且这个通信的通道是双向的。

双向通信的通道:JS向Native发送消息:调用相关功能、通知Native当前JS的相关状态等。Native向JS发送消息:回溯调用结果、消息推送、通知JS当前Native的状态等。

H5与Native交互如下图:

cf4b03d66ef104bb5c03bb65404cc9fa.png

二、JSBridge的实现原理

JavaScript是运行在一个单独的JS Context中(例如WebView的Webkit引擎、JSCore)。由于这些Context与原生运行环境的天然隔离,我们可以将这种情况与RPC(Remote Procedure Call,远程过程调用)通信进行类比,将Native与JavaScript的每次互相调用看做一次RPC调用。

在JSBridge的设计中,可以把前端看做RPC的客户端,把Native端看做RPC的服务器端,从而JSBridge要实现的主要逻辑就出现了:通信调用(Native与JS通信)和句柄解析调用

7b40f33f265b462329ad0bf0dfd95098.png

三、JSBridge的通信原理

1.JavaScript调用Native的方式

主要有两种:注入API和拦截URL SCHEME

1.1 注入API

注入API方式的主要原理是,通过WebView提供的接口,向JavaScript的Context(window)中注入对象或者方法,让JavaScript调用时,直接执行相应的Native代码逻辑,达到JavaScript调用Native的目的。

iOS

UIWebVIew(iOS2+)和WKWebView(iOS8+)的调用方式有所区别

//假设ios客户端约定方法名为nativeBridge//UIWebViewwindow.nativeBridge(message);//WKWebViewwindow.webkit.messageHandlers.nativeBridge.postMessage(message);

Android

原理:通过WebView提供的addJavascriptInterface方法给浏览器window注入一个命名空间,然后给Web增加一些可以操作Java的反射。

//addJavascriptInterfacemWebView.addJavascriptInterface(new Class(), 'android');  //@JavascriptInterfacepublic class Class(){  @JavascriptInterface  public void method(){  }}//js 代码window.android.method();

备注:在4.2之前,Android注入JavaScript对象的接口是addJavascriptInterface,但是这个接口有漏洞,可以被不法分子利用,危害用户的安全,因此在4.2中引入新的接口@JavascriptInterface(上面代码中使用的)来替代这个接口,解决安全问题。

1.2 拦截URL SCHEME

解释一下URL SCHEME:URL SCHEME是一种类似于url的链接,是为了方便app直接互相调用设计的,形式和普通的url近似,主要区别是protocol和host一般是自定义的。

例如:esign://home/url?url=www.baidu.com,protocol是esign,host则是home。

拦截URL SCHEME 的主要流程是:Web端通过某种方式(例如iframe.src)发送URLScheme请求,之后Native拦截到请求并根据URL SCHEME(包括所带的参数)进行相关操作。

在时间过程中,这种方式有一定的缺陷:

  • 使用iframe.src发送URLSCHEME会有url长度的隐患。
为什么选择iframe.src不选择locaiton.href?因为如果通过location.href连续调用Native,很容易丢失一些调用。
创建请求,需要一定的耗时,比注入API的方式调用同样的功能,耗时会较长。

因此:JavaScript调用Native推荐使用注入API的方式

173af1a1b097c5941fccc5d6e8dd32a7.png

2.Native调用JavaScript的方式

相比于JavaScript调用Native,Native调用JavaScript较为简单,直接执行拼接好的JavaScript代码即可。

从外部调用JavaScript中的方法,因此JavaScript的方法必须在全局的window上。

iOS

对于iOS的UIWebView,示例如下:

//UIWebViewresult = [uiWebview stringByEvaluatingJavaScriptFromString:javaScriptString];

对于iOS的WKWebView,示例如下:

//WKWebView[wkWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler];

Android

Android

在Kitkat(4.4)之前是使用webview的loadUrl进行调用的:

webView.loadUrl("javascript:JSBridge.trigger('webviewReady')");

而Kitkat之后的版本,也可以用evaluateJavascript方法实现:

webView.evaluateJavascript(javaScriptString,new ValueCallback() {    @Override    publicvoidonReceiveValue(String value){    }});
7fe406408445401d3b254cae9aecf703.png

四、JSBridge 接口实现

从上面的剖析中,可以得知,JSBridge的接口主要功能有两个:调用Native(给Native发消息)和接被Native调用(接收Native消息)。因此,JSBridge可以设计如下:

window.JSBridge = {    // 调用 Native    invoke: function(msg) {        // 判断环境,获取不同的 nativeBridge        nativeBridge.postMessage(msg);    },    receiveMessage: function(msg) {        // 处理 msg    }};

在上面部分中,提到过RPC中有一个非常重要的环节是句柄解析调用,这点在JSBridge中体现为句柄与功能对应关系。同时,我们将句柄抽象为桥名(BridgeName),最终演化为一个BridgeName对应一个Native功能或者一类Native消息。基于此点,JSBridge的实现可以优化为如下:

window.JSBridge = {    // 调用 Native    invoke: function(bridgeName, data) {        // 判断环境,获取不同的 nativeBridge        nativeBridge.postMessage({            bridgeName: bridgeName,            data: data || {}        });    },    receiveMessage: function(msg) {        var bridgeName = msg.bridgeName,            data = msg.data || {};        //具体逻辑    }};

终极提问:消息都是单向的,那么调用Native功能时Callback怎么实现的?

对于JSBridge的Callback,其实就是RPC框架的回调机制。当然也可以用更简单的JSONP机制解释:

当发送JSONP请求时,url参数里会有callback参数,其值是当前页面唯一的,而同时以此参数值为key将回调函数存到window上,随后,服务器返回script中,也会以此参数值作为句柄,调用相应的回调函数。

整体流程:

在Native端配合实现JSBridge的JavaScript调用Native逻辑也很简单,主要的代码逻辑是:接收到JavaScript消息=>解析参数,拿到bridgeName、data和callbackId=>根据bridgeName找到功能方法,以data为参数执行=>执行返回值和callbackId一起回传前端。

Native调用JavaScript也同样简单,直接自动生成一个唯一的ResponseId,并存储句柄,然后和data一起发送给前端即可。

7285bb214990f718327f0940f1c8a582.png

五、JSBridge的总结

对于JSBridge的引用,常用有如下两种方式,但各有利弊。

1.由Native端进行注入

注入方式和Native调用JavaScript类似,直接执行桥的全部代码。

它的优点是:

桥的版本很容易与Native保持一致,Native端不用对不同版本的JSBridge进行兼容。

它的缺点是:

注入时机不确定,需要实现注入失败后重试的机制,保证注入的成功率,同时JavaScript端在调用接口时,需要优先判断JSBridge是否已经注入成功。

2.由JavaScript端引用

直接与JavaScript一起执行。

它的优点是:

JavaScript端可以确定JSBridge的存在,直接调用即可。

它的缺点是:

如果桥的实现方式有更改,JSBridge需要兼容多版本的Native Bridge或者Native Bridge兼容多版本的JSBridge。

至此,JSBridge的原理介绍完毕,欢迎大家转发留言进行交流。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值