混合开发实践
混合开发使用场景
移动混合开发不是新概念了。移动应用可分为三类,一是原生应用,一是web应用,介于这两者之间的是混合应用。每一种技术方案都有它的使用场景。盲目的使用显然会导致产品质量的低下。
毫无疑问,原生应用的性能和用户体验都要优于web,web页面交互效果也稍差。原生应用对于用户来说是友好的,对于一个成熟的产品来说,也必须是原生应用(至少80%已上的页面是native写的)。这一点Facebook已经走过弯路了,曾经出了一款web应用,后来饱受批评而下架,改回原生开发。
那为什么我们还要使用混合开发呢?产品从有想法,到最后到用户手上,期间要经历很多过程,其中的一个过程是需求的验证和原型的开发,这个过程的迭代速度是极快的,不断的假设,再不断的实现和验证。我把这个过程命名为验证阶段。最后需求相对明确和趋于稳定下来,会进入到产品的实质开发阶段。
在验证阶段,如果使用原生的来做,开发的压力会比较大。Web技术发展多年,已经非常成熟,开发速度会比原生的快不少,对于需求的响应速度就能更快满足产品需要。对于iOS应用来说,还有一道障碍是苹果漫长的审核周期,这对于需要快速迭代的产品来说是很不爽的。这时候混合开发就派上用场了。对于需要验证和频繁更新的需求,使用web技术来做,可以规避发布新版本。在这个阶段,有些页面是原生的,有些是web的,保证产品始终处于一个比较完整的状态。这可以让产品尽早地交付产品经理、设计师、用研,以及测试用户,来验证需求。
在实质开发阶段,需要逐步地将混合页面过度到原生页面,尤其是对于交互和性能有所要求的页面。不然用户是不会接受的。
总结来说,混合开发有几个好处:
- 热更新,避免频繁发版本,减少等待审核时间
- 迭代速度快,Web开发速度要比Native的快一些
- 总的工作量小,iOS和Android两个平台可以共用一套代码
混合开发技术探究
混合开发技术主要需要解决两个问题:
- Native和Web跨技术平台合作:iOS开发和Web前端开发还是有很大差别的。需要想办法让两者能够顺畅地沟通。
- 优化WebView的性能和体验:WebView的体验不好,所以我们需要想办法去缩小Native和WebView之间的鸿沟。
打通Native & Web
iOS7以前,ObjC调用JS代码使用的是这个方法:stringByEvaluatingJavaScriptFromString
而JS要调用ObjC代码,一般的解决方案是先协议好一些事件,在WebView的delegate中去捕捉。
iOS7出了个框架:JavaScriptCore.Framework. 使用这个框架,让JavaScript和ObjC代码互相调用就方便而简单很多了。JavaScriptCore还做了ObjC和JS间的类型转换。 在拿到JavaScript的上下文(JSContext)之后,可以方便地注入变量和执行JS代码:
JSContext *context = [[JSContext alloc] init];
[context evaluateScript:@"console.log('hello world');"];
而要让JS调用ObjC代码,有两种方法:一种是通过block,另一种是实现JSExport协议。放在JSExport协议下的方法都可以暴露给JS。JavaScriptCore会自动生成一个Wrapper Object来桥接。可以参考HybridBridge的写法。
要在真正的项目中使用还需要对这个框架做一下封装。最基本的需要考虑以下几种场景:
JS调用ObjC的一段代码,ObjC成功后回调JS。假设bridge是注入的JS变量。
bridge.sendMessage(event, message, callback)
- Native端实现网络代理。
bridge.httpRequest(url, method, callback)
- Native端对图片等资源做缓存,为JS提供资源。在这里,图片返回的是它的base64编码后的字符串。
bridge.loadImage(url, callback)
- 提供页面级的跳转。
bridge.pushController(url, controllerName) | bridge.presentController(url, controllerName)
- 为了方便调试,Native为JS提供一个log方法。
bridge.console(message)
- Native端实现网络代理。
ObjC调用JS代码,JS成功后再回调。
[object callHandler:parameters:callback:]
优化WebView
一般来说WebView需要先请求资源,请求数据,然后再去渲染。这是一个耗时的过程,所以经常会看到WebView一直显示在loading。请求模板资源和数据跟网络情况有关,数据是可能经常变的,而资源的变化频率就比较小了。可以做个优化,把资源放到本地。这种优化可以减少页面大部分的响应时间。
资源也并不是一直不变的,如果这样的话,那就没办法利用混合开发的热更新。资源的增量打包和动态更新是另一项重要工作。当前端代码更新时,将增量部分打包,根据时间戳形成一个新的版本的zip包。客户端保存有当前使用的资源版本号,当App进入到后台时,根据保存的版本号向后端请求更新的资源。如果有新的资源则下载到本地,并解压覆盖旧的资源。
这种方法在优化加载时间的同时兼顾了热更新特性。
任何技术方案都有好有坏,用之有道才能扬长避短。