如今的互联网时代也称移动互联网时代,基本上每个人每天都会花费大量时间在移动设备上,早期的移动端应用大都使用原生开发(android,ios),而现在的移动开发技术选型上基本都是混合开发(Hybrid),混合开发是一种开发模式,指使用多种开发模型开发App,通常会涉及到两大类技术:原生Native、Web H5
原生技术主要指iOS(Objective C)、Android(Java),原生开发效率较低,开发完成需要重新打包整个App,发布依赖用户的更新,性能较高功能覆盖率更高,发布流程较为复杂
Web H5主要由HTML、CSS、JavaScript组成,Web可以更好的实现发布更新,跨平台也更加优秀,但性能较低,功能实现也受限
混合开发的意义就在于吸取两者的优点,而且随着手机硬件的升级迭代、系统(Android 5.0+、ISO 9.0+)对于Web特性的较好支持,H5的劣势被逐渐缩小
原生、Web相互通信都离不开<code>JSBridge</code>。
在<code>Hybrid</code>模式下,H5会经常需要使用<code>Native</code>的功能,比如打开二维码扫描、调用原生页面、获取用户信息等,同时Native也需要向Web端发送推送、更新状态等,而<code>JavaScript</code>是运行在单独的<code>JS Context</code>中<code>(Webview容器、JSCore等)</code>,与原生有运行环境的隔离,所以需要有一种机制实现Native端和Web端的双向通信,这就是<code>JSBridge</code>:以JavaScript引擎或Webview容器作为媒介,通过协定协议进行通信,实现Native端和Web端双向通信的一种机制。
通过JSBridge,Web端可以调用Native端的Java接口,同样Native端也可以通过JSBridge调用Web端的JavaScript接口,实现彼此的相互调用。
首先了解下<code>webView</code>,<code>webView</code>是移动端(原生)提供的运行JavaScript的环境,它是一种嵌入式浏览器,原生应用可以用它来展示网络内容。可与页面JavaScript交互,实现混合开发,其中<code>Android</code>和<code>iOS</code>又有些不同:
<code>Android</code>的<code>WebView</code>采用的是低版本和高版本使用了不同的webkit内核,4.4后直接使用了Chrome。
<code>iOS</code>中<code>UIWebView</code>算是自<code>IOS2</code>就有,但性能较差,特性支持较差,<code>WKWebView</code>是<code>iOS8</code>之后的升级版,性能更强特性支持也较好。
<code>WebView</code>控件除了能加载指定的url外,还可以对URL请求、JavaScript的对话框、加载进度、页面交互进行强大的处理,之后会提到拦截请求、执行JS脚本都依赖于此。
Web端和Native可以类比于Client/Server模式,Web端调用原生接口时就如同Client向Server端发送一个请求类似,JSBridge在此充当类似于HTTP协议的角色,实现JSBridge主要是两点:
将Native端原生接口封装成JavaScript接口
将Web端JavaScript接口封装成原生接口
首先来说Native端调用Web端,这个比较简单,JavaScript作为解释性语言,最大的一个特性就是可以随时随地地通过解释器执行一段JS代码,所以可以将拼接的JavaScript代码字符串,传入JS解析器执行就可以,JS解析器在这里就是webView。
Web调用Native端主要有两种方式
4.2.1 拦截Webview请求的URL Schema
<code>URL Schema</code>是类URL的一种请求格式,格式如下:
我们可以自定义JSBridge通信的<code>URL Schema</code>,比如:<code>jsbridge://showToast?text=hello</code>
<code>Native</code>加载<code>WebView</code>之后,Web发送的所有请求都会经过WebView组件,所以Native可以重写WebView里的方法,拦截Web发起的请求,我们对请求的格式进行判断:
如果符合我们自定义的URL Schema,对URL进行解析,拿到相关操作、操作,进而调用原生Native的方法
如果不符合我们自定义的URL Schema,我们直接转发,请求真正的服务
Web发送URL请求的方法有这么几种:
安卓提供了<code>shouldOverrideUrlLoading</code>方法拦截
IOS<code>UIWebView</code>使用<code>shouldStartLoadWithRequest</code>,
IOS<code>WKWebView</code>则使用<code>decidePolicyForNavigationAction</code>
这种方式从早期就存在,兼容性很好,但是由于是基于URL的方式,长度受到限制而且不太直观,数据格式有限制,而且建立请求有时间耗时。
4.2.2 向Webview中注入JS API
这个方法会通过<code>webView</code>提供的接口,App将Native的相关接口注入到<code>JS</code>的<code>Context(window)</code>的对象中,一般来说这个对象内的方法名与Native相关方法名是相同的,Web端就可以直接在全局window下使用这个全局JS对象,进而调用原生端的方法。
Android(4.2+)提供了addJavascriptInterface注入:
在Web端直接调用这个方法即可:
上面已经说到了Native、Web间双向通信的两种方法,但站在一端而言还是一个单向通信的过程 ,比如站在Web的角度:Web调用Native的方法,Native直接相关操作但无法将结果返回给Web,但实际使用中会经常需要将操作的结果返回,也就是JS回调。
所以在对端操作并返回结果,有输入有输出才是完整的调用,那如何实现呢?
其实基于之前的单向通信就可以实现,我们在一端调用的时候在参数中加一个<code>callbackId</code>标记对应的回调,对端接收到调用请求后,进行实际操作,如果带有<code>callbackId</code>,对端再进行一次调用,将结果、callbackId回传回来,这端根据callbackId匹配相应的回调,将结果传入执行就可以了。
实现一个完整的JSBridge是比较复杂的,需要考虑一些低端机型的兼容问题、同步异步调用问题,好在已经有开源的JSBridge供我们直接使用了:
DSBridge,主要通过注入API的形式,DSBridge for Android、DSBridge for IOS
JsBridge,主要通过拦截URL Schema,JsBridge
以DSBridge-Android为例:
Hybrid开发是目前移动端开发的主流技术选项,其中Native和Web端的双向通信就离不开JSBridge 其中Native调用Web端是直接在JS的Context直接执行JS代码,Web端调用Native端有两种方法,一种是基于URL Schema的拦截操作,另一种是向JS的Context(window)注入Api,其中注入Api是目前最好的选择。完整的调用是双向通信,需要一个回调函数,技术实现上就是使用了两次单向通信
开源的JSBridge:DSBridge、jsBridge。
作者:前端南玖
出处:https://www.cnblogs.com/songyao666/
-------------------------------------------
个性签名:智者创造机会,强者把握机会,弱者坐等机会。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,可以关注下方公众号,在该公众号同样会推送技术文章给大家,谢谢~
欢迎加入前端技术交流群:928029210