Hybrid开发是现在的主流形式,对于业务快速迭代的公司尤其重要。曾将在鞋厂接触了很多关于Hybrid的理念,在这里分享一些Hybrid框架思想。
Hybrid框架包括Native与H5的通信,WebView的管理等,这里主要介绍通信。
文章主要分为两个部分,第一部分介绍Hybrid与H5通信的几种方式,第二部分分析了开源框架的具体做法。
第一部分 Hybrid与H5通信
Hybrid与H5通信实现方式有很多种,有基于url拦截的,也有基于prompt拦截的。
最后分析的这个框架和PhoneGap一样采用prompt拦截,但内部处理机制没有PhoneGap复杂,暂时对PhoneGap不是完全了解,就不装B了。
H5与Native通信,现在采用最多的方式是依赖中间过渡的WebView,其他的不了解。
基于对Hybrid的了解,就分H5调用Native和Native通知H5。下面来细说这两点。
1.H5调用Native
这种方式主要是需要Native宿主环境通过WebView来提供一些H5调用的接口方法。
如果采用url拦截的,也就是通过一个隐藏iframe或者修改location发起请求,比如bridge://service/method?params&callback,可以在webview加载时获取到该url,并针对url信息分析对应到Native中的某个service类的某个method方法。
如果采用prompt拦截的,比如prompt(service,method,params,callback),原理与url方式差不多,不过是在H5发起prompt请求,webview截获到这个prompt中的参数,调用Native中对应的某个service类的某个method方法。
这两种方式一般会与一个Bridge.js配合,Bridge.js封装了bridge://service/method?params&callback的构造,或prompt(service,method,params,callback)的请求,提供H5良好的访问接口。
当H5端调用某个方法时,将对应的参数和回调封装成url或prompt的形式,然后请求webview,webview截获url或prompt,请求本地服务获取数据后,通过注册在window对象上的callback将请求结果返回给H5。
这两种方式的开源库可参考:jsbridge-to-cocoa(url+bridge.js) safe-java-js-webview-bridge(prompt)
针对这两种基本方式可扩展,比如某所是直接采用了url+bridge这种方式,而鞋厂则针对性的做出些调整(后面针对性的介绍),还有后面介绍的safe-java-js-webview-bridge则与PhoneGap类似,消除了H5对Bridge.js的可见性,通过反射Native提供的service自动构造Bridge.js并注入到WebView中。
至于上面两种方式及其扩展的好坏之分,主要看设计上如何使H5调用变得简单则好,尽量降低Native与H5的耦合,分清构造Bridge.js的职责。
2.Native通知H5
这种方式主要是H5将某些监听事件(如webview下拉刷新、native推送)绑定到window上,当Native需要调用H5时,可以通过webview中注册的这些事件回调通知H5。
Native通知H5的方式比H5调用Native来的简单,不过在项目中如何将二者结合起来,提供统一的调用接口则需要良好的设计。
如果需要完成H5与Native的相互访问,基本上采用上面两种方法即可完成,但如果要封装的对H5调用接口友好,则需要在设计上下功夫,这就是仁者见仁智者见智的事情。
后续会分别补充某所和鞋厂各自对Bridge.js的封装思想。//TODO
第二部分 开源框架分析
1.iOS开源框架 jsbridge-to-cocoa
先来看看jsbridge-to-cocoa的源码结构,因为不存在太多的设计思想,仅仅是上述方式的一个实现过程。
采用url拦截的方式实现H5调用Native,但调用后没有回调的过程,而且还未实现Native通知H5的过程。(可能理解有偏差,大神勿喷)
下面说说这个框架的基本思想,Bridge.js中包含了供H5和Native使用的方法,分两步:
1. H5通过调用AddObject添加请求的参数和回调,通过SendObject封装的url来触发webview拦截;
2. Native中的webview拦截后,会分析url中的请求参数,调用本地服务,完成本地功能后会调用Bridge提供的接口,调用H5的回调
下面直接看看时序图,也比较易于理解。
注:描述过程和截图中都含有红色部分,是针对该框架的弱点提供的补充,即可保证H5访问Native后能回调H5的过程。
2.Android开源框架 safe-java-js-webview-bridge
抽空看了了下safe-java-js-webview-bridge的源码,整理了一份类之间的调用关系图。
值得推荐的是这个库屏蔽了H5对Bridge.js的可见性,而且Bridge.js是通过对Native中对外公开的类进行反射生成的,提高了复用性。
不过也有其缺点,Native提供给H5的方法都封装在一个Bridge.js中,如果Native需要暴露给H5的功能模块增多时,且需要按模块进行细分时,Bridge.js则显得有点模糊。
这个问题只需要对其原理熟悉,改造成支持多模块的成本也不大。后续补充源码连接,还在改造中。//TODO
注:这个库中Bridge.js这个文件名是不存在的,可自行指定,这里为了方便理解,所以采用Bridge.js。
下面说说开源库safe-java-js-webview-bridge的基本思路,分三步:
1.在native端编写调用本地功能的class(如HostJsScope.java),在初始化WebviewChromeClient时根据该class(在JsCallJava构造函数中)反射动态生成js代码;
2.将动态生成的js代码通过webview.loadUrl触发的onProgressChanged注入到webview中,供前端可调用;
3.在前端调用HostJsScope对应的接口,出发webview的onPrompt事件,进而调用本地HostJsScope方法,如果是同步且有返回值,通过prompt返回值返回,如果是异步,则反射调用JsCallback将数据返回前端。
先上图,后面逐步分析调用关系。(由于对UML时序图不甚了解,原谅图中的错误)
根据截图可以清晰的看到三个步骤的调用过程,如果有兴趣的可以拿源码对比该截图进行分析。
通过对以上两个开源框架的分析,可以理解H5调用Native并回调H5的通信过程,但二者都为对Native通知H5的通信实现,不过这部分实现也比较简单。原理上面也解释过了,通过截图来描述下。
Hybrid框架中H5与Native相互通信的过程基本如此,不过很多原理细节未做过多描述,如果兴趣的同学可以留言一起讨论。