一、jsbridge的定义JSBridge是一个JS实现的Bridge,桥两端连接N??ative和H5。可以让Native在APP中方便的调用JS,JS调用Native,这是一个双向的通信通道。JSBridge主要提供JS调用Native代码的能力,实现查看本地相册、开启相机、指纹支付等原生功能。2.JSBridge的用途JSBridge,正如名字中“桥”的意思,是Native和非Native之间的桥梁。它的核心是在Native和non-Native之间建立一个消息通信的通道,是一个双向的通信通道。双向通信通道:1)JS向Native发送消息:调用相关函数,通知Native当前JS相关状态等2)Native向JS发送消息:回溯调用结果,推送消息,通知JS当前Native状态等。H5与Native的交互如下图所示:3.JSBridge的实现原理JavaScript运行在一个单独的JSContext中(例如WebView的Webkit引擎,JSCore)。由于这些Context与native运行环境天然隔离,我们可以将这种情况类比为RPC(RemoteProcedureCall,远程过程调用)通信,将Native和JavaScript之间的每一次相互调用都看成是一次RPC调用。在JSBridge的设计中,前端可以看成是RPC客户端,Native端可以看成是RPC服务器端,这样JSBridge要实现的主要逻辑就出现了:通信调用(Native和JS通信)并处理决议电话。四、JSBridge的通信原理1、JavaScript调用Native的方式JavaScript调用Native的方式主要有两种:注入API和拦截URLSCHEME。1、InjectAPIAPI注入方式的主要原理是通过WebView提供的接口,将对象或方法注入到JavaScriptContext(窗口)中,从而在调用JavaScript时,直接执行相应的Native代码逻辑,从而实现JavaScript调用Native的目的。对于iOSUIWebView,示例如下:JSContext*context=[uiWebViewvalueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];context[@"postBridgeMes??sage"]=^(NSArray*calls){//原生逻辑};前端调用方法:window.postBridgeMes??sage(message);2.拦截URLSCHEME首先解释一下URLSCHEME:URLSCHEME是一个类似于url的链接,是为了方便app之间直接调用而设计的。大致上,主要区别在于协议和host一般是自定义的,比如:qunarhy://hy/url?url=ymfe.tech,协议是qunarhy,host是hy。拦截URLSCHEME的主要过程是:Web端通过某种方法(如iframe.src)发送一个URLScheme请求,然后Native拦截该请求并根据URLSCHEME(包括其携带的参数)进行相关操作).在时间的过程中,该方法存在一定的缺陷:1)使用iframe.src发送URLSCHEME会存在url长度的隐患。2)创建请求需要一定的时间,比通过注入API调用相同的函数要长。因此:推荐使用API??注入的方式从JavaScript中调用Native。其次,从Native调用JavaScript的方法比从JavaScript调用Native简单。从Native调用JavaScript更简单,直接执行拼接好的JavaScript代码即可。JavaScript中的方法是从外部调用的,所以JavaScript的方法必须在全局窗口上。对于iOS的UIWebView,示例如下:result=[uiWebviewstringByEvaluatingJavaScriptFromString:javaScriptString];*javaScriptString为JavaScript代码字符串ForWKWebViewforiOS,示例如下:[wkWebViewevaluateJavaScript:javaScriptStringcompletionHandler:completionHandler];3、通信原理总结通信原理是JSBridge实现的核心1)推荐使用注入API的方式从JavaScript调用Native(iOS6无视,Android4.2以下使用WebViewClient的onJsPrompt方法)。2)Native调用JavaScript时,可以直接执行拼接后的JavaScript代码。4.JSBridge接口实现JSBridge接口主要有两个功能:调用Native(向Native发送消息)和被Native调用(接收Native消息)。因此,JSBridge可以这样设计:window.JSBridge={//调用Nativeinvoke:function(msg){//判断环境,获取不同的nativeBridgenativeBridge.postMessage(msg);},receiveMessage:function(msg){//处理消息}};在上面的文章中,提到了RPC中一个很重要的环节就是句柄解析调用,在JSBridge中体现为句柄与函数的对应关系。同时,我们将句柄抽象为桥名(BridgeName),最终演化为一个N??ative函数或一类Native消息对应的BridgeName。基于这一点,JSBridge的实现可以优化如下:window.JSBridge={//CallNativeinvoke:function(bridgeName,data){//判断环境,得到不同的nativeBridgenativeBridge.postMessage({bridgeName:bridgeName,data:data||{}});},receiveMessage:function(msg){varbridgeName=msg.bridgeName,data=msg.data||{};//具体逻辑}};对于JSBridge的Callback,其实就是RPC框架的回调机制。当然也可以用更简单的JSONP机制来解释:发送JSONP请求时,url参数中会有一个回调参数,其值对当前页面唯一,同时回调函数会作为键存入窗口,然后,服务器返回脚本,参数值也会作为句柄调用相应的回调函数。整体流程:在Native端实现JSBridgeJavaScript调用Native逻辑也很简单。主要代码逻辑为:接收JavaScript消息=>解析参数,获取bridgeName、data和callbackId=>根据bridgeName找到函数方法,以data为参数执行=>执行返回值和callbackId返回给前端.Native调用JavaScript也很简单,直接自动生成唯一的ResponseId,并存储句柄,然后连同数据一起发送给前端。5、如何引用JSBridge引用JSBridge常用的方法有两种,各有优缺点。1)Native端注入注入方式类似于从Native调用JavaScript,直接执行bridge的所有代码。优点:bridge的版本容易和Native保持一致,Native端不需要兼容不同版本的JSBridge;同时,缺点:注入时机不确定,注入失败后需要实现重试机制,保证注入成功率。同时,JavaScript端调用接口时,需要先判断JSBridge是否注入成功。2)被JavaScript端引用直接用JavaScript执行。它与从Native端注入正好相反。优点:JavaScript端可以判断JSBridge的存在,直接调用即可;缺点:如果bridge的实现发生变化,JSBridge需要兼容多个版本的NativeBridge或者NativeBridge兼容多个版本的JSBridge。