去年曾对Phonegap做过一次调研,当时还是1.1版本,印象也一般。对他的性能以及真实的跨平台能力都不太确定。今年过完春节至今正好有机会参与了一个纯Phonegap + HTML5开发的项目,项目至今已经完成了一期的App Store提交,所以也正好能抽时间来小结一下。一个月左右的开发过程让我对这种开发模式有了更深的认识,这对于前端开发人员而言绝对是一个大的机会。Phonegap Native API + Plugin基本能访问移动设备绝大部分本地功能,除此之外就是HTML5了,迁移成本非常的低,而开发效率也是很高的。
与传统Web开发相比,在移动设备进行Web开发有着自己的特点,例如不同设备的屏幕尺寸以及分辨率都有可能不同,因此开发时需要考虑灵活性;移动设备上基本上都是使用webkit来跑Web,因此你的脚本和框架可以放心的使用一些高级的特性,以及可以彻底抛弃兼容IE的那些恶心代码;当今移动设备的性能与PC相比还有很大的差距,因此性能问题在移动设备上更值得重视,尤其是脚本性能(DOM操作、Redraw、Reflow)。
关于Phonegap
Phonegap最大的价值在于跨平台,理想情况下应该是只需开发一份代码就可以同时发布到iOS/Android等N多平台(理想情况一般仅限于一句hello world),因此开发效率与开发本地应用相比有非常大的提升。此外,由于可以使用HTML5开发,因此开发人群就由各种稀有的本地应用开发人员(OC、Android、Symbian等)转向到相对传统前端开发人群,资源相对来说要丰富一些。
Phonegap的最大问题则应该是性能问题,它实现跨平台的方式基本上就是使用内置的浏览器内核来运行你的HTML CSS和Javascript,例如在iOS中就是创建一个UIWebview来加载index.html。因此这种运行在应用层的代码和Native代码相比,效率上会有很大的差距。如果你想做很炫的动画或需要大量运算的应用的话还是选择Native吧,这里可以参考一下这个性能比较的Benchmark。
因此,就目前而言,如果你准备开发的应用没有复杂的运算或动画,能够适合使用HTML+CSS来展现,那么可以果断的使用Phonegap + HTML5的模式来开发。
关于前端框架
移动设备上的前端框架目前发展非常迅速,从Phonegap Development Tool列表上就可以看出,很大一部分都是前端开发框架。框架的种类很多,有打包了UI实现的例如Sencha Touch、jQuery Mobile、jQ Touch、jQ.Mobi,也有UI无关的例如Zepto。
项目中使用了jQuery + jQuery Mobile + jQuery.tmpl,不过现在看来这个搭配并不理想:jQuery Mobile中基本上只使用了简单的事件,其他诸如Page以及其他的特性都未使用上。一方面是因为我们的UI和jQuery Mobile有非常大的差别,如果按照它的结构来写页面反而效率更低;另一方面,我们的页面表现相对来说复杂一些,资源也比较多,经测试发现它的Page功能(动画效果类)在性能上并不理想。因此,我们彻底放弃了jQuery Mobile UI相关的功能,仅使用了一些诸如scroll、tap的事件而已。
jQuery Mobile的实现方式是在jQuery的基础上写了一套Mobile相关的代码,例如事件、各种模拟的Native UI等。这种基于PC上的框架来实现移动框架的方式,我并不太认同,使用时还必须先引用庞大(相对于移动设备而言)的jQuery。jQuery兼容了PC上各种浏览器的实现,而相对于移动设备较为单一的浏览器环境而言是臃肿的。
jQ.Mobi则换了种方式,它针对移动设备重写了jQuery中最常用的部分接口(jqMobi),因此在代码体积和效率上有更佳的表现,此外,在jqMobi的基础上还提供了jqUi。
jQ Touch与jQ.Mobi也很相似,既可以选择jQuery,也可以选择Zepto来作为底层脚本库。
了解各个框架的特点后,就可以根据自己应用的特性来选择合适的框架了,像我的这个应用UI完全自己实现,页面切换也是Single Page + 自己实现切换,因此基本上使用Zepto或者jqMobi就足够了。
关于性能
移动设备的硬件和PC相比还有很大的差距,因此,原先PC上可以忽略的性能问题在移动设备上会被放大。尤其是涉及到浏览器Redraw和Reflow的,例如使用循环遍历并修改DOM节点。如果是在PC上,这样的操作也许需要上千次或者更多次才可能表现出性能问题;但是在移动设备上,100次左右的操作就可能要消耗几秒钟的时间(真实案例)。对于此类问题,之前在PC上开发的经验依然适用,而且需要更加重的重视。之前写的一篇文章可以继续作为参考。
关于动画
首先还是想说说性能的问题。原来在PC上实现的动画,绝大部分都是setTimeout / setInterval来实现,或者适用HTML5的requestAnimationFrame,但是这两种方式在移动设备上都是无法使用的。requestAnimationFrame目前在移动设备上还未支持;而使用setTimeout来绘制动画的性能是让人无法忍受的,例如jQuery的slideUp,即使是在iPhone 4S上性能也足以让你瞠目结舌。
幸好CSS3支持了强大的动画功能,浏览器自身解析而实现的动画效率比Javascript实现要高得多。诸如之前介绍的移动框架的动画也正是使用CSS3来实现的。关于CSS3的动画语法之类的就不多说了,总之CSS3动画是这种开发模式的必修课之一。
此外,分享一个关于动画的小技巧,就是CSS动画是可以添加回调的,包括TransitionEnd和AnimationEnd两类,当动画执行完毕后会调用,示例代码如下:
view plaincopy to clipboardprint?
- $('body').bind('webkitTransitionEnd',function(){});
- $('body').bind('webkitAnimationEnd',function(){});
关于iScroll
iScroll4实现了各种"scroll"相关的功能,例如类似PC上传统的Slide幻灯片效果、微博中常用的Pull to Refresh的效果以及在iOS上实现overflow:scroll效果。而我最初使用它的也正是因为第三点原因,iOS5以下的设备都不支持overflow:scroll属性,也就是说没法scroll元素的内容。这样一来,常见的固定头尾的布局就没法实现了。iScroll则使用 Touch Event + CSS3 动画的方式来模拟了原生的scroll效果。
不过在实际的开发过程中发现,一旦scroll的内容较多,尤其是有背景图的情况下,iScroll模拟的滚动效果会非常卡,背景图比<img>要卡很多,估计是因为浏览器redraw时性能Hold不住了。于是,原先准备用它来实现固定头尾的想法也就放弃了,而是在局部页面的小块内容中使用,以及新手帮助的slide效果中也使用到。
另外,透露一下目前固定尾部的实现方式:iOS5设备中,由于支持postion:fixed,因此可以直接定位在底部,用户滑动的是整个页面,而不是某个容器的内容;非iOS5设备中使用了类似ie6中的实现,scroll时隐藏,scroll结束时显示,很恶心…而且由于性能以及浏览器本身一些渲染特性偶尔还会导致scroll时无法消失。这个问题目前只能期待iOS5设备的普及了。
关于Viewport和Retina屏
iPhone Retina屏幕的分辨率为640 * 960,因此如果希望获得清晰的画质,页面在设计、布局时也应该按照该尺寸实现,否则如果按照320 * 480的实际屏幕大小进行布局,则在显示时会被拉伸,页面中的图片会变模糊。
在显示时,需要正确设置viewport,否则会显示异常,这里需要设置viewport为640,也即把手机的屏幕当做640宽度来显示。关于viewport的相关知识可以参考以下几篇文章:
《Using the viewport meta tag to control layout on mobile browsers》
关于工具
WEINRE是必须要介绍的工具,现阶段而言简直就是前端开发调试的神器!它允许你在PC上直接调试真机上的程序,例如在控制台中输入alert(’hello world’);,手机上就能蹦出一个对话框;Inspect DOM元素,修改属性、修改CSS,真机上立即就能体现。它的功能基本上就是Chrome的开发者工具拿掉脚本调试那块。
在实际开发过程中,从WEINRE中确实获益匪浅,能够快速高效的定位问题和验证解决方案。关于它的使用方式已经有不少参考了,例如《使用weinre调试Web应用及PhoneGap应用》
此外是关于XCode Build方面的一个小技巧,XCode的Build是可以加入自己的编译脚本的,用脚本可以访问到打包后的APP。因此,我们加入了自己的编译脚本,功能是使用Closure Complier对脚本进行压缩并打包到APP中。大致方式如下:
在项目的Build Phases中添加一个Run Script Pharse,配置大致如下:
在build.sh中做了事情就是到Build的目标路径中扫描所有JS,然后做压缩等各种处理即可,由于最终的APP是带签名的,所以每次Build前需要先Clean。
(完)