Hybrid App 开发模式

  开发移动App主要有三种模式:Native、 Hybrid 和 Web App。

  需要注意的一点是在选择开发模式的时候,要根据你的项目类型(图片类?视频类?新闻类?等),产品业务和人员技术储备等做权衡。

  Hybrid开发模式就是既有Native开发也有Web app的开发。那我们怎么去确定App中某个功能模块使用Native还是Web开发?它们之间如果需要接口通信又该如何去实现呢?又该如何更好的去维护Hybrid App产品呢?

1、Native or Web开发模块

  当我们选择用Hybrid模式开发App时,应先熟悉项目整个框架和App各个模块。然后将通用的,对性能要求不是那么高的App界面可抽出来作为web界面开发,Native直接调用。一般Hybrid App开发,App界面之间的跳转关系由Native实现并完成,web界面主要作为内容填充到Android和iOS的浏览器控件中。拉手网之前Android客户端就是采用这种模式,Native搭一个App框架壳,里面展示内容和网络请求全部由web实现。由于客户端浏览器控件版本不同,web界面加载,渲染和缓存机制等原因,这种模式开发的App整体在图文比较多的情况下体验就不太好,甚至可能会出现意想不到的奇葩问题。 建议图文列表,涉及到视频等多并发和界面元素比较负责或具有很强的动画特效的情况优先考虑Native开发。 这方面在Android尤其有必要,Android 4.4之前的浏览器控件WebView基于缺省的WebKit内核,它不同于Chromium所使用的Webkit内核;而在4.4之后(包括4.4)的WebView的实现被替换成Chromium WebKit内核。当我们想让App尽可能的在低版本也能运行良好时,就需要不断做兼容性开发和测试了,除非自己在App里面打包编译最新WebView源码,类似开发一个浏览器。

2、Native & web 通信

  • Native调用js方法

Android和iOS都提供了API直接调用:

webview.loadUrl("javascript:functionName(\"" + argument + "\")");

别忘了设置 webview.getSettings().setJavaScriptEnabled(true);

[webView stringByEvaluatingJavaScriptFromString:@"alert('hello world!')"];
  • js调用Native方法。

Android实现js调用native方法一般是先编写供js调用的类,然后通过添加javascripteInterface的方法,如

webView.addJavascriptInterface(pandoInterface, "pando");

  将java对象pandoInterface生成js对象pando,然后直接window.pando就可以调用pandoInterface对象里面的方法。需要注意的是供js调用的pandoInterface对象里面的java方法需手动加上@JavascriptInterface注解,这个是Google为解决安全问题引入的。

  iOS实现js调用Native方法相对繁琐一点。主要是iOS原生并没有提供js直接调用native的方式,只能通过UIWebView相关的UIWebViewDelegate协议的方法来做拦截,并在这个方法中,根据url的协议或特征字符串来做调用方法或触发事件等工作。当js需要调用Native方法时,js创建一个隐藏的iframe设置或改变其src就会触发Native拦截url事件。

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
if ([[url scheme] isEqualToString:@"someFunction") {
//调用原生方法
return NO;
} else {
return YES;
}
}

  不知道大家发现没有,以上两种方法都只是实现了js调用Native方法,但是都没有实现js函数回调,将Native方法返回结果传递给js。

  微信开放了很多jsApi接口,供大家直接调用微信Native的功能。通过jsApi接口和文档我们会发现里面实现了Native方法执行结果回调给js。这种Hybrid App开发模式很好的利用了Native高性能,多并发的优势,将网络请求,扫码等复杂的逻辑或者web不可能实现的功能由Native完成,而web只是做了界面显示效果。将微信Android安装包解压之后,在assets/jsapi目录下有个80多kb的wxjs.js文件,里面实现了微信jsApi逻辑jsbridge。下面主要简单介绍一下这种jsbridge实现原理。

  jsbridge核心难点在于如何在Native方法执行完之后将返回接口给js,并且让js能理解传过来的参数所表达的意思。针对这,我们可以在js调用Native方法之间,将js一次调用Native的唯一标示符identifier和期望Native调用完后执行的回调函数存储在Map里面,将identifier和其他参数传递给Native,native执行完成后,将identifier和执行结果作为参数调用js函数,在js函数里面解析参数,得到identifier,然后在Map里查询对应的回调函数,将native执行结果作为参数传递进去调用。有点绕,但是巧妙的利用消息传递机制,实现js调用Native进行回调函数调用,同理,Native调用js函数将返回结果给Native调用也是可以的。

  Android在实现jsbridge时,早期方法也是需要iOS那样,先给web界面创建iframe,然后通过js改变iframe src,Native方法通过shouldOverrideUrlLoading(WebView view, String url)拦截url处理。但是在Android 4.2.2系统上,这个方法在iframe src改变是,是不会触发的。目前建议大家通过拦截js alert弹框做处理。

@Override
public boolean onJsAlert(WebView view, String url, String message,
JsResult result) {
LogUtils.i("url:" + url+"\n message:" + message);
try {
String msg = URLDecoder.decode(message, "utf-8");
if (msg.startsWith(BridgeUtil.PANDO_RETURN_DATA)) { // 如果是返回数据
handlerReturnData(message);
result.cancel();
return true;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return super.onJsAlert(view, url, message, result); }

  注意,onJsAlert方法拦截做处理后一定要result.cancel();不然web界面就会出现点击没反应的情况。

3、Hybrid App维护

Hybrid App涉及到html、css和js等web资源文件,当web和Native之间有相互调用时,两者之间任何一方接口变动都会导致App出现bug。

  • 考虑类似微信方案,将jsbridge文件或者部分常用web资源随App打包发布,降低维护成本,也不用担心在网络不好的情况下加载不了web界面,在接口升级之前发布出去的App肯定也是稳定可用的,当然这个也要考虑安全性问题,毕竟你的web界面源码通过反编译代码可以得到。
  • 所有web资源统一从服务器获取。由于web资源在服务器,所以可以随时动态更改web界面,发现bug也不用发布App,直接在线接口升级。但是要维护web资源,使得每个发布出去的每个版本的App在加载web资源时都可用。

讨论:

  Q:

最近想自己写个android的hybrid app,看了下大多推荐的是PhoneGap,不知道他的运行效率怎么样,如果以原生为重的话,适不适合用PhoneGap?

  A:

我来说说吧,其实就是mui开发最快,这是我自己实践的结果,ionic我没用,可是cordova我用过,因为国内没多少人分享经验,所以坑很多。

你做一个带扫码,摇一摇,地理位置追踪,消息推送的app,这些基础功能mui基本不用研究拿来就能用。cordova光是研究插件集成和使用就得花3天时间,中间还会有很多坑。(这个已经有半成品)

但是,cordova对于你做一个需求比较奇特的app来说很好,因为他的插件库全。mui对这个支持比较弱。(这个试了一周后放弃)

话又说回来,如果那么奇特需求的app在技术选型上为什么不选原生?如果非得用hybird自己用webview做就是了。学cordova的时间够把如何原生调用js和js调用原生弄明白10次了。现在我就是这么做的。

A:

  如果对原生的部分功能要求较高的话,不推荐使用PhoneGap,虽说现在已经很成熟,但是如果涉及到原生功能还是很差的,我之前体验过。。

---------------------------分------------割-------------------------------------

以上内容摘自

https://www.tuicool.com/articles/riE3Yn

感谢大神们的实践总结~

上一篇:SpringBoot捕获全局异常


下一篇:Hybrid App 开发初探:使用 WebView 装载页面