随便搜索一下“Android vs. iOS”,都会出现不少关于哪一个平台更好的争论,大多数的争论点都是关于市场占有率、易用性和设备分化等问题。固然也有一些“以开发者的角度”去比较这两个平台的文章,可是不多有从技术上作深刻的比较,一般也只是用一个简单的示例应用介绍一些基本的特性。缺乏这种深刻的比较实际上是有缘由的:一个公司要作一个足够复杂的移动应用,一般须要一我的或团队作Android,另一我的或团队作iOS。这两个平台使用不一样的编程语言(Java和Objective-C),提供不一样的SDK,使用不一样的开发工具,因此人力资源分配上各作各的平台也就不奇怪了。html
GQueues是一个在线任务管理器,以前只有一个HTML5版本。最近我完成了GQueues for Android 和GQueues for iPhone & iPad 的开发。虽然这两个应用的复杂程度不能和第一人称射击游戏相提并论,但也毫不简单 – 为用户存储和管理数以千计的任务信息、支持多帐户、提供到WEB端的后台同步、复杂的过滤、排序和分组功能。经过此次的实践,我但愿透过独特的视角,分析和比较为这两个平台开发GQueues应用的过程。python
-- | Android App | iOS App |
---|---|---|
启动日期 | Sept 21, 2012 | Mar 2, 2013 |
第一个可测的Beta版本 | Dec 22, 2012 | June 10, 2013 |
应用发布日期 | Jan 31, 2013 | July 18, 2013 |
项目总耗时 | 4.25 months | 4.5 months |
Ramp Up Time | 1 week | 2 weeks |
开发耗时 | 870 hours (approx) | 960 hours (approx) |
Beta测试&Bugfix | 34 days | 38 days |
Beta测试人员人数 | 92 people | 48 people |
代码行数 | 26,981 lines | 23,872 lines |
应用大小 | 1.1 MB | 3.5 MB |
视频预览 | GQueues for Android Video | GQueues for iOS Video |
下载 | Google Play | App Store |
我已经写了12年的代码,但这是我写的第一个Android应用,也是我写的第一个偏向数据处理的iOS应用(2010年我作过两个iOS 3上的游戏,但那两个游戏主要只涉及一些动画和蓝牙链接)。 我最后一次用Java是在研究生阶段,而个人Objective-C 也仅限于那两个游戏。因此对于这两个平台,我基本上能够算是从零开始。android
简单讲,只须要花一半学习iOS的时间来学习Android,我就能开始Android开发。对于Android,我花了一周时间用来看书、跟着一些教程作一些测试应用,这些测试应用包含了GQueues将会用到的一些核心功能。作完这些,我基本上算是打好了为GQueues设计架构的基础,同时也能够开始为这个项目写代码了。在接下来的一周我能够很轻松自如地基于Android作开发,而再也不须要依赖某个资源去实现新特性了。ios
对于iOS,我一样按照上面的流程,但我花了两周时间作各类测试/实验,才让本身以为能够开始为这个项目写一些基础代码了。其中大部分的时间都花在研究CoreData各类复杂的API上面。搞清楚怎么设置、怎么在线程安全的前提下,为每一个用户集中管理PersistentStoreCoordinators和ManagedObjectContexts也花了些功夫,最重要的是要支持多帐户(这个话题可能须要另外一篇博客来单独讲讲)。为 FetchedResultsControllers开发一个可扩展的架构花了更多时间,FetchedResultsControllers用于支持可被用户查看以及操做的任务表单、队列和分类。最后又过了两周(总共花了一个月)本身才能比较轻松自如地基于iOS写代码。git
总的来讲,Android的文档(官方文档、第三方教程、图书、代码示例、StackOverflow)质量都很是高。我从一些著名的开源Android应用中学到了不少架构上的最佳实践,如Google开放给开发者的2012 Google I/O app。此外,Android自己就是开源的,必要时我能够本身查看Android的平台代码,弄清楚一些疑难问题。虽然iOS也有不少文档,但因为iOS5和iOS6相比以前的版本改动很是大,大部分文档都已通过时,其中包括ARC入门一文(introduction of Automatic Reference Counting)。所以,大部分的示例代码(包括Apple官方示例)和一些问题的解决方法都是不正确的,须要使用新的方法取而代之。搞清楚这些确定也须要花更多的时间。github
从上面的统计表中也能够看出,开发GQueues for Android要比开发 iOS 版的快十分之一的时间,尽管在开发Android版的期间我从新实现了以前用于支持GQueues HTML5版的整个后端服务器同步代码。而开发一个不采用原始iOS6风格UI的应用也须要多花些时间,单单比较这个数据,Android开发就是比iOS开发快。web
Android 应用正则表达式
iOS 应用sql
上面列出来的书其实用处颇有限,由于跟大部分的技术类书籍同样,书的内容都有点过期了,并且大部分书只停留在入门级别的概念介绍。不过,在一开始的前几天看一下这些书,可以比较快地理解平台上的一些核心功能。就目前来说,对于这两个平台,在线资源仍然是最有价值的。数据库
接下来我只简单说一下这两个平台的开发工具,由于关于这个话题已经有不少的讨论。我不是Eclipse或者XCode的脑残粉,它们有各自的强项和弱点(其实我最喜欢的仍是Vim)。Eclipse的搜索暴慢并且很繁琐。XCode Organizer的文档搜索也卡爆了。Eclipse中使用log tags(经过Android插件的logcat集成)过滤日志超级实用。两个IDE的代码补全都很不错,XCode的Interface Builder一点用处都没有(后面细讲)。不过XCode Instruments就很是有用了,能够用它作优化分析、调试等等。我开始作GQueues for Android的时候,Google还没发布Android Studio,不过在GQueues的后续更新版本中我会拿它来试试。
若是你一边写代码一边测试,用Android的模拟器简直就是浪费时间(真不敢相信它能慢成这个鸟样)。在开发过程当中,我都是直接部署到真机上测试的,用真机快不少。iOS的模拟器则很不一样,跟Android相比简直就是火箭跟蜗牛赛跑,这也让整个开发过程更加高效。每写一小段代码我都会在模拟器上跑一下,等到整个功能完成了我就会部署到真机上玩玩。
对于Android,我有各个版本的测试机器(除了Gingerbread,即Android 2.3),除此以外,就要倚靠beta测试过程当中各类设备的覆盖了。对于iOS来说就要简单不少了,我只须要拿GQueues须要支持的最旧的和最新的机器来测试就够了。
Android App
iOS App
GQueues的其中一个需求就是必须同时支持任意尺寸的手机和平板,而且针对不一样的表单元素进行优化布局。因为各类各样的设备都运行着Android系统,Android也理所固然地有着成熟的UI组件帮助开发者支持各类尺寸。例如从Android第一个版本开始,RelativeLayout提供了View之间相对布局的支持,可用于建立灵活、响应迅速的布局。另外,在Android中全部的布局都由XML定义,这设计界面的方式很是简洁、简单而且高效,试过iOS中建立布局以后这种体会就更加深入了。
相对于Android的RelativeLayout,iOS有Auto Layout,这种布局方式比较新(iOS 6新引入的),集成到了Interface Builder(IB)中,可是太难用了。我花了好多天学习IB中怎么用Auto Layout,跟任何iOS 6开发者同样,仅靠IB为视图(View)设定各类精确的约束,彻底改变了我本身的标准,这是由于IB所谓的“智能”系统时刻维持(纠正)着视图布局相对位置。我学了不少技巧,想着弥补IB的短板,可是没啥做用。最后我只能放弃IB,转而用冗长的代码实现全部布局。若是你放弃IB和富有极客范的ASCII art style来写布局,使用Auto Layout来实现仍是很强大、很直接的。但愿苹果在iOS 7中已经改善这些,不过我还木有试过。
若是一个应用须要同时针对小屏设备和大屏设备进行优化,最关键的就是基于屏幕的真实尺寸进行动态组合视图,这种方式被称做“适配性布局(Adaptive Layout)”,平板电脑能够在一屏中显示两个或三个视图,而手机上一屏则只显示一个视图。Android经过Fragments支持这种设计,Fragment是一个独立的、自包含的的模块,可以在须要的时候直接丢到Activity中去用。经过使用Fragments,只须要调整几行XML代码就可让GQueues的布局适配不一样分辨率的屏幕。对于我来说,Fragments是一种很是天然的解决方案,由于它是基于面向对象里面两个众所周知的准则设计的 - 高内聚和低耦合。
经过Custom Container View Controller(你也能够用Master-Detail模板,固然这种方式宽度是固定的,也不支持个性化定制),iOS支持一屏使用多个ViewController。对于这个不成熟的特性,我以为Apple的文档显得很复杂和不完整,最好的资源还要数Ray’s iOS5 tutorials和WWDC视频。我花了比预计要多的时间,终于搞好了在iPad上同时显示多个View、在iPhone上显示单个View的布局架构。
简单说,在Android上支持设备翻转须要作不少工做,这些工做也是最终致使不少bug的源头,而在iOS上,支持屏幕翻转只须要作一点点工做,剩下就是系统帮咱们搞定了。在Android上,屏幕翻转会直接销毁现有整个视图栈(Activity栈),屏幕翻转完成后再重建每一个视图。因此在GQueues中支持屏幕翻转,我须要无时无刻保存好全部当前状态,随时保证翻转后能正常恢复状态。而在iOS上,系统会帮你管理全部屏幕翻转相关的细节,惟一须要我关心的就是翻转以后,我须要调整那些没有被Auto Layout处理好的视图的位置。
网页开发上有一些常见的布局在GQueues上实现起来很是困难,无论是Android仍是iOS。其中一个例子是在任务详细界面显示标签。每一个标签都是变长的,在必要时标签须要自动换行。在网页上实现这个只须要设置CSS的float值就能够了。但无论是Android仍是iOS对这种“流式布局”(Flow Layout)都没有原生的支持,这也意味着我须要写不少代码本身去计算和摆放这些标签,以达到“流式布局”的效果。最后Android的代码是基于Romain Guy的演讲内容和 Artem Votincev 的flow layout实现的。在iOS上也采用了相似的方法,基于容器的总宽度,计算每一个标签的宽度,最后设置auto layout的参数。对于这个布局的实如今两个平台上都耗了很大的工做量。
关于Android的生态系统常被人吐槽的就是严重的系统分化。运营商推送更新的步伐老是很慢,因此如今仍有大量运行着旧系统的设备,这也就意味着若是要保证应用足够大的设备覆盖率,开发者就不能使用新版系统带来的新特性。不过好在如今针对这个问题,Android社区作了很大的努力,提供了一些用于在旧系统上支持新特性的库。经过使用Android官方的 Support Library和Jake Wharton的ActionBarSherlock Library,我几乎能够在Android 2.2上使用Jelly Bean(4.2)中全部的新特性。
对于iOS来讲,支持旧系统一说几乎不存在,或者说根本就不是关键。在准备阶段我花了一些时间考虑从哪一个iOS版本开始支持,而当时的统计数据显示使用iOS 6系统的设备已经达到 83%,而当时对于放弃支持iPad一代我也有一些疑虑,由于我老爸老妈老姐用的就是iPad一代,他们将是GQueues的铁杆支持者。最后我决定仍是只支持iOS 6+,这样我能够放开手使用Auto Layout,而不须要浪费大量时间实现任何过期的布局技术。固然,我解决了iPad一代的问题(至少对我家里人说来讲已经解决),就是换掉他们的iPad一代,给他们每人买一个iPad四代(做者有钱银)。
对于GQueues来讲,数据是核心 - 把数据保存到设备上而后同步到WEB端。Android和iOS有着彻底不一样的数据管理系统。Android提供了ContentProvider,它是SQLite数据库上层的一个可被继承的应用接口,做为一个结构化框架被用于全部应用的数据处理。ContentProvider学习起来比较难,搞定一个GQueues可用的实现,前期须要花不少工做。一旦搞定了第一步后面的扩展和个性化定制都变得简单多了。
一些背景信息,GQueues的web service是基于 Google App Engine’s Datastore 的,这是一个高扩展性的分布式NoSQL存储系统,而SQLite则是一个标准的关系型数据库,扩展性明显也比较差,但这彻底不须要考虑,由于这个应用只存储一个用户的数据。(顺便说一下,架构上我采用了“一个用户对应一个数据库”的设计,这对于快速简单地实现多用户切换有重要意义,不过实现细节可能得再开一博来聊了)。无论怎么说,Android的一个很大的优势就是能够建立 SQLite Views来支持Smart Queues。为了支持 Smart Queues,搞清楚各类复杂的表关联查询和子查询也花了写功夫,可是这也让Smart Queues的加载更加高效和快速,由于过滤不是在代码里面实现的(在SQL里面)。
在iOS上,我用的是 Core Data,它是iOS上的“schema驱动数据图形管理和持久化框架”,基本上它能够被看作是一个NoSQL存储,不过有趣的是,Core Data背后其实是SQLite数据库(呃…实际上SQLite也是几个可选项中最合理的选择)。iOS也容许用户直接建立SQLite数据库,但只支持经过纯C代码来操做,对于其余iOS组件没有原生集成。Core Data的学习起来也比较困难,但最后我仍是选择Core Data而不用SQLite,由于这样我能够轻松实现不少功能,包括缓存、数据模型迁移支持,还有经过 NSFetchedResultsController,能够很是简单地为界面中的table(列表)提供数据。
管理数据集的关键就是使用事务,尤为重要是作数据同步的时候 - ACID,即:atomic(原子性)、consistent(一致性)、isolated(隔离性)、durable(持久性)。Android上实现事务似很直观,跟大部分关系型数据库管理系统的实现方式是同样的,所以,保证数据完整性并不困难。另外,用好SQLite中的UNIQUE ON CONFLICT REPLACE语句,在数据同步的过程当中建表、对记录进行原子更新的时候几乎不须要作任何额外工做。
严格来说,Core Data并不彻底支持事务。经过使用单独的子ManagedObjectContexts作后台线程处理,再加上@synchronized,可以处理好数据更新和同步,同时避免不正确的写操做覆盖(overwrite)。关于高效更新和建立对象,iOS给的建议帮助很小,总的来讲,CoreData给个人赶脚很笨重,并无它声称的那么好用。另外,在Android上,SQLite能够轻松实现快速加载Smart Queues,而在iOS上,全部的过滤都必须在代码中实现,就算用了大量的缓存,速度仍然很慢。
在GQueues for Android上增长强大的全文搜索功能很简单,我模仿Google I/O应用里面的搜索实现,使用了SQLite的 FTS3 特性。首先建立一个虚拟表,而后在一个存储了用户任务的表上设置几个触发器,由这些触发器填充数据到虚拟表。作完了这些,剩下的就是设计一个搜索界面和为搜索历史添加存储。
iOS的Core Data对于全文搜索并无原生支持,因此我经过在谓词(Predicate)中使用LIKE语句,实现基本的任务描述和日记的搜索功能。这个实现固然没有全文搜索那么强大,但我认为它已经可以覆盖现实生活中大部分的使用场景了。
用于比较,我只会列举在GQueues中使用到的几个API。
正则表达式在实现GQueues中 Quick Add解析的时候扮演着一个很是重要的角色,幸运的是,Android和iOS对于正则表达式都有着原生的支持。Android中的Pattern和Matcher从第一个版本起就开始支持,同时也包含了不少正则语法,其中包括前向断言(look-ahead assertion)和后向断言(look-behind assertion)。iOS则从iOS 4开始引入NSRegularExpression类,使人高兴的是,我能够把我在Android上辛辛苦苦写好的正则表达式几乎原封不动地搬到了iOS上。
在设计界面的时候,我但愿用户在查看任务详细的时候左右滑动切换。在Android上我用了 ViewPager和新的FragmentStatePagerAdapter类,FragmentStatePagerAdapter还处于试验阶段,而且只能经过支持库(Support Library)来使用。我花了几天的时间实现了一个绑定好数据的初级版本,同时解决了几个关于重复菜单项的bug和在数据发生变化后的处理。这些比我预想的要困难不少,要不是由于左右滑动切换任务的用户体验那么好的话,我真不想实现这个功能。iOS上的UIPageViewController就简单不少了,虽然也有一些奇怪问题要解决,而且须要本身再加上缓存支持使滑动复杂视图的时候达到可用状态。
Android提供了了一个先进但很容易使用的speech-to-text API,只用20行代码,我就把RecognizerIntent集成到GQueues,提供了一个自定义的语音输入功能。但很遗憾,iOS并无提供支撑SIRI背后技术的API,开发者只能使用第三方库,依赖键盘上的麦克风提供语音输入的支持。我找了各类第三方库,包括Nuance - SIRI语音识别的提供商,但发现没有免费版本,收费版本价格不菲。因此最后GQueues只能靠用户本身使用键盘上内置的麦克风选项来进行语音输入,其实这也已经足够了,只要用户还记得有这么个功能。
经过使用Intent,在Android上能够很容易就能够把个人应用集成到安装在用户手机上的其余应用。一样地,只须要不多的代码,经过支持ACTION_SEND intent,我就可以让用户在其余应用中建立GQueues任务。Android同时也提供了一个小部件平台,因而我也作了几个小部件,之后还会增长一些。iOS对于跨应用集成和桌面小部件的支持度为零,彻底不支持这两个功能。
在上面的统计概况表中已经指出,beta版面向真实用户测试了一个多月。两组测试人员都很是棒,帮我找到了数十计的bug,提出了增长一些特性的建议,对一些UI上不合理的地方提出了反馈。我经过私有的Google Group组织beta测试,这样的beta测试保证了最后发布的应用对人们是真正有用的。在每次beta测试的最后,经过调查问卷我收集到了不少有建设性的反馈,也帮助进一步判断个人应用是否达到了可发布的状态。
让测试者开始测试只须要发个APK的连接,让他们下载到他们机器上(呃..他们还须要在设置界面中开启“容许安装Google Play之外的应用”的选项)。Google很方便地支持用真实用户来进行alpha和beta测试,可在开发者控制台和阶段推广中进行设置。在将来的版本更新中我想用用这两个功能。
iOS中的beta测试困可贵多,就算用了 TestFlight服务,虽然TestFlight很大程度地简化了流程。为了知足Apple的控制欲,每部测试设备的UUID都要加到用于签名beta版应用的证书当中。所以,每次要添加beta测试者的时候,不管是添加一我的仍是一群人,我都须要从新build一遍个人app。除此以外,Apple还限制了你一年最多只能注册100个测试设备。因此我要当心利用好这100个坑,这也是为何GQueues的iOS测试者只有Android的一半。
固然,不谈谈发布流程,Android和iOS的比较都不算完,在Google Play上发布GQueues是一件很好玩的事情,只要我认为已经准备好了,我随时能够发布个人应用。点下按钮以后,30分钟内,个人应用就能在Google Play上被全世界的用户找到并安装到他们的设备上。而在App Store上发布一款应用,相信每一个iOS开发者都有一样的感觉,那是一个使人感到郁闷的经历。通过了数月紧张严密的编码,我只能把个人创做提交给Apple,而后等7天,7天以后审核人员花2分钟看看个人应用,最后拒绝了个人提交。我只能按要求作了修改以后再次提交,我又得等8天才在最后经过了审核。固然还有不少关于提交应用到App Store的恐怖故事,跟他们比起来,我就像是公园里逛了一圈。尽管如此,在本身的商业控制上要对这样一个“情绪化的第三方平台”作出那么多的让步,仍然让我以为很不爽。
从上面的分析来看,作GQueues的过程当中,并无出现平台A完胜平台B的状况。Android和iOS在某些领域各有千秋,也都有须要改进的地方。从这两个平台的历史来看,貌似目前Android势头更猛一些,不止体如今市场占有率上,而是看到了Android近两年在UI上的改进和开发平台的稳步提高。而Apple则是封闭的王者,我也坚信他们在很努力地作着他们认为是下一代移动计算革命的事情。无论怎么说,当我想一想这6年间所兴起的app生态圈,我为本身在这个移动技术快速更新的时代,能在这两个平台上作开发感到荣幸。
原文:Android vs. iOS: Comparing the Development Process of the GQueues Mobile Apps
转载自:伯乐在线 - neevek