出处:http://www.infoq.com/cn/news/2013/10/douban-artist-PhoneGap-practice?utm_source=infoq&utm_medium=related_content_link&utm_campaign=relatedContent_news_clk
豆瓣音乐人app在2011年开发时,便采用了基于原生与webapp混合架构的PhoneGap框架,直到今天。这也是目前豆瓣唯一一款使用PhoneGap的app。最近我们刚发布了音乐人app的ios新版,仍然保持这一架构,在原生方面的功能上做了一些增强。PhoneGap为音乐人app的顺利发布带来很大帮助,当然同时也造成了一些局限。
我们之所以在技术选型时作出这一选择,主要有以下几个方面的原因:
开发效率的考虑
尽管豆瓣音乐人的用户对app有很强的需求,但音乐人app的定位和发展方向,当时处于不断探索和快速迭代的阶段,这样的情况意味着,音乐产品线希望使用尽可能简单的方式、占用较少的人力资源进行开发,尽快在多个平台发布,并且对于迭代的需求能够快速响应。在各种因素的权衡中,优先考虑满足上述需求。
对于原生app好还是webapp好这个问题,似乎一直有很大争议,实际上我不认为这是一个纯粹的技术问题。webapp在开发效率上的优势,原生app在性能和开发自由度上的优势,都是不言自明的,一个app是否采用混合架构,在我看来,最重要的因素还是产品定位和发展策略,如果希望尽快发布、跨平台、能快速响应可以预见的迭代,那么混合架构就很值得考虑。如果有足够的开发人员覆盖各平台、产品设计成熟度高、产品周期上可接受相对较长的开发时间,那么原生显然是更好的选择。
跨平台的考虑
豆瓣音乐人会是一个以展示内容和收听流媒体音乐为主的app,那些只有原生代码才可以实现的功能,我们需要得比较少。这意味着,如果我们采用混合架构,需要实现的原生特性与需要解决的跨平台问题会较少,混合架构的优势会被放大。
即使考虑了第一个因素后认为值得使用混合架构,如果app本身的特性不适合webapp的方式,那也会显得没有这个必要。Webapp之所以开发效率高,一方面在于html+css+js能做的事情,比用原生代码做同样的事情要简单得多,另一方面在于方便跨平台。如果app里面要实现的功能,很多都没法用html做,必须用原生代码,那这两方面的优势都消失殆尽。
实际上,就在我们第一个版本发布前不久,设计方面进行了一次review,然后对app的整体外观风格和某些功能与交互做了大幅修改。但其实只用了几天,设计的修改就被完全实现了,这样的速度对web前端开发来说当然不是什么难事,但对原生app来说却是难以想象的。
PhoneGap只是个原生外壳,app的内核是一个完整的webapp,需要调用的原生功能将以原生插件的形式实现,以暴露js接口的方式调用。在webapp框架的选择上,我调研了当时的一些专用于webapp的js框架,几乎都不大成熟,没什么合适的,当然现在的情况已经大不一样了。由于音乐人app的规模不算大,而且在移动设备的webview中性能非常重要,我决定把一些小工具组合成一套微型框架来使用,尽可能优化执行效率。框架大致由以下小零件组成:
jQuery;
iScroll4(模拟app风格的滚动);
js模板机制;
url分发与访问历史管理;
页面关系与页面切换机制;
基于Jsonp的带用户认证的api接口封装。
这样就简洁地实现了最小化的js框架。之所以使用jsonp的方式通信,是因为我非常希望能使用chrome进行调试,这样开发时就很方便,只需要双击本地的html文件,chrome就会成为一个完美的移动设备模拟器,我可以使用自己喜欢的任意前端开发调试工作流,这比任何移动设备模拟器都要方便得多。
有了框架,接下来只需要一个页面一个页面实现就好了,我把webapp部分作为git submodule,ios和android的仓库都包含它,打包时使用各自的编译发布流程即可。
大致说一下遇到的印象深刻的问题。其实PhoneGap现在的版本已经有很大改进,而且主流手机的性能已经比以前好太多,现在新开发PhoneGap的话,应该会轻松很多。
我们开始的设计中,有一些半透明和投影等效果,但我发现用css3实现后,会导致性能不好,这跟原生开发时可能遇到的半透明性能问题是一样的。Webkit并不如我们想象的那样有保障。后来,我们为此修改了设计,尽可能使用不透明的元素,去掉投影等效果,并减少dom复杂度,性能得到了明显提升。
对于不同像素密度的屏幕,需要准备不同的图片,然后在css里面使用媒体选择器,根据 �Cwebkit-device-pixel-ratio,分别插入密度为0.75(老android手机),1(非retina iPhone),1.5(一些android手机),2(retina)的不同css,以使用不同的背景图片。只需要修改一个css文件,MakeFile脚本会自动生成其他的几个css文件。当然,我还需要保证这四套图片是存在并且正确命名的。
iOS的webview支持mp3播放是没有问题的,但当时会有一个限制,就是如果用户没有主动操作,webview就不能自动开始播放,为它做一个workaround也就能够解决了。比较麻烦的是android的某些较老的版本,虽然支持audio标签,但是不支持mp3格式的音频,事实上它不支持任何格式的音频。所以对于这种情况,只能使用PhoneGap自带的音频播放功能。对用户而言,效果是一样的,但这增加了webapp的依赖,使webapp部分变得复杂了。
虽然大体上来说,iOS和android使用的webview,其行为都是差不多的,而且由于都是webkit,样式会非常接近,几乎是自动完美跨平台。但是实际开发中发现,还是会有一些区别,例如:
app ready时触发的事件不一样,当然这和PhoneGap封装有关;
android有时候会有软键盘问题,有个插件可以解决;
处理打开外部url时行为不一致;
支持的动画方式有区别,对不同平台需要尽可能使用高效、硬加速的动画方式。
需要为android的几个实体按键写专门的处理函数。
有的需求在webapp内无法做到,这是经常遇到的事。例如:
推送消息;
状态栏提醒;
打开内置浏览器访问一些url;
绑定社交平台账号;
缓存下载的图片和音乐等文件。
很多都可以找到插件来解决,现在市面上的插件比当时开发音乐人app最初版本时,已经丰富得多了,但仍然可能无法满足需求,这时就需要自己写插件来完成,每出现一个这样的需求,就意味着要为每个系统做一次原生解决方案。我们正准备把音乐人app中使用的“推荐到社交平台”的插件进行开源,提供给其他有类似需求的开发者使用。
我简单试过WebOS,样式上会非常一致,但存在一些其他问题,为稳定起见,我们没有发布WebOS的打包。另外,移动版IE10已经是对标准非常友好的浏览器,但样式上跟webkit仍然有差异,不能把webkit的webapp直接拿来就用,需要做适配。感觉上又回到了桌面web开发的世界。
有趣的是,使用MacGap把app核心部分打包成Mac的桌面应用,倒是完全无痛,几乎直接就可以用。
使用感觉上来说, iOS上的效果要略好于android上的效果,几乎跟原生界面没太大区别。虽然跟原生app相比,渲染速度等细节上仍然略微吃亏,但总的看来是完全可以接受的水平。
总结一下的话,我们对基于PhoneGap得到的成果是满意的,开发性价比很高。用户对音乐人app的评价也比较好。将来在产品稳定后,我们是否会使用纯原生app替代PhoneGap,现在还不知道,这将取决于产品未来的决策。希望得到什么,也就同时决定了会放弃什么,一切都是权衡的结果,框架没有银弹。
苏丹,北京师范大学数学系毕业,现任豆瓣音乐Techleader。
免费赠送QCon/ArchSummit门票、热门图书,InfoQ联合亚马逊推出“注册信息即送AWS服务25美元折扣券”活动。