豆瓣音乐人 app 在 2011 年开发时,便采用了基于原生与 webapp 混合架构的 PhoneGap 框架,直到今天。这也是目前豆瓣唯一一款使用 PhoneGap 的 app。最近我们刚发布了音乐人 app 的 ios 新版,仍然保持这一架构,在原生方面的功能上做了一些增强。PhoneGap 为音乐人 app 的顺利发布带来很大帮助,当然同时也造成了一些局限。
当时如何做出使用 PhoneGap 的决定
我们之所以在技术选型时作出这一选择,主要有以下几个方面的原因:
- 开发效率的考虑
尽管豆瓣音乐人的用户对 app 有很强的需求,但音乐人 app 的定位和发展方向,当时处于不断探索和快速迭代的阶段,这样的情况意味着,音乐产品线希望使用尽可能简单的方式、占用较少的人力资源进行开发,尽快在多个平台发布,并且对于迭代的需求能够快速响应。在各种因素的权衡中,优先考虑满足上述需求。
对于原生 app 好还是 webapp 好这个问题,似乎一直有很大争议,实际上我不认为这是一个纯粹的技术问题。webapp 在开发效率上的优势,原生 app 在性能和开发自由度上的优势,都是不言自明的,一个 app 是否采用混合架构,在我看来,最重要的因素还是产品定位和发展策略,如果希望尽快发布、跨平台、能快速响应可以预见的迭代,那么混合架构就很值得考虑。如果有足够的开发人员覆盖各平台、产品设计成熟度高、产品周期上可接受相对较长的开发时间,那么原生显然是更好的选择。
2. 跨平台的考虑
豆瓣音乐人会是一个以展示内容和收听流媒体音乐为主的 app,那些只有原生代码才可以实现的功能,我们需要得比较少。这意味着,如果我们采用混合架构,需要实现的原生特性与需要解决的跨平台问题会较少,混合架构的优势会被放大。
即使考虑了第一个因素后认为值得使用混合架构,如果 app 本身的特性不适合 webapp 的方式,那也会显得没有这个必要。Webapp 之所以开发效率高,一方面在于 html+css+js 能做的事情,比用原生代码做同样的事情要简单得多,另一方面在于方便跨平台。如果 app 里面要实现的功能,很多都没法用 html 做,必须用原生代码,那这两方面的优势都消失殆尽。
实际上,就在我们第一个版本发布前不久,设计方面进行了一次 review,然后对 app 的整体外观风格和某些功能与交互做了大幅修改。但其实只用了几天,设计的修改就被完全实现了,这样的速度对 web 前端开发来说当然不是什么难事,但对原生 app 来说却是难以想象的。
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 现在的版本已经有很大改进,而且主流手机的性能已经比以前好太多,现在新开发 PhoneGap 的话,应该会轻松很多。
css3 性能问题
我们开始的设计中,有一些半透明和投影等效果,但我发现用 css3 实现后,会导致性能不好,这跟原生开发时可能遇到的半透明性能问题是一样的。Webkit 并不如我们想象的那样有保障。后来,我们为此修改了设计,尽可能使用不透明的元素,去掉投影等效果,并减少 dom 复杂度,性能得到了明显提升。
像素密度问题
对于不同像素密度的屏幕,需要准备不同的图片,然后在 css 里面使用媒体选择器,根据 –webkit-device-pixel-ratio,分别插入密度为 0.75(老 android 手机),1(非 retina iPhone),1.5(一些 android 手机),2(retina)的不同 css,以使用不同的背景图片。只需要修改一个 css 文件,MakeFile 脚本会自动生成其他的几个 css 文件。当然,我还需要保证这四套图片是存在并且正确命名的。
Mp3 播放问题
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。
评论