GTLC全球技术领导力峰会·上海站,首批讲师正式上线! 了解详情
写点什么

豆瓣音乐人 app 的 PhoneGap 实践

2013 年 10 月 31 日

豆瓣音乐人 app 在 2011 年开发时,便采用了基于原生与 webapp 混合架构的 PhoneGap 框架,直到今天。这也是目前豆瓣唯一一款使用 PhoneGap 的 app。最近我们刚发布了音乐人 app 的 ios 新版,仍然保持这一架构,在原生方面的功能上做了一些增强。PhoneGap 为音乐人 app 的顺利发布带来很大帮助,当然同时也造成了一些局限。

当时如何做出使用 PhoneGap 的决定

我们之所以在技术选型时作出这一选择,主要有以下几个方面的原因:

  1. 开发效率的考虑

尽管豆瓣音乐人的用户对 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。

2013 年 10 月 31 日 22:457995

评论

发布
暂无评论
发现更多内容

海华大赛第一名团队聊比赛经验和心得:AI在垃圾分类中的应用

华为云开发者社区

AI 算法 数据分析 垃圾回收机制 华为云

Spring Boot+Redis+拦截器+自定义Annotation实现接口自动幂等

我是苞谷

IDEA 插件找不到?看这里!那就自己敲一个!

程序员小航

json IDEA 开发工具 idea插件 IntelliJ IDEA

架构师训练营第九周

Melo

功能扎实的ERP模版已上架应用库(支持免费安装使用)

明道云

java高并发系列 - 第11天:线程中断的几种方式

简爱W

秒懂云通信:如何用阿里云语音通知服务(小白指南)

阿里云Edge Plus

语音

智能的财务管理系统,来自某科技公司CEO亲手搭建

明道云

实践录丨如何在鲲鹏服务器OpenEuler操作系统中快速部署OpenGauss数据库

华为云开发者社区

数据库 鲲鹏920 操作系统 服务器 opengauss

骚操作!用 CPU 烤肉,这位程序员做到了!

程序员生活志

程序员 gpu 程序人生

Spring系列第2篇:控制反转(IoC)与依赖注入(DI),晦涩难懂么?

老大哥

架构师技术领导力成长之路

IT民工大叔

领导力 架构师

一条更新sql在mysql中是怎么执行的

简爱W

创业公司技术体系建设-CI/CD

星际行者

CI/CD

助力银行核心下移,监控分布式数据库,融天鹰眼轻松应对五大挑战

DT极客

策略模式解析

南方有乔木兮

JVM系列之:通过一个例子分析JIT的汇编代码

程序那些事

Java JVM JIT 汇编

六字说出微服务的本质

看山

架构 微服务

腾讯安全领御区块链与张裕集团达成战略合作,打造高端葡萄酒区块链溯源平台

CECBC区块链专委会

产品溯源 无法篡改

Java异步之《我call(),Future在哪里》

BUZHIDAO

LeetCode002-两数相加-medium

书旅

算法 数据结构与算法

Twitter高性能分布式日志系统架构解析

俊俊哥

pulsar bookKeeper 分布式文件存储

实现扫码登陆的最简单方案与原理

Java小咖秀

Java 解决方案 经验总结

新技术(区块链)--让游戏行业走的更远

CECBC区块链专委会

区块链技术 防篡改不可逆

(政务上链)新数据孤岛、安全风险等问题待解

CECBC区块链专委会

工作效率 公开透明 新技术

【华为云技术分享】DLI跨源|当DLI遇见MongoDB

华为云开发者社区

数据库 mongodb dlib 数据集 华为云

刚坐下,一个面试官居然问了我 30个Spring Boot问题!

只喝纯牛奶

编程日课•理解学院

顿晓

学习 编程日课 理解学院

我天!xx.equals(null) 是什么骚操作??

导导

LeetCode题解:189. 旋转数组,pop+unshift一行,JavaScript,详细注释

Lee Chen

LeetCode 前端进阶训练营

面经手册 · 第1篇《认知自己的技术栈盲区》

小傅哥

Java 小傅哥 面试官 技术栈

DNSPod与开源应用专场

DNSPod与开源应用专场

豆瓣音乐人app的PhoneGap实践-InfoQ