Android和iOS孰優(yōu)孰劣:真實(shí)應(yīng)用開(kāi)發(fā)過(guò)程告訴你答案
隨便搜索一下“Android vs. iOS”,都會(huì)出現(xiàn)很多關(guān)于哪個(gè)平臺(tái)更好的爭(zhēng)論,大多數(shù)的爭(zhēng)論點(diǎn)都是關(guān)于市場(chǎng)占有率、易用性和設(shè)備分化等問(wèn) 題。當(dāng)然也有一些“以開(kāi)發(fā)者的角度”去比較這兩個(gè)平臺(tái)的文章,但是很少有從技術(shù)上做深入的比較,通常也只是用一個(gè)簡(jiǎn)單的示例應(yīng)用介紹一些基本的特性。缺少 這種深入的比較其實(shí)是有原因的:一個(gè)公司要做一個(gè)足夠復(fù)雜的移動(dòng)應(yīng)用,通常需要一個(gè)人或團(tuán)隊(duì)做Android,另外一個(gè)人或團(tuán)隊(duì)做iOS。這兩個(gè)平臺(tái)使用 不同的編程語(yǔ)言(Java和Objective-C),提供不同的SDK,使用不同的開(kāi)發(fā)工具,所以人力資源分配上各做各的平臺(tái)也就不奇怪了。
GQueues是一個(gè)在線任務(wù)管理器,之前只有一個(gè)HTML5版本。最近我完成了GQueues for Android 和GQueues for iPhone & iPad 的開(kāi)發(fā)。雖然這兩個(gè)應(yīng)用的復(fù)雜程度不能和***人稱射擊游戲相提并論,但也絕不簡(jiǎn)單 – 為用戶存儲(chǔ)和管理數(shù)以千計(jì)的任務(wù)信息、支持多賬戶、提供到WEB端 的后臺(tái)同步、復(fù)雜的過(guò)濾、排序和分組功能。通過(guò)這次的實(shí)踐,我希望透過(guò)獨(dú)特的視角,分析和比較為這兩個(gè)平臺(tái)開(kāi)發(fā)GQueues應(yīng)用的過(guò)程。

統(tǒng)計(jì)概況
| Android App | iOS App | |
| 啟動(dòng)日期 | Sept 21, 2012 | Mar 2, 2013 | 
| ***個(gè)可測(cè)的Beta版本 | Dec 22, 2012 | June 10, 2013 | 
| 應(yīng)用發(fā)布日期 | Jan 31, 2013 | July 18, 2013 | 
| 項(xiàng)目總耗時(shí) | 4.25 months | 4.5 months | 
| Ramp Up Time | 1 week | 2 weeks | 
| 開(kāi)發(fā)耗時(shí) | 870 hours (approx) | 960 hours (approx) | 
| Beta測(cè)試&Bugfix | 34 days | 38 days | 
| Beta測(cè)試人員人數(shù) | 92 people | 48 people | 
| 代碼行數(shù) | 26,981 lines | 23,872 lines | 
| 應(yīng)用大小 | 1.1 MB | 3.5 MB | 
| 視頻預(yù)覽 | GQueues for Android Video | GQueues for iOS Video | 
| 下載 |  ![]()  | 
             ![]()  | 
        
