Hybrid
为什么需要这种设计,或者技术方案,我们就不多说了,但是我还是要强调几点个人的见解
- 最好不要大面积使用此方案,以免影响用户体验,最好别超过项目的30%。
- 在某些页面变化比较大,而又不太需要性能的页面,采取此设计非常合适
- 还有一个非常重要的,一定要注意,此交互方案在app内是异步线程,注意要回到主线程处理UI。安卓和iOS都是如此!!!
在安卓上面
我们有三种方案,分别是
- Native提供方法,js调用Native方法
- Native在本地注入js方法并且调用
- Webview拦截Ajax请求,并做业务处理
Native提供方法,js调用Native方法
- native注入对象(有一系列供js使用的方法)以及提供给js调用的名称。
1
2webView.addJavascriptInterface(new HybridJsInterface(),"HybridJSInterface");
- native提供可以供js调用的方法。
1
2
3
4
5public class HybridJsInterface {
final public void hello(String text)
Log.i("method hello","text="+text);
} - js调用native的方法。
1
2
3function hybrid(){
window.HybridJSInterface.hello("hello hybrid");
}
Native在本地注入js方法并且调用
1 | // function helloJs(){ |
1 | String handle = "helloJs()"; |
Webview拦截Ajax请求,并做业务处理
native拦截h5发过来的请求协议(自定义协议)。
webview位置拦截的WebViewClient对象。1
webView.setWebViewClient(new HybridWebViewClient());
HybridWebViewClient重写shouldOverrideUrlLoading方法
1
2
3
4
5public boolean shouldOverrideUrlLoading(WebView view, String url) {Uri parse = Uri.parse(url);
String path = parse.getPath();witch (path) {
//TODO
}
}js那边发起请求协议。
方案分析
这三种方案单独使用都比较有局限性。
方案一的思路是native提前给h5实现好h5需要使用的方法,方法调用完全由h5控制,缺陷是h5调用的功能实现都由native实现,当h5页面中需要新功能的时候需要修改native才能支持。
方案二的思路是js提前给native提供方法,方法调用完全由native控制,缺陷是当js提供了新的方法那么需要修改native主动调用才能使用新功能。
方案三的思路是native拦截h5发过了的请求进行分发控制,js需要使用的功能是native已经提前准备好的,使用不同的url进行分发来使用,缺陷是h5使用新的功能那么需要修改native提供新功能。
单独使用这三种方案的共同缺点就是js和native都是一个单向的调用,相互太过依赖。要是三种方案都用上是不是可以解决问题呢,其实根本问题不在这里,而在于这些方案都没有办法动态扩展,也就是说native一旦完成之后那么单纯靠js是很难完成功能扩展的。我们需要一种可以适应一定程度动态扩展的方案,那就让h5作为项目主导,native提供服务。
hybrid设计
总体设计思路是h5控制整个业务流程以及交互流程。h5那边负责发命令并且回调,native负责响应命令。我是采用方案三来实现,客户端需要做的就是预先处理好这些命令(url)。既然是响应命令那么首先就需要把和业务无关的命令给整理出来,比较通用的包括下面内容(不一定全):
- header控制。
heade的样式可以参考新闻类app的详情页(这里不截图),包括内容:左边按钮(多个),右边按钮(多个),主标题,副标题。
需要做的控制是左、右按钮是否显示、显示的文本及图标以及点击按钮的回调,主、副标题是否显示及显示内容。
- 页面刷新。
页面刷新用于内容改变之后h5主动通知native进行刷新。
- 页面跳转。
页面跳转分成两种一种是页面跳转到一个新的native页面,另一种是在webview内部做跳转。native的跳转包括内容:跳转动画、跳转目标页、目标页需要的参数。
- loadingview/progressbar。
通常情况建议直接使用h5的进度显示。loadingview的控制包括:loadingview是否显示,loadingview的显示样式(通常只有一种样式)。
- 传感器数据。
传感器这部分不一定每个应用都需要。比如某些h5页面需要做活动,那么里面可能会用的摇一摇这样的功能。传感器的控制包括:地理位置、方向、震动、运动量。
- h5离线包更新。
离线包的更新对于h5来说是一条更新命令。不过在native实现上面需要包括:离线包更新检查(版本比较)、离线包下载、离线包解压保存。
- 离线包开关。
是否使用离线数据。native需要做的是开启离线包命令之后需要把请求的url映射到本地文件缓存。
- 数据请求。
数据请求是指h5需要请求数据不通过直接网络访问,而是通过native自己的网络服务获取数据,尤其是在跨域的情况下很方便。
iOS上面
同样的,iOS也具备上述三个方案,分别是
- JavaScriptCore
- WebviewLoad
- Url Schema
JavaScriptCore
在ios7后,Apple新增了一个JavaScriptCore让Native可以与H5更好的交互(Android早就有了),我们这里主要讨论js如何与Native通信,这里举一个简单的例子:
① 首先定义一个js方法,这里注意其中调用了一个没有声明的方法:
1 | function printHello() { |
然后,上述未声明方法事实上是Native注入给window对象的:
1 | NSString * scriptPath = [[NSBundle mainBundle] pathForResource:@"hello" ofType:@"js"]; |
这个样子,JavaScript就可以调用Native的方法了,这里Native需要注意方法注入的时机,一般是一旦载入页面便需要载入变量
- 此方案需要特别注意的就是注入时机,要保证JS能调用到注入的方法
WebviewLoad
此方案和安卓一样
1 | [self.wkWebView loadHTMLString:@"javascriptStr" baseURL:@"urlstr"]; |
Url Schema
H5与Native交互的桥梁为Webview,而“联系”的方式是以url schema的方式做的,在用户安装app后,app可以自定义url schema,并且把自定义的url注册在调度中心, 例如
- dongfangdi://open 打开懂房帝App
- weixin:// 打开微信
事实上Native能捕捉webview发出的一切请求,所以就算这里不是这种协议,Native也能捕捉,这个协议的意义在于可以在浏览器中直接打开APP,
我们在H5获取Native方法时一般是会构造一个这样的请求,使用iframe发出(设置location会有多次请求覆盖的问题):
1 | requestHybrid({ |
总结
由于一开始我就强调过,不要完全依赖Hybrid来做app主要框架,它只是为我们提供更多的页面热更新,页面获取Native信息的一种技术。
- 在iOS8.0以后,WebKit框架又给我们提供了一套方案
- 在WKUserContentController类中,我们可以看到这个方法然后我们可以在下面这个方法中处理对应的name
1
2
3
4
5
6
7
8/*! @abstract Adds a script message handler.
@param scriptMessageHandler The message handler to add.
@param name The name of the message handler.
@discussion Adding a scriptMessageHandler adds a function
window.webkit.messageHandlers.<name>.postMessage(<messageBody>) for all
frames.
*/
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;强烈推荐此方法!!!1
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{}
相关demo代码已放在github上
- https://github.com/Jack-Ving/Hybrid_Interaction 这个是用Vue写的对应的js代码
- https://github.com/Jack-Ving/Hybrid 这个是采用拦截的方式写的OC代码
由于仓促,如果遇到什么问题,尽管联系我.
QQ:727881945 微信:Q727881945