移動混合應用Hybrid App開發實戰
【引言】近年來隨著移動設備類型的變多,操作系統的變多,用戶需求的增加,對于每個項目啟動前,大家都會考慮到的成本,團隊成員,技術成熟度,時 間,項目需求等一堆的因素。因此,開發App的方案已經變得越來越多了。曾經有一段HTML5的小浪潮,無數的人參與或者看到過一個討論:原生開發還是混 合開發,又或者是Web開發?到底***實踐是怎樣的,筆者認為只有實踐過的人才會知道。尤其是在這個充滿各種變數的移動互聯網時代。
【摘要】筆者將從Hybrid App的開發現狀出發,闡述Hybrid App的優缺點,同時對比Hybrid App與Native App的各自特性,***探討一下Hybrid App的新思想方向。
Hybrid App現狀分析
Web App
毫無疑問Web App就是成本***,最快速地解決方案了。尤其是近兩年非常流行的響應式設計,Web App市場提供了非常好的實踐場地。最近典型的Web App***案例是Sun天氣應用了,其細節處理讓人贊不絕口。
一般來說,擁有下面特點的就是一個Web App了:使用瀏覽器運行;純Web前端架構,很多重要手機特性無法訪問,例如聯系人以及Push notification之類的;Single Page App;銷售渠道多限于瀏覽器。
Hybrid App
所謂的Hybrid App其實會有不同的分支。而且會和Native應用有重合的地方。下面就說三種不同的解決方案。
方案一:使用PhoneGap、AppCan之類的中間件,以WebView作為用戶界面層,以Javascript作為基本邏輯,以及和中間件通訊,再由中間件訪問底層API的方式,進行應用開發。這種架構一般會非常依賴WebView層的性能。
方案二:使用Adobe Air、RubyMotion、Appcelerator或者是Xamarin這種非官方語言的工具,打包成原生應用的方式開發。為什么筆者會將它們定義 為Hybrid App,主要是它們并沒有很單純地使用原生提供的語言進行開發,而是通過對開發者提供友好的開發工具,并折中地把這種開發語言轉換成原生語言,最終打包出 整個應用,所以也屬于混合應用范疇。
方案三:在開發原生應用的基礎上,嵌入WebView但是整體的架構使用原生應用提供,一般這樣的開發由Native開發人員和Web前端開發人員 組成。Native開發人員會寫好基本的架構以及API讓Web開發人員開發界面以及大部分的渲染。保證到交互設計,以及開發都有一個比較折中的效果出 來,優化得好也會有很棒的效果。(當年Facebook Three20就使用該方案)
因此,Hybrid App有以下的特性:
- 開發時可能不采用或者大部分不采用原生語言,但是卻有所有原生應用的特性;
- 架構方案會和原生有出入,基本由工具而定;
- 具有跨平臺特性;
- 一般開發相對原生開發的方式要簡單。
Native App
Native App毫無疑問是最可靠的方案。但是學習成本,人才成本,開發效率以及照顧不同平臺的特性去考慮,都成為了開發人員心目中的一道坎。至于說這道坎是不可逾 越的還是一道讓你提高的坎,筆者覺得完全取決于你自己。基于種種因素的考慮,估計很多人就會選擇折中的方案到了Hybrid App的開發行列當中,包括筆者自己也是這樣過來的。
下面更多的內容都將圍繞Hybrid App開發展開討論。
Hybrid App在開發當中的優點和缺點
在Hybrid App的開發過程中,幾種不同的方案筆者都有經歷過。當然也經歷到了Native App的開發階段。在如此糾結復雜的過程中給了筆者不少的經驗,下面筆者也會就自身的經驗和大家分享這些方案當中的優缺點。對于初入行的朋友,筆者是從 Web前端入行的,畢竟門檻較低,而且能夠快速地培養自己的信心以及對代碼的感覺。深入后就開始接觸到移動開發這塊了。所以會先從Hybrid App的***種方案說起吧。
方案一(Web架構為重)
優點:
- 全Web開發,一定程度上有利于Web前端技術人員快速地構建頁面樣式;
- 有利于在不同的平臺上面展示同一個交互層;
- 便于調試,開發的時候可以通過瀏覽器的方式進行調試,工具豐富。
缺點:
- 雖然說你可以專注在界面以及交互開發上了,但是這頁會成為一個缺點,比如說要仿造一個iOS的默認設置界面,就需要大量的html以及css代碼了,而且效果不一定和iPhone上面的界面一樣好;
- 正因為這是跨平臺的開發,所以還是這句話:兼容是前端的痛。了解過在Android機器上面的Web開發就知道這個痛了。比如前些年在Android設備上面寫圓角,border-radius:10px,在Android的設備上面會出現毛邊。
- 便于調試其實是在Web界面層的。但是實際上做Hybrid App開發的時候,你會遇到需求,進入手機的底層請求,做某些處理。比如說如果該應用有Push Notification服務的話,你就需要到底層,獲取Push Notification發生時的數據,以及做相應的交互處理。當然類似PhoneGap這類框架,已經有很好的插件機制去幫助你解決類似的問題,當然還 有Game Center之類的插件,具體的話可以到Github去關注PhoneGap官方的賬戶,資源非常豐富;
方案二(編譯轉換方式)
優點:
- 利用自己熟悉的語言,進行應用開發,比如RubyMotion,就是使用Ruby語言去做iOS開發,開發起來的話,代碼量是數量級地下降啊。
- 部分開發工具提供跨平臺的功能,讓你的應用能夠快速地發布到不同的平臺上面。比如Mono社區的Xamarin,就是典型的例子了。使用C#語言,能夠把你的應用發布到iOS,Android以及WinPhone市場上面;
- 開發出來的程序運行高效。大部分這種架構的應用,其實還是非常依賴底層的東西的,而且包括界面的東西,都是使用原生的API,效率就當然要比類似于PhoneGap這種架構要好了;
缺點:
嚴重依賴于其工具廠商提供的工具包,調試的時候就要有全套的工具。當然一般來說這些廠商都會以收費的形式發布他們的工具,相應的也有客服提供技術支 持。遇到系統升級,第三方sdk升級,開發工具出現bug等,那么就要等待工具廠商解決了。相當于把風險壓在對方身上了,自己卻要承擔責任。
方案三(Native架構為重)
優點:
- 這無疑是最穩定的Hybrid App開發方式了,交互層的效率上由Native的東西解決了,而且架構上基本就是在App內寫網頁,連App Store都是采用了該種方案;
- 開發時分工非常明確,底層的由iOS開發人員處理,上層的由Web前端開發人員處理;
- 有效的在線參數配置方式,以便于及時在線替換界面;
缺點:
- 團隊至少需要兩個工程師,一個是Web的,一個是iOS的。當然如果開發人員會兩種技術也可獨立承擔;
- 還是運行效率,要權衡好多少界面采用Web來渲染,畢竟WebView的效率會相對降低,以前Facebook就是因為Web的渲染效率 低下,把整個應用改為原生的解決方案。當然這里面可以通過優化來解決。但是優化也是有限度的,如Ruby創始人Matz所說優化要恰當(包括花的時間,技 巧等),而且有時候的優化達到的回報率不一定達到你自己的期望。
Hybrid App和Native App開發對比
因為方案三中的思想基本上就是原生應用的開發思想了。這里要做的對比應該不算大,因此筆者不會做太多的闡述介紹兩者的不同。但是如果是偏重Web架 構的,或者是以方案二這種透過特殊工具開發的,就和原生開發有對比了。這次筆者暫時會以方案一拿來討論。討論中主要會以架構,代碼管理上來討論,當然也會 說到部分細節。
架構討論:
因為這是偏重于Web開發的應用,這里面就需要開發人員有很強烈的大型Web前端架構思想在里面。提到這里可能馬上浮現在你腦海中的詞語就 是:angular.js,require.js,sea.js,backbone.js等。沒錯,這些工具都能夠幫助你快速地梳理好思路,管理好你的 Web應用。對開發者最友好的,發揮空間***的非PhoneGap莫屬了。所以筆者就會以PhoneGap應用展開討論。(因為類似Sencha也有提供 方案,但是Sencha本身是一個重量級的框架,而且有自己的思想在里頭,加上他本身也提供開發工具,在這里就不適合討論了。對于開發者來說可以根據自己 的需求選擇好工具)
從工具上看:
用于雙向綁定,網絡請求,視圖管理等工作。
javascript模塊化工具,在使用較多的交互對象,PhoneGap插件的時候,你就會發現一個強大的模塊化工具會在開發的時候提供極好的幫助。能夠幫助你把整體的代碼,管理得井井有條。
模板引擎。筆者個人比較推薦使用Jade,而且筆者本人也在博客中多次寫到Jade在不同場景下使用的技巧的有關文章。主要是jade的語法太簡潔了,而且面向JS開發人員非常友好。如果你還沒有開始使用模板引擎,趕緊加入這個隊列吧,你已經落后了。
如果你暫時還沒有一個設計師,但是又急于構造一個應用出來。jquery mobile就提供了多套不同風格的模板,供你使用,而且還含有不同的交互動畫等。而且也是跨平臺的。當然實際場景中,筆者覺得你會花很多時間在寫css 上面,因為設計總是天馬行空的。當然你還有很多工具啦,例如sass,以及less.js等。
PhoneGap.js或者Cordova.js
做Phonegap開發必須使用的代碼庫,用于和PhoneGap框架通訊。現在這個庫已經改名了,是Cordova。具體為什么改名,得問Adobe咯。
PhoneGap的插件能夠幫助你快速地抵達手機的其他API上面,直接使用Javascript來操控這些底層的API。例如調用Push Notification的相應發生的事件。
從代碼目錄上面看混合應用中的Web層:
- /js
- mainView.js
- settingView.js
- networkObject.js
- renderObject.js
- /lib
- /PhoneGapPlugins
- push-notification-plugin.js
- pickerView.js
- PhoneGap.js
- zepto.js
- jquerymobile.js
- iscroll.js
- angular.js
- jade.js
- /css
- /mainView
- listItemTemplate.css
- questionListTemplate.css
- /settingView
- /personView
- /layout
- navigationBar.css
- tabButton.css
- app.css
- /template
- /mainView
- listItemTemplate.txt
- questionListTemplate.txt
- /settingView
- /personView
- /layout
- navigationBarTemplate.txt
- tabButtonTemplate.txt
- index.html
- app.js
- require.js
從代碼的目錄上面看,就是經典的靜態網頁文件的目錄,非常簡單。下面就用一句話來說說整個應用的運作過程吧:
打開PhoneGap應用 ->進入 index.html ->運行require.js ->加載應用資源 -> app.js 控制整個應用 -> angular.js 進行事件綁定以及視圖渲染 ->視圖渲染的時候會將數據和加載好的視圖模板(template目錄下的代碼)處理 ->經過jade模板引擎 ->渲染到相應的位置上
就是如此簡單。
看完了簡單的PhoneGap應用后,筆者們來看看簡單iOS應用在開發時候的代碼目錄吧。思路上還是非常相似的。在這里面,筆者不會深入代碼部分去討論具體的實現以及細節上的東西。
- demoApp
- /Resource
- navigationBar.png
- navigationBar@2x.png
- /demoApp
- AppDelegate.h
- AppDelegate.m
- /SettingViewController
- settingViewController.h
- settingViewController.m
- /MainViewController
- mainViewController.h
- mainViewController.m
- /Supporting Files
- demoApp-Info.plist
- InfoPlist.strings
- ...
- /plugin
- /AFNetworking
- AFHTTPClient.h
- AFHTTPClient.m
- AFHTTPRequestOperation.h
- AFHTTPRequestOperation.m
- ...
- /Frameworks
- CoreData.framework
- UIKit.framework
- /Products
- demoApp.app
Objective-C 是一種通用、高級、面向對象的編程語言。Objective-C是承自Smalltalk的信息傳遞模型(message passing)。Objective-C里,與其說對象互相調用方法,不如說對象之間互相傳遞信息更為精確。Objective-C強調面對對象編程, 且Objective-C中強制要求將類的(interface)與實現(implementation)分為兩個部分。類的定義文件遵循C語言之慣例以 .h 為后綴,實現文件以 .m 為后綴。所以你會看到大量的類文件在里頭,整個工程就是有不同的類構成的。(當然可能這么描述不太準確,但是便于大家理解)
這就和豐富的Web前端有很大區別了,在Web前端開發里有HTML,CSS,JS三劍客,必須要用好這三個東西才可以把整個應用才可構建出來。但 是在Native應用中,就很單一了。你只需要把握好Objective-C就可以了。因此對于原生應用來說,開發時只要遵守好規范,即使是一個新手參與 開發,也可以快速地上手,看懂代碼。因為模式已經定好,大家使用同一套的API。按著流程走就好了。當然學習Objective-C需要過程,但是對于擁 有C語言,Java語言經驗的開發者來說,是非常簡單的事情。
當然,原生開發的缺點也很明顯了,就是滿足不了你的跨平臺需求。
從代碼目錄上面看,其實也基本上看到筆者為什么使用多種JS庫以及框架的原因了。主要的目的就是為了構建一個可維護的,具有規范性的Web應用。因 為本身Javascript這門語言非常靈活,100個人可以具有100種風格,加上沒有專門對于Javascript開設的課程,在過往都容易存在對這 門語言的誤解。基于種種的原因,就要約束好一個應用的代碼風格,架構。此外,Javascript本身沒有類的概念,所以在Javascript的面向對 象編程中:Javascript的數據和成員封裝很簡單。沒有類,完全是對象操作。這和Objective-C有很大不同。這個時候必須要有一種心態處理 好整個Web應用:就是盡可能地抽象成對象,你的工作就是對象與對象之間存在交流。
另外有一些點是值得開發者注意的。對于原生應用來說,不管是iOS的,還是Android的,都會提供一套原生界面的庫。以Objective-C 為例子。如果筆者需要調用Alert,筆者只需要編寫:UIAlertView * alertView = [[UIAlertViewalloc]init];,就把這個view聲明好了。再去執行相應的方法,就可以了。但是對于Web應用來說,就需要編 寫<div id='alertView'><button>確定</button></div><script& gt;$('#alertView').show();</script>
,一堆的css代碼和html代碼去實現。當然你會詢問筆者,直接寫 alert() 不就可以了嗎?要是真這么簡單的話,建議你在iOS的WebView中編寫一下alert,實現:title 是提示,內容是:alert view,確定按鈕的文字是:好的。你就知道WebView的限制在哪里了。
因此要完成JS在Web App開發當中的***實踐,肯定要學習優秀的思想和實現方法了。在這篇文章里面,筆者們暫時先不去做這種深入的討論。而是先把例子拋給大家,也許會在下一次討論的時候,再詳細深入以下這兩個項目。
***個是斯坦福的iOS開發公開課中的例子,使用objective-c實現,一個簡單的卡牌游戲。這是經典的mvc開發了。項目地址如下:https://github.com/lbj96347/Stanford-W2013-CardGame,如果您正在使用Mac,那恭喜你,可以馬上編譯這個游戲進行測試以及代碼瀏覽。
第二個是使用JavaScript編寫的例子,實現同樣的需求,做一個簡單的卡牌游戲。但是使用的是HTML+CSS+JS開發。同樣學習了繼承以及mvc的思想。項目地址是:https://github.com/lbj96347/JSMatchismo ,再次恭喜你,不管使用什么電腦,都可以隨時瀏覽代碼以及運行該游戲。
Hybrid App的新思想
這兩年多以來,因為市場的不同,也出現了不一樣的需求,各個技術都有了新的發展。對于Hybrid App來說,其實都有了一些新的解決方案。為了解決問題其實最終思想都會被還原成以下幾個點上:
- 根據需求,選擇工具;
- 用適當的工具做適當的事情,有針對性地解決問題;
- 世界是平衡的,對于開發者來說,做的有用功越多,用戶體驗就越好,反之越差;
- 跨平臺是一個"幌子",什么都做得到不代表什么都做得好
這也是筆者體驗最深的幾個點。而且你會發現Hybrid技術也基本在跟隨這幾個點來走。
根據需求,選擇工具
如果你使用過Jquery Mobile,你做過過場動畫(就是從一個view去到另一個view),過場動畫在iOS的navigationController中很常見,而且很 簡單,效果很好很流暢。在Jquery Mobile中使用ajax,css去實現了,核心代碼可能就幾十行。可能跟iOS里面的差不多(如果包含動畫),但是實際出來的效果卻差強人意。會出現 類似的問題:頁面抖動,感覺不連貫,在部分的設備下運行緩慢。如果你的應用要求的體驗并不是很高,例如一些新聞展示類應用,更強調排版。這里小小的體驗差 距,就可以忽略了。(因為英國BBC就是這么干的),但是如果你的應用非常強調體驗細節,這里的解決方案可能就不適合了。或許你要做優化,但是優化的時間 可能足以夠你去學習更多的東西了。這樣的話,你是繼續選擇用一個不成熟的工具,還是選擇去學習一種新的語言呢?所以還是根據需求而定吧。
另外一個例子。曾經有人跟筆者提及到,在使用HTML和CSS編寫應用界面時確實很爽,但是效率不咋的。那為什么不嘗試把應用內容直接搬到 Canvas里面呢?構造一套足夠強大的工具,一套足夠彪悍的UI組件,把整個應用運行于Canvas中。這種想法是很好的,但是其實里面的短板頁就出現 了,Canvas的性能雖高,但是里面的元素組件多了你可以保證效果高?所有的東西都會依賴于JavaScript,這對于Javascript來說要構 造足夠強悍的面向對象的組件,也非簡單之事,拋棄了CSS和HTML,意味著內部的設計組件能夠高度定制,松耦合做得非常好。完全是實現了一套新的 xcode和ui庫啊。這就不是在解決一兩個問題了。既然有這么一個工具,筆者為什么不選擇更好的,例如Xamarin。
用適當的工具做適當的事情
做游戲的朋友估計就深有體會了。為了解決Canvas性能的問題,越來越多的人和應用廠商(尤其是瀏覽器廠商),提供一種解決方案就是希望將 Canvas API和系統底層的API打通。意味著你只需要編寫Canvas代碼,實際做渲染的時候使用的是系統底層的東西,整體上提高了性能。例如Ejecta http://impactjs.com/ejecta 這個東西。
對于開發人員來說用Javascript編寫游戲邏輯以及做各種控制都非常舒服,而且因為用的API相同,放到PC上(放開性能問題),同樣可以運 行。這就真的做到了跨平臺,但是又不缺乏效率。讓筆者感觸最深的就是@大城小胖在做混合應用(做游戲)時的做法,小胖的游戲架構。JS負責邏輯,引擎。 JS Binding綁定原生OpenGL,讓原生的來做復雜的渲染處理。HTML CSS可以處理UI(比如一些Button)。這就是典型的:讓工具去做其擅長的事情。
跨平臺是一個"幌子"
為什么這么說?筆者不是一直希望大家能夠跨平臺么?是的。但是要真的認清這個坎。從IE兼容,到目前多個瀏覽器的亂戰,到iOS以及Android 設備Web上的兼容,這不就是一個歷史的例子嘛。跨平臺不是不好,只是在一個時代里,你能夠達到怎樣的效果,真的是很難估量的。就好比你出國旅游,如果兩 國關系非常好,而且很多慣例法律一致,對你來說不會造成太多負擔。但是如果語言不一樣,生活習慣什么的都不同,你就很難適應。同樣是人,你很難在不同的環 境下生存。真正的跨平臺,就意味著大家求同。這絕對不是一兩天的事情,也非簡單的事情。
那為什么還要跨平臺。業務需求嘛。在這里必須就要遵守根據需求選擇工具,用適當的工具做適當的事情,根據實際情況來作開發。如果可以,筆者覺得很有 必要都了解一遍,這樣的話各種開發的思想就會影響到你,你就能夠分辨到什么是好什么是壞,做更好的選擇。例如筆者剛剛說到的過場動畫的例子。其實完全可以 使用筆者說的混合應用中,方案三,去解決這個問題。你無非就是希望用navigationController做一個漂亮的過場動畫嘛,在iOS中幾句代 碼就實現了。
再說一個例子吧,如果你正在做一個todo-list的應用,其實無非就是簡單存儲數據以及做一些相關界面渲染。在使用原生的控件的話,有大堆的代碼要寫,而且還要處理好內存問題。但是其實如果使用Web的方式實現,比如backbone.js。總體代碼可能100行左右。就把整個應用實現了,包括本地存儲。你要做的事情就是把整個界面搭建得漂亮些。可能就1個小時的工作。但是如果用原生開發,很難保證到一個小時內完成,因為調試編譯都需要時間吧?況且還有界面呢。
所以要認清跨平臺這個"幌子",并非所有的問題都用同一個方法處理。筆者們要融匯貫通嘛!
總結和筆者的感受
對于做Web App的坑,其實挺多的。這里無法一一表達。但是相信實踐過就會知道如何更好地繞過這些坑(例如筆者說的過場動畫的例子)。那么對于開發者來說要有堅強的 毅力,努力去實踐,滿足自己永遠不能滿足的好奇心,因為最終的經驗會給你帶來不一樣的感受,stay hungry。同時筆者們必須保持一顆學習的心,不斷地吸收有營養的思想,學習新的知識,不要太容易滿足,stay foolish。每一種語言都會有其中的思想,每一種工具都有自己解決問題的方法論。多嘗試就能夠給自己帶來更優秀的架構,更優秀的應用,提供給用戶更好 的體驗。當然,也會有更好的回報。