學(xué)習(xí)曲線
我已經(jīng)寫(xiě)了12年的代碼,但這是我寫(xiě)的***個(gè)Android應(yīng)用,也是我寫(xiě)的***個(gè)偏向數(shù)據(jù)處理的iOS應(yīng)用(2010年我做過(guò)兩個(gè)iOS 3上的 游戲,但那兩個(gè)游戲主要只涉及一些動(dòng)畫(huà)和藍(lán)牙連接)。 我***一次用Java是在研究生階段,而我的Objective-C也僅限于那兩個(gè)游戲。所以對(duì)于 這兩個(gè)平臺(tái),我基本上可以算是從零開(kāi)始。
簡(jiǎn)單講,只需要花一半學(xué)習(xí)iOS的時(shí)間來(lái)學(xué)習(xí)Android,我就能開(kāi)始Android開(kāi)發(fā)。對(duì)于Android,我花了一周時(shí)間用來(lái)看書(shū)、跟著一 些教程做一些測(cè)試應(yīng)用,這些測(cè)試應(yīng)用包含了GQueues將會(huì)用到的一些核心功能。做完這些,我基本上算是打好了為GQueues設(shè)計(jì)架構(gòu)的基礎(chǔ),同時(shí)也 可以開(kāi)始為這個(gè)項(xiàng)目寫(xiě)代碼了。在接下來(lái)的一周我可以很輕松自如地基于Android做開(kāi)發(fā),而不再需要依賴某個(gè)資源去實(shí)現(xiàn)新特性了。
對(duì)于iOS,我同樣按照上面的流程,但我花了兩周時(shí)間做各種測(cè)試/實(shí)驗(yàn),才讓自己覺(jué)得可以開(kāi)始為這個(gè)項(xiàng)目寫(xiě)一些基礎(chǔ)代碼了。其中大部分的時(shí)間都花在研究CoreData各種復(fù)雜的API上面。搞清楚怎么設(shè)置、怎么在線程安全的前提下,為每個(gè)用戶集中管理PersistentStoreCoordinators和ManagedObjectContexts也花了些功夫,最重要的是要支持多賬戶(這個(gè)話題可能需要另一篇博客來(lái)單獨(dú)講講)。為FetchedResultsControllers開(kāi)發(fā)一個(gè)可擴(kuò)展的架構(gòu)花了更多時(shí)間,FetchedResultsControllers用于支持可被用戶查看以及操作的任務(wù)表單、隊(duì)列和分類。***又過(guò)了兩周(總共花了一個(gè)月)自己才能比較輕松自如地基于iOS寫(xiě)代碼。
總的來(lái)說(shuō),Android的文檔(官方文檔、第三方教程、圖書(shū)、代碼示例、StackOverflow)質(zhì)量都非常高。我從一些著名的開(kāi)源 Android應(yīng)用中學(xué)到了很多架構(gòu)上的***實(shí)踐,如Google開(kāi)放給開(kāi)發(fā)者的2012 Google I/O app。此外,Android本身就是 開(kāi)源的,必要時(shí)我可以自己查看Android的平臺(tái)代碼,弄清楚一些疑難問(wèn)題。雖然iOS也有很多文檔,但由于iOS5和iOS6相比之前的版本改動(dòng)非常 大,大部分文檔都已經(jīng)過(guò)時(shí),其中包括ARC入門(mén)一文(introduction of Automatic Reference Counting)。因此,大部分的示例代碼(包括Apple官方示例)和一些問(wèn)題的解決方法都是不正確的,需要使用新的方法取而代之。搞清楚這些肯定也需要花更多的時(shí)間。
從上面的統(tǒng)計(jì)表中也可以看出,開(kāi)發(fā)GQueues for Android要比開(kāi)發(fā) iOS 版的快十分之一的時(shí)間,盡管在開(kāi)發(fā)Android版的期間我重新實(shí)現(xiàn)了之前用于支持GQueues HTML5版的整個(gè)后端服務(wù)器同步代碼。而開(kāi)發(fā)一個(gè)不 采用原始iOS6風(fēng)格UI的應(yīng)用也需要多花些時(shí)間,單單比較這個(gè)數(shù)據(jù),Android開(kāi)發(fā)就是比iOS開(kāi)發(fā)快。
用到的資源
上面列出來(lái)的書(shū)其實(shí)用處很有限,因?yàn)楦蟛糠值募夹g(shù)類書(shū)籍一樣,書(shū)的內(nèi)容都有點(diǎn)過(guò)時(shí)了,而且大部分書(shū)只停留在入門(mén)級(jí)別的概念介紹。不過(guò),在一開(kāi)始的前幾天看一下這些書(shū),能夠比較快地理解平臺(tái)上的一些核心功能。就目前來(lái)講,對(duì)于這兩個(gè)平臺(tái),在線資源仍然是最有價(jià)值的。
工具
接下來(lái)我只簡(jiǎn)單說(shuō)一下這兩個(gè)平臺(tái)的開(kāi)發(fā)工具,因?yàn)殛P(guān)于這個(gè)話題已經(jīng)有很多的討論。我不是Eclipse或者XCode的腦殘粉,它們有各自的強(qiáng)項(xiàng)和 弱點(diǎn)(其實(shí)我最喜歡的還是Vim)。Eclipse的搜索暴慢而且很繁瑣。XCode Organizer的文檔搜索也卡爆了。Eclipse中使用 log tags(通過(guò)Android插件的logcat集成)過(guò)濾日志超級(jí)實(shí)用。兩個(gè)IDE的代碼補(bǔ)全都很不錯(cuò),XCode的 Interface Builder一點(diǎn)用處都沒(méi)有(后面細(xì)講)。不過(guò)XCode Instruments就非常有用了,可以用它做優(yōu)化分析、調(diào)試等等。 我開(kāi)始做GQueues for Android的時(shí)候,Google還沒(méi)發(fā)布Android Studio,不過(guò)在GQueues的后續(xù)更新版本中我會(huì) 拿它來(lái)試試。
如果你一邊寫(xiě)代碼一邊測(cè)試,用Android的模擬器簡(jiǎn)直就是浪費(fèi)時(shí)間(真不敢相信它能慢成這個(gè)鳥(niǎo)樣)。在開(kāi)發(fā)過(guò)程中,我都是直接部署到真機(jī)上測(cè)試 的,用真機(jī)快很多。iOS的模擬器則很不同,跟Android相比簡(jiǎn)直就是火箭跟蝸牛賽跑,這也讓整個(gè)開(kāi)發(fā)過(guò)程更加高效。每寫(xiě)一小段代碼我都會(huì)在模擬器上 跑一下,等到整個(gè)功能完成了我就會(huì)部署到真機(jī)上玩玩。
對(duì)于Android,我有各個(gè)版本的測(cè)試機(jī)器(除了Gingerbread,即Android 2.3),除此之外,就要倚靠beta測(cè)試過(guò)程中各種設(shè)備的覆蓋了。對(duì)于iOS來(lái)講就要簡(jiǎn)單很多了,我只需要拿GQueues需要支持的最舊的和***的機(jī)器來(lái)測(cè)試就夠了。
測(cè)試設(shè)備
            
  | 
            
            
  | 
        
