Hybrid App開發實戰

infoq發表於2014-03-22

  近年來隨著移動裝置型別的變多,作業系統的變多,使用者需求的增加,對於每個專案啟動前,大家都會考慮到的成本,團隊成員,技術成熟度,時間,專案需求等一堆的因素。因此,開發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應用有重合的地方。下面就說三種不同的解決方案。

  方案一:使用PhoneGapAppCan之類的中介軟體,以WebView作為使用者介面層,以Javascript作為基本邏輯,以及和中介軟體通訊,再由中介軟體訪問底層API的方式,進行應用開發。這種架構一般會非常依賴WebView層的效能。

  方案二:使用Adobe Air、RubyMotion、Appcelerator或者是Xamarin這種非官方語言的工具,打包成原生應用的方式開發。為什麼筆者會將它們定義為Hybrid App,主要是它們並沒有很單純地使用原生提供的語言進行開發,而是通過對開發者提供友好的開發工具,並折中地把這種開發語言轉換成原生語言,最終打包出整個應用,所以也屬於混合應用範疇。

  方案三:在開發原生應用的基礎上,嵌入WebView但是整體的架構使用原生應用提供,一般這樣的開發由Native開發人員和Web前端開發人員組成。Native開發人員會寫好基本的架構以及API讓Web開發人員開發介面以及大部分的渲染。保證到互動設計,以及開發都有一個比較折中的效果出來,優化得好也會有很棒的效果。(當年Facebook Three20就使用該方案)

  因此,Hybrid App有以下的特性:

  1. 開發時可能不採用或者大部分不採用原生語言,但是卻有所有原生應用的特性;
  2. 架構方案會和原生有出入,基本由工具而定;
  3. 具有跨平臺特性;
  4. 一般開發相對原生開發的方式要簡單。

  Native App

  Native App毫無疑問是最可靠的方案。但是學習成本,人才成本,開發效率以及照顧不同平臺的特性去考慮,都成為了開發人員心目中的一道坎。至於說這道坎是不可逾越的還是一道讓你提高的坎,筆者覺得完全取決於你自己。基於種種因素的考慮,估計很多人就會選擇折中的方案到了Hybrid App的開發行列當中,包括筆者自己也是這樣過來的。

  下面更多的內容都將圍繞Hybrid App開發展開討論。

  Hybrid App在開發當中的優點和缺點

  在Hybrid App的開發過程中,幾種不同的方案筆者都有經歷過。當然也經歷到了Native App的開發階段。在如此糾結複雜的過程中給了筆者不少的經驗,下面筆者也會就自身的經驗和大家分享這些方案當中的優缺點。對於初入行的朋友,筆者是從Web前端入行的,畢竟門檻較低,而且能夠快速地培養自己的信心以及對程式碼的感覺。深入後就開始接觸到移動開發這塊了。所以會先從Hybrid App的第一種方案說起吧。

  方案一(Web架構為重)

  優點:

  1. 全Web開發,一定程度上有利於Web前端技術人員快速地構建頁面樣式;
  2. 有利於在不同的平臺上面展示同一個互動層;
  3. 便於除錯,開發的時候可以通過瀏覽器的方式進行除錯,工具豐富。

  缺點:

  1. 雖然說你可以專注在介面以及互動開發上了,但是這頁會成為一個缺點,比如說要仿造一個iOS的預設設定介面,就需要大量的html以及css程式碼了,而且效果不一定和iPhone上面的介面一樣好;
  2. 正因為這是跨平臺的開發,所以還是這句話:相容是前端的痛。瞭解過在Android機器上面的Web開發就知道這個痛了。比如前些年在Android裝置上面寫圓角,border-radius:10px,在Android的裝置上面會出現毛邊。
  3. 便於除錯其實是在Web介面層的。但是實際上做Hybrid App開發的時候,你會遇到需求,進入手機的底層請求,做某些處理。比如說如果該應用有Push Notification服務的話,你就需要到底層,獲取Push Notification發生時的資料,以及做相應的互動處理。當然類似PhoneGap這類框架,已經有很好的外掛機制去幫助你解決類似的問題,當然還有Game Center之類的外掛,具體的話可以到Github去關注PhoneGap官方的賬戶,資源非常豐富;

  方案二(編譯轉換方式)

  優點:

  1. 利用自己熟悉的語言,進行應用開發,比如RubyMotion,就是使用Ruby語言去做iOS開發,開發起來的話,程式碼量是數量級地下降啊。
  2. 部分開發工具提供跨平臺的功能,讓你的應用能夠快速地釋出到不同的平臺上面。比如Mono社群的Xamarin,就是典型的例子了。使用C#語言,能夠把你的應用釋出到iOS,Android以及WinPhone市場上面;
  3. 開發出來的程式執行高效。大部分這種架構的應用,其實還是非常依賴底層的東西的,而且包括介面的東西,都是使用原生的API,效率就當然要比類似於PhoneGap這種架構要好了;

  缺點:

  嚴重依賴於其工具廠商提供的工具包,除錯的時候就要有全套的工具。當然一般來說這些廠商都會以收費的形式釋出他們的工具,相應的也有客服提供技術支援。遇到系統升級,第三方sdk升級,開發工具出現bug等,那麼就要等待工具廠商解決了。相當於把風險壓在對方身上了,自己卻要承擔責任。

  方案三(Native架構為重)

  優點:

  1. 這無疑是最穩定的Hybrid App開發方式了,互動層的效率上由Native的東西解決了,而且架構上基本就是在App內寫網頁,連App Store都是採用了該種方案;
  2. 開發時分工非常明確,底層的由iOS開發人員處理,上層的由Web前端開發人員處理;
  3. 有效的線上引數配置方式,以便於及時線上替換介面;

  缺點:

  1. 團隊至少需要兩個工程師,一個是Web的,一個是iOS的。當然如果開發人員會兩種技術也可獨立承擔;
  2. 還是執行效率,要權衡好多少介面採用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本身是一個重量級的框架,而且有自己的思想在裡頭,加上他本身也提供開發工具,在這裡就不適合討論了。對於開發者來說可以根據自己的需求選擇好工具)

  從工具上看:

  Angular.js

  用於雙向繫結,網路請求,檢視管理等工作。

  Require.js

  javascript模組化工具,在使用較多的互動物件,PhoneGap外掛的時候,你就會發現一個強大的模組化工具會在開發的時候提供極好的幫助。能夠幫助你把整體的程式碼,管理得井井有條。

  Jade Template Engine

  模板引擎。筆者個人比較推薦使用Jade,而且筆者本人也在部落格中多次寫到Jade在不同場景下使用的技巧的有關文章。主要是jade的語法太簡潔了,而且面向JS開發人員非常友好。如果你還沒有開始使用模板引擎,趕緊加入這個佇列吧,你已經落後了。

  Jquery Mobile

  如果你暫時還沒有一個設計師,但是又急於構造一個應用出來。jquery mobile就提供了多套不同風格的模板,供你使用,而且還含有不同的互動動畫等。而且也是跨平臺的。當然實際場景中,筆者覺得你會花很多時間在寫css上面,因為設計總是天馬行空的。當然你還有很多工具啦,例如sass,以及less.js等。

  PhoneGap.js或者Cordova.js

  做Phonegap開發必須使用的程式碼庫,用於和PhoneGap框架通訊。現在這個庫已經改名了,是Cordova。具體為什麼改名,得問Adobe咯。

  PhoneGap Plugins

  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>$('#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來說,其實都有了一些新的解決方案。為了解決問題其實最終思想都會被還原成以下幾個點上:

  1. 根據需求,選擇工具;
  2. 用適當的工具做適當的事情,有針對性地解決問題;
  3. 世界是平衡的,對於開發者來說,做的有用功越多,使用者體驗就越好,反之越差;
  4. 跨平臺是一個"幌子",什麼都做得到不代表什麼都做得好

  這也是筆者體驗最深的幾個點。而且你會發現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。每一種語言都會有其中的思想,每一種工具都有自己解決問題的方法論。多嘗試就能夠給自己帶來更優秀的架構,更優秀的應用,提供給使用者更好的體驗。當然,也會有更好的回報。

相關文章