設(shè)計(jì)
布局
GQueues的其中一個(gè)需求就是必須同時(shí)支持任意尺寸的手機(jī)和平板,并且針對(duì)不同的表單元素進(jìn)行優(yōu)化布局。由于各種各樣的設(shè)備都運(yùn)行著 Android系統(tǒng),Android也理所當(dāng)然地有著成熟的UI組件幫助開(kāi)發(fā)者支持各種尺寸。例如從Android***個(gè)版本開(kāi) 始,RelativeLayout提供了View之間相對(duì)布局的支持,可用于創(chuàng)建靈活、響應(yīng)迅速的布局。另外,在Android中所有的布局都由XML定 義,這設(shè)計(jì)界面的方式非常簡(jiǎn)潔、簡(jiǎn)單并且高效,試過(guò)iOS中創(chuàng)建布局之后這種體會(huì)就更加深刻了。
相對(duì)于Android的RelativeLayout,iOS有Auto Layout,這種布局方式比較新(iOS 6新引入的),集成到了 Interface Builder(IB)中,但是太難用了。我花了好多天學(xué)習(xí)IB中怎么用Auto Layout,跟任何iOS 6開(kāi)發(fā)者一樣,僅靠 IB為視圖(View)設(shè)定各種精確的約束,完全改變了我自己的標(biāo)準(zhǔn),這是因?yàn)镮B所謂的“智能”系統(tǒng)時(shí)刻維持(糾正)著視圖布局相對(duì)位置。我學(xué)了很多技 巧,想著彌補(bǔ)IB的短板,但是沒(méi)啥作用。***我只能放棄IB,轉(zhuǎn)而用冗長(zhǎng)的代碼實(shí)現(xiàn)所有布局。如果你放棄IB和富有極客范的 ASCII art style來(lái)寫(xiě)布局,使用Auto Layout來(lái)實(shí)現(xiàn)還是很強(qiáng)大、很直接的。希望蘋(píng)果在iOS 7中已經(jīng)改善這些,不過(guò)我還木有試 過(guò)。
如果一個(gè)應(yīng)用需要同時(shí)針對(duì)小屏設(shè)備和大屏設(shè)備進(jìn)行優(yōu)化,最關(guān)鍵的就是基于屏幕的真實(shí)尺寸進(jìn)行動(dòng)態(tài)組合視圖,這種方式被稱作“適配性布局 (Adaptive Layout)”,平板電腦可以在一屏中顯示兩個(gè)或三個(gè)視圖,而手機(jī)上一屏則只顯示一個(gè)視圖。Android通過(guò)Fragments 支持這種設(shè)計(jì),F(xiàn)ragment是一個(gè)獨(dú)立的、自包含的的模塊,能夠在需要的時(shí)候直接丟到Activity中去用。通過(guò)使用Fragments,只需要調(diào) 整幾行XML代碼就可以讓GQueues的布局適配不同分辨率的屏幕。對(duì)于我來(lái)講,F(xiàn)ragments是一種非常自然的解決方案,因?yàn)樗腔诿嫦驅(qū)ο罄?面兩個(gè)眾所周知的準(zhǔn)則設(shè)計(jì)的 - 高內(nèi)聚和低耦合。
通過(guò)Custom Container View Controller(你也可以用Master-Detail模板,當(dāng)然這種方式寬度是固定的, 也不支持個(gè)性化定制),iOS支持一屏使用多個(gè)ViewController。對(duì)于這個(gè)不成熟的特性,我覺(jué)得Apple的文檔顯得很復(fù)雜和不完整,***的 資源還要數(shù)Ray’s iOS5 tutorials和WWDC視頻。我花了比預(yù)計(jì)要多的時(shí)間,終于搞好了在iPad上同時(shí)顯示多個(gè)View、在 iPhone上顯示單個(gè)View的布局架構(gòu)。
設(shè)備翻轉(zhuǎn)
簡(jiǎn)單說(shuō),在Android上支持設(shè)備翻轉(zhuǎn)需要做很多工作,這些工作也是最終導(dǎo)致很多bug的源頭,而在iOS上,支持屏幕翻轉(zhuǎn)只需要做一點(diǎn)點(diǎn)工作, 剩下就是系統(tǒng)幫我們搞定了。在Android上,屏幕翻轉(zhuǎn)會(huì)直接銷毀現(xiàn)有整個(gè)視圖棧(Activity棧),屏幕翻轉(zhuǎn)完成后再重建每個(gè)視圖。所以在 GQueues中支持屏幕翻轉(zhuǎn),我需要無(wú)時(shí)無(wú)刻保存好所有當(dāng)前狀態(tài),隨時(shí)保證翻轉(zhuǎn)后能正?;謴?fù)狀態(tài)。而在iOS上,系統(tǒng)會(huì)幫你管理所有屏幕翻轉(zhuǎn)相關(guān)的細(xì) 節(jié),唯一需要我關(guān)心的就是翻轉(zhuǎn)之后,我需要調(diào)整那些沒(méi)有被Auto Layout處理好的視圖的位置。
“復(fù)雜”布局

網(wǎng)頁(yè)開(kāi)發(fā)上有一些常見(jiàn)的布局在GQueues上實(shí)現(xiàn)起來(lái)非常困難,不管是Android還是iOS。其中一個(gè)例子是在任務(wù)詳細(xì)界面顯示標(biāo)簽。每個(gè)標(biāo) 簽都是變長(zhǎng)的,在必要時(shí)標(biāo)簽需要自動(dòng)換行。在網(wǎng)頁(yè)上實(shí)現(xiàn)這個(gè)只需要設(shè)置CSS的float值就可以了。但不管是Android還是iOS對(duì)這種“流式布 局”(Flow Layout)都沒(méi)有原生的支持,這也意味著我需要寫(xiě)很多代碼自己去計(jì)算和擺放這些標(biāo)簽,以達(dá)到“流式布局”的效果。***Android 的代碼是基于Romain Guy的演講內(nèi)容和Artem Votincev的flow layout實(shí)現(xiàn)的。在iOS上也采用了類似的方法,基于容器的總寬度,計(jì)算每個(gè)標(biāo)簽的寬度,***設(shè)置auto layout的參數(shù)。對(duì)于這個(gè)布局的實(shí)現(xiàn)在兩個(gè)平臺(tái)上都耗了很大的工作量。
舊設(shè)備支持
關(guān)于Android的生態(tài)系統(tǒng)常被人吐槽的就是嚴(yán)重的系統(tǒng)分化。運(yùn)營(yíng)商推送更新的步伐總是很慢,所以現(xiàn)在仍有大量運(yùn)行著舊系統(tǒng)的設(shè)備,這也就意味著 如果要保證應(yīng)用足夠大的設(shè)備覆蓋率,開(kāi)發(fā)者就不能使用新版系統(tǒng)帶來(lái)的新特性。不過(guò)好在現(xiàn)在針對(duì)這個(gè)問(wèn)題,Android社區(qū)做了很大的努力,提供了一些用 于在舊系統(tǒng)上支持新特性的庫(kù)。通過(guò)使用Android官方的 Support Library和Jake Wharton的ActionBarSherlock Library,我?guī)缀蹩梢栽贏ndroid 2.2上使用Jelly Bean(4.2)中所有的新特性。
對(duì)于iOS來(lái)說(shuō),支持舊系統(tǒng)一說(shuō)幾乎不存在,或者說(shuō)根本就不是關(guān)鍵。在準(zhǔn)備階段我花了一些時(shí)間考慮從哪個(gè)iOS版本開(kāi)始支持,而當(dāng)時(shí)的統(tǒng)計(jì)數(shù)據(jù)顯示使用iOS 6系統(tǒng)的設(shè)備已經(jīng)達(dá)到83%, 而當(dāng)時(shí)對(duì)于放棄支持iPad一代我也有一些疑慮,因?yàn)槲依习掷蠇尷辖阌玫木褪莍Pad一代,他們將是GQueues的鐵桿支持者。***我決定還是只支持 iOS 6+,這樣我可以放開(kāi)手使用Auto Layout,而不需要浪費(fèi)大量時(shí)間實(shí)現(xiàn)任何過(guò)時(shí)的布局技術(shù)。當(dāng)然,我解決了iPad一代的問(wèn)題(至少對(duì)我 家里人說(shuō)來(lái)說(shuō)已經(jīng)解決),就是換掉他們的iPad一代,給他們每人買一個(gè)iPad四代(作者有錢(qián)銀)。
架構(gòu)
數(shù)據(jù)存儲(chǔ)和管理
對(duì)于GQueues來(lái)說(shuō),數(shù)據(jù)是核心 - 把數(shù)據(jù)保存到設(shè)備上然后同步到WEB端。Android和iOS有著完全不同的數(shù)據(jù)管理系統(tǒng)。 Android提供了ContentProvider,它是SQLite數(shù)據(jù)庫(kù)上層的一個(gè)可被繼承的應(yīng)用接口,作為一個(gè)結(jié)構(gòu)化框架被用于所有應(yīng)用的數(shù)據(jù)處 理。ContentProvider學(xué)習(xí)起來(lái)比較難,搞定一個(gè)GQueues可用的實(shí)現(xiàn),前期需要花很多工作。一旦搞定了***步后面的擴(kuò)展和個(gè)性化定制都 變得簡(jiǎn)單多了。
一些背景信息,GQueues的web service是基于Google App Engine’s Datastore的, 這是一個(gè)高擴(kuò)展性的分布式NoSQL存儲(chǔ)系統(tǒng),而SQLite則是一個(gè)標(biāo)準(zhǔn)的關(guān)系型數(shù)據(jù)庫(kù),擴(kuò)展性明顯也比較差,但這完全不需要考慮,因?yàn)檫@個(gè)應(yīng)用只存儲(chǔ) 一個(gè)用戶的數(shù)據(jù)。(順便說(shuō)一下,架構(gòu)上我采用了“一個(gè)用戶對(duì)應(yīng)一個(gè)數(shù)據(jù)庫(kù)”的設(shè)計(jì),這對(duì)于快速簡(jiǎn)單地實(shí)現(xiàn)多用戶切換有重要意義,不過(guò)實(shí)現(xiàn)細(xì)節(jié)可能得再開(kāi)一 博來(lái)聊了)。不管怎么說(shuō),Android的一個(gè)很大的優(yōu)點(diǎn)就是可以創(chuàng)建SQLite Views來(lái)支持Smart Queues。為了支持Smart Queues,搞清楚各種復(fù)雜的表關(guān)聯(lián)查詢和子查詢也花了寫(xiě)功夫,但是這也讓Smart Queues的加載更加高效和快速,因?yàn)檫^(guò)濾不是在代碼里面實(shí)現(xiàn)的(在SQL里面)。

在iOS上,我用的是Core Data, 它是iOS上的“schema驅(qū)動(dòng)數(shù)據(jù)圖形管理和持久化框架”,基本上它可以被看做是一個(gè)NoSQL存儲(chǔ),不過(guò)有趣的是,Core Data背后實(shí)際上是 SQLite數(shù)據(jù)庫(kù)(呃…實(shí)際上SQLite也是幾個(gè)可選項(xiàng)中最合理的選擇)。iOS也允許用戶直接創(chuàng)建SQLite數(shù)據(jù)庫(kù),但只支持通過(guò)純C代碼來(lái)操 作,對(duì)于其他iOS組件沒(méi)有原生集成。Core Data的學(xué)習(xí)起來(lái)也比較困難,但***我還是選擇Core Data而不用SQLite,因?yàn)檫@樣我可以 輕松實(shí)現(xiàn)很多功能,包括緩存、數(shù)據(jù)模型遷移支持,還有通過(guò) NSFetchedResultsController,可以非常簡(jiǎn)單地為界面中的 table(列表)提供數(shù)據(jù)。
管理數(shù)據(jù)集的關(guān)鍵就是使用事務(wù),尤其重要是做數(shù)據(jù)同步的時(shí)候 - ACID,即:atomic(原子性)、consistent(一致性)、 isolated(隔離性)、durable(持久性)。Android上實(shí)現(xiàn)事務(wù)似很直觀,跟大部分關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)的實(shí)現(xiàn)方式是一樣的,因此,保 證數(shù)據(jù)完整性并不困難。另外,用好SQLite中的UNIQUE ON CONFLICT REPLACE語(yǔ)句,在數(shù)據(jù)同步的過(guò)程中建表、對(duì)記錄進(jìn)行原子更新的時(shí)候幾乎不需要做任何額外工作。
嚴(yán)格來(lái)講,Core Data并不完全支持事務(wù)。通過(guò)使用單獨(dú)的子ManagedObjectContexts做后臺(tái)線程處理,再加上@synchronized,能夠處理好數(shù)據(jù)更新和同步,同時(shí)避免不正確的寫(xiě)操作覆蓋(overwrite)。關(guān)于高效更新和創(chuàng)建對(duì)象,iOS給的建議幫助很小,總的來(lái)說(shuō),CoreData給我的趕腳很笨重,并沒(méi)有它聲稱的那么好用。另外,在Android上,SQLite可以輕松實(shí)現(xiàn)快速加載Smart Queues,而在iOS上,所有的過(guò)濾都必須在代碼中實(shí)現(xiàn),就算用了大量的緩存,速度仍然很慢。
搜索
在GQueues for Android上增加強(qiáng)大的全文搜索功能很簡(jiǎn)單,我模仿Google I/O應(yīng)用里面的搜索實(shí)現(xiàn),使用了SQLite的FTS3特性。首先創(chuàng)建一個(gè)虛擬表,然后在一個(gè)存儲(chǔ)了用戶任務(wù)的表上設(shè)置幾個(gè)觸發(fā)器,由這些觸發(fā)器填充數(shù)據(jù)到虛擬表。做完了這些,剩下的就是設(shè)計(jì)一個(gè)搜索界面和為搜索歷史添加存儲(chǔ)。
iOS的Core Data對(duì)于全文搜索并沒(méi)有原生支持,所以我通過(guò)在謂詞(Predicate)中使用LIKE語(yǔ)句,實(shí)現(xiàn)基本的任務(wù)描述和日記的搜索功能。這個(gè)實(shí)現(xiàn)當(dāng)然沒(méi)有全文搜索那么強(qiáng)大,但我認(rèn)為它已經(jīng)能夠覆蓋現(xiàn)實(shí)生活中大部分的使用場(chǎng)景了。
特性API
用于比較,我只會(huì)列舉在GQueues中使用到的幾個(gè)API。
快速添加(Quick Add)
正則表達(dá)式在實(shí)現(xiàn)GQueues中Quick Add解 析的時(shí)候扮演著一個(gè)非常重要的角色,幸運(yùn)的是,Android和iOS對(duì)于正則表達(dá)式都有著原生的支持。Android中的Pattern和 Matcher從***個(gè)版本起就開(kāi)始支持,同時(shí)也包含了很多正則語(yǔ)法,其中包括前向斷言(look-ahead assertion)和后向斷言 (look-behind assertion)。iOS則從iOS 4開(kāi)始引入NSRegularExpression類,令人高興的是,我可以把我在Android上辛辛苦苦寫(xiě)好的正則表達(dá)式幾乎原封不動(dòng)地搬到了iOS上。
分頁(yè)

在設(shè)計(jì)界面的時(shí)候,我希望用戶在查看任務(wù)詳細(xì)的時(shí)候左右滑動(dòng)切換。在Android上我用了 ViewPager和新的FragmentStatePagerAdapter類,F(xiàn)ragmentStatePagerAdapter 還處于試驗(yàn)階段,并且只能通過(guò)支持庫(kù)(Support Library)來(lái)使用。我花了幾天的時(shí)間實(shí)現(xiàn)了一個(gè)綁定好數(shù)據(jù)的初級(jí)版本,同時(shí)解決了幾個(gè)關(guān)于重 復(fù)菜單項(xiàng)的bug和在數(shù)據(jù)發(fā)生變化后的處理。這些比我預(yù)想的要困難很多,要不是因?yàn)樽笥一瑒?dòng)切換任務(wù)的用戶體驗(yàn)?zāi)敲春玫脑?,我真不想?shí)現(xiàn)這個(gè)功能。iOS 上的UIPageViewController就簡(jiǎn)單很多了,雖然也有一些奇怪問(wèn)題要解決,并且需要自己再加上緩存支持使滑動(dòng)復(fù)雜視圖的時(shí)候達(dá)到可用狀態(tài)。
語(yǔ)音輸入
Android提供了了一個(gè)先進(jìn)但很容易使用的speech-to-text API,只用20行代碼,我就把RecognizerIntent集成到GQueues,提供了一個(gè)自定義的語(yǔ)音輸入功能。但很遺憾,iOS并沒(méi)有提供支撐SIRI背后技術(shù)的API,開(kāi)發(fā)者只能使用第三方庫(kù),依賴鍵盤(pán)上的麥克風(fēng)提供語(yǔ)音輸入的支持。我找了各種第三方庫(kù),包括Nuance - SIRI語(yǔ)音識(shí)別的提供商,但發(fā)現(xiàn)沒(méi)有免費(fèi)版本,收費(fèi)版本價(jià)格不菲。所以***GQueues只能靠用戶自己使用鍵盤(pán)上內(nèi)置的麥克風(fēng)選項(xiàng)來(lái)進(jìn)行語(yǔ)音輸入,其實(shí)這也已經(jīng)足夠了,只要用戶還記得有這么個(gè)功能。
分享/插件(小部件)
通過(guò)使用Intent,在Android上可以很容易就可以把我的應(yīng)用集成到安裝在用戶手機(jī)上的其他應(yīng)用。同樣地,只需要很少的代碼,通過(guò)支持ACTION_SEND intent,我就能夠讓用戶在其他應(yīng)用中創(chuàng)建GQueues任務(wù)。Android同時(shí)也提供了一個(gè)小部件平臺(tái),于是我也做了幾個(gè)小部件,以后還會(huì)增加一些。iOS對(duì)于跨應(yīng)用集成和桌面小部件的支持度為零,完全不支持這兩個(gè)功能。
測(cè)試和發(fā)布
beta測(cè)試
在上面的統(tǒng)計(jì)概況表中已經(jīng)指出,beta版面向真實(shí)用戶測(cè)試了一個(gè)多月。兩組測(cè)試人員都非常棒,幫我找到了數(shù)十計(jì)的bug,提出了增加一些特性的建 議,對(duì)一些UI上不合理的地方提出了反饋。我通過(guò)私有的Google Group組織beta測(cè)試,這樣的beta測(cè)試保證了***發(fā)布的應(yīng)用對(duì)人們是真正 有用的。在每次beta測(cè)試的***,通過(guò)調(diào)查問(wèn)卷我收集到了很多有建設(shè)性的反饋,也幫助進(jìn)一步判斷我的應(yīng)用是否達(dá)到了可發(fā)布的狀態(tài)。
讓測(cè)試者開(kāi)始測(cè)試只需要發(fā)個(gè)APK的鏈接,讓他們下載到他們機(jī)器上(呃..他們還需要在設(shè)置界面中開(kāi)啟“允許安裝Google Play以外的應(yīng)用”的選項(xiàng))。Google很方便地支持用真實(shí)用戶來(lái)進(jìn)行alpha和beta測(cè)試,可在開(kāi)發(fā)者控制臺(tái)和階段推廣中進(jìn)行設(shè)置。在未來(lái)的版本更新中我想用用這兩個(gè)功能。
iOS中的beta測(cè)試?yán)щy得多,就算用了TestFlight服 務(wù),雖然TestFlight很大程度地簡(jiǎn)化了流程。為了滿足Apple的控制欲,每部測(cè)試設(shè)備的UUID都要加到用于簽名beta版應(yīng)用的證書(shū)當(dāng)中。因 此,每次要添加beta測(cè)試者的時(shí)候,不論是添加一個(gè)人還是一群人,我都需要重新build一遍我的app。除此之外,Apple還限制了你一年最多只能 注冊(cè)100個(gè)測(cè)試設(shè)備。所以我要小心利用好這100個(gè)坑,這也是為什么GQueues的iOS測(cè)試者只有Android的一半。
發(fā)布
當(dāng)然,不談?wù)劙l(fā)布流程,Android和iOS的比較都不算完,在Google Play上發(fā)布GQueues是一件很好玩的事情,只要我認(rèn)為已經(jīng) 準(zhǔn)備好了,我隨時(shí)可以發(fā)布我的應(yīng)用。點(diǎn)下按鈕之后,30分鐘內(nèi),我的應(yīng)用就能在Google Play上被全世界的用戶找到并安裝到他們的設(shè)備上。而在 App Store上發(fā)布一款應(yīng)用,相信每個(gè)iOS開(kāi)發(fā)者都有同樣的感受,那是一個(gè)令人感到郁悶的經(jīng)歷。經(jīng)過(guò)了數(shù)月緊張嚴(yán)密的編碼,我只能把我的創(chuàng)作提交 給Apple,然后等7天,7天之后審核人員花2分鐘看看我的應(yīng)用,***拒絕了我的提交。我只能按要求做了修改之后再次提交,我又得等8天才在***通過(guò)了 審核。當(dāng)然還有很多關(guān)于提交應(yīng)用到App Store的恐怖故事,跟他們比起來(lái),我就像是公園里逛了一圈。盡管如此,在自己的商業(yè)控制上要對(duì)這樣一個(gè)“情 緒化的第三方平臺(tái)”做出那么多的讓步,仍然讓我覺(jué)得很不爽。
獲勝的平臺(tái)
從上面的分析來(lái)看,做GQueues的過(guò)程中,并沒(méi)有出現(xiàn)平臺(tái)A完勝平臺(tái)B的情況。Android和iOS在某些領(lǐng)域各有千秋,也都有需要改進(jìn)的地 方。從這兩個(gè)平臺(tái)的歷史來(lái)看,貌似目前Android勢(shì)頭更猛一些,不止體現(xiàn)在市場(chǎng)占有率上,而是看到了Android近兩年在UI上的改進(jìn)和開(kāi)發(fā)平臺(tái)的 穩(wěn)步提升。而Apple則是封閉的王者,我也堅(jiān)信他們?cè)诤芘Φ刈鲋麄冋J(rèn)為是下一代移動(dòng)計(jì)算革命的事情。不管怎么說(shuō),當(dāng)我想想這6年間所興起的app生 態(tài)圈,我為自己在這個(gè)移動(dòng)技術(shù)快速更新的時(shí)代,能在這兩個(gè)平臺(tái)上做開(kāi)發(fā)感到榮幸。

















 
 
 






 
 
 
 