重要的并不是我們提供的信息量有多大,而是我們能否給他們提供真正需要的信息。 -《瞬間之美》
本文涉及如下方面:
- 什么是Hybrid架構(gòu)(可略讀)
- Hybrid與Native的關(guān)系
- 設(shè)計(jì)上的考慮
- 一句話說(shuō)明白
- 技術(shù)實(shí)現(xiàn)
- Cordova
Hybrid架構(gòu)
Hybrid App:Hybrid App is a mobile application that is coded in both browser-supported language and computer language. They are available through application distribution platforms such as the Apple App Store, Google Play etc. Usually, they are downloaded from the platform to a target device, such as iPhone, Android phone or Windows Phone. The subscribers need to install to run them.

Hybrid App(混合模式移動(dòng)應(yīng)用)是指介于web-app、native-app這兩者之間的app,兼具“Native App良好用戶交互體驗(yàn)的優(yōu)勢(shì)”和“Web App跨平臺(tái)開(kāi)發(fā)的優(yōu)勢(shì)”。Hybrid開(kāi)發(fā)效率高、跨平臺(tái)、低層本的特點(diǎn),Hybrid從業(yè)務(wù)開(kāi)發(fā)上講,沒(méi)有版本問(wèn)題,對(duì)于BUG能及時(shí)修復(fù)。但Hybrid也是有缺點(diǎn)的,Hybrid體驗(yàn)比不上Native,同樣的功能在性能上存在巨大差距。Web界面上JS對(duì)HTML Node的操作需要消耗大量的CPU資源,手機(jī)CPU的性能還不能與PC相提并論,就算在智能手機(jī)之間,硬件水準(zhǔn)也參差不齊,一個(gè)可以在iPhone 6上流暢運(yùn)行的界面,跑到三星上很可能就卡住不動(dòng)了。所以我們經(jīng)??梢园l(fā)現(xiàn)一些富交互頁(yè)面上的操作無(wú)法達(dá)到令人滿意的流暢度,而流暢度也正是用戶評(píng)價(jià)一款A(yù)pp優(yōu)劣的最直觀因素。所以混合式編程比較適用于需要快速試錯(cuò)、快速占領(lǐng)市場(chǎng)的團(tuán)隊(duì),當(dāng)然,也不是絕對(duì)。

Hybrid App按網(wǎng)頁(yè)語(yǔ)言與程序語(yǔ)言的混合,通常分為三種類型:多View混合型,單View混合型,Web主體型。
多View混合型即Native View和Web View獨(dú)立展示,交替出現(xiàn)。這種應(yīng)用混合邏輯相對(duì)簡(jiǎn)單。即在需要的時(shí)候,將WebView當(dāng)成一個(gè)獨(dú)立的View(Activity)運(yùn)行起來(lái),在WebView內(nèi)完成相關(guān)的展示操作。這種移動(dòng)應(yīng)用主體通常是Native App,Web技術(shù)只是起到補(bǔ)充作用。開(kāi)發(fā)難度和Native App基本相當(dāng)。
單View混合型即在同一個(gè)View內(nèi),同時(shí)包括Native View和Web View?;ハ嘀g是覆蓋(層疊)的關(guān)系。這種Hybrid App的開(kāi)發(fā)成本較高,開(kāi)發(fā)難度較大,但是體驗(yàn)較好。如百度搜索為代表的單View混合型移動(dòng)應(yīng)用,既可以實(shí)現(xiàn)充分的靈活性,又能實(shí)現(xiàn)較好的用戶體驗(yàn)。
Web主體型即移動(dòng)應(yīng)用的主體是Web View,主要以網(wǎng)頁(yè)語(yǔ)言編寫(xiě),穿插Native功能的Hybrid App開(kāi)發(fā)類型。這種類型開(kāi)發(fā)的移動(dòng)應(yīng)用體驗(yàn)相對(duì)而言存在缺陷,但整體開(kāi)發(fā)難度大幅降低,并且基本可以實(shí)現(xiàn)跨平臺(tái)。Web主體型的移動(dòng)應(yīng)用用戶體驗(yàn)的好壞,主要取決于底層中間件的交互與跨平臺(tái)的能力。國(guó)外的appMobi、PhoneGap和國(guó)內(nèi)的WeX5、AppCan和Rexsee都屬于Web主體型移動(dòng)應(yīng)用中間件。其中Rexsee不支持跨平臺(tái)開(kāi)發(fā)。appMobi和PhoneGap除基礎(chǔ)的底層能力更多是通過(guò)插件(Plugins)擴(kuò)展的機(jī)制實(shí)現(xiàn)Hybrid。AppCan除了插件機(jī)制,還提供了大量的單View混合型的接口來(lái)完善和彌補(bǔ)Web主體型Hybrid App體驗(yàn)差的問(wèn)題,接近Native App的體驗(yàn)。而WeX5則在揉合PhoneGap和Bootstrap等主流技術(shù)的基礎(chǔ)上,對(duì)性能進(jìn)一步做了深度優(yōu)化,不但完全具備Native App對(duì)本地資源的調(diào)用能力,性能體驗(yàn)也不輸原生;WeX5所開(kāi)發(fā)出來(lái)的app具備完全的跨端運(yùn)行能力,可以無(wú)需任何修改直接運(yùn)行在各種前端環(huán)境上。
多主體共存型(靈活型)是一種新型的開(kāi)發(fā)模式,即支持Web主體型的應(yīng)用,又支持以Native主體的應(yīng)用,也支持兩者混合的開(kāi)發(fā)模式。比如kerkee框架 ,它具有跨平臺(tái)、用戶體驗(yàn)好、性能高、擴(kuò)展性好、靈活性強(qiáng)、易維護(hù)、規(guī)范化、具有Debug環(huán)境、徹底解決跨域問(wèn)題等特點(diǎn)。用戶體驗(yàn)與Native App媲美。功能方面,開(kāi)發(fā)者可隨意擴(kuò)展接口。
Hybrid與Native的關(guān)系
在Hybrid架構(gòu)設(shè)計(jì)中Native提供的是一宿主環(huán)境,實(shí)現(xiàn)合理的邏輯架構(gòu)需要考慮:交互設(shè)計(jì),資源訪問(wèn),Hybrid開(kāi)發(fā)調(diào)試,通訊設(shè)計(jì)、并發(fā)設(shè)計(jì)、異常處理、日志監(jiān)控以及安全模塊等問(wèn)題,前端要做的事情就是封裝Native提供的各種能力。
處理交互設(shè)計(jì)時(shí)需要考慮前端與Native配合處理,如H5與Native的互相跳轉(zhuǎn)邏輯;
資源訪問(wèn)機(jī)制需要做到既能以file的方式訪問(wèn)Native內(nèi)部資源,又能使用url的方式訪問(wèn)線上資源,處理好跳轉(zhuǎn)的邏輯;需要提供前端資源增量替換機(jī)制,以擺脫APP迭代發(fā)版問(wèn)題,避免用戶升級(jí)APP,這里將涉及到靜態(tài)資源在APP中的存放策略,更新策略的設(shè)計(jì),以及服務(wù)器端的支持等。當(dāng)然,有現(xiàn)成框架和解決方案的支持,但這些確實(shí)是不可忽略的問(wèn)題。
Hybrid的交互是通過(guò)Native調(diào)用前端頁(yè)面的JS方法,或者前端頁(yè)面通過(guò)JS調(diào)用Native提供的接口實(shí)現(xiàn)的,兩者交互的橋梁是Webview,iOS可以使用javascripbrige來(lái)實(shí)現(xiàn)(現(xiàn)成框架),在UIWebView的shouldStartLoadWithRequest方法里面捕獲url的變化,解析出需要的參數(shù),然后傳給一個(gè)統(tǒng)一的處理方法。app自身可以自定義url schema,并且把自定義的url注冊(cè)在調(diào)度中心。JS與Native通信可以創(chuàng)建這類URL被Native捕獲處理,即schema跳轉(zhuǎn)邏輯。APP安裝后會(huì)在手機(jī)上注冊(cè)一個(gè)schema,比如淘寶是taobao://,Native會(huì)有一個(gè)進(jìn)程監(jiān)控Webview發(fā)出的所有schema://請(qǐng)求,然后分發(fā)到“控制器”。hybridapi處理程序,Native控制器處理時(shí)會(huì)需要param提供的參數(shù)(encode過(guò)),根據(jù)實(shí)際需要處理業(yè)務(wù)邏輯問(wèn)題。
設(shè)計(jì)上的考慮
無(wú)論在Android還是iOS平臺(tái)上,都有各自的一套交互習(xí)慣,包括視覺(jué)風(fēng)格,界面切換,操作習(xí)慣等,與Web習(xí)慣完全不同。以iOS界面切換為例,系統(tǒng)風(fēng)格是新界面自右向左推入,后退時(shí)界面自左向右推出,而舊界面保持狀態(tài)。Web開(kāi)發(fā)的默認(rèn)習(xí)慣則是刷新頁(yè)面,無(wú)論新載入頁(yè)面或是后退,都會(huì)對(duì)頁(yè)面進(jìn)行刷新。因此使用Web模式開(kāi)發(fā)多界面功能就面臨這樣的交互習(xí)慣差異,造成體驗(yàn)上的損失。當(dāng)然Web方式也可模擬Native的交互方式,但這樣的模擬首先提高了開(kāi)發(fā)成本,有悖于最初的高效原則,從效果上看,也很難達(dá)到Native的流暢性。
一句話說(shuō)明白
如果用一句話來(lái)講明白這個(gè)問(wèn)題,就是Hybrid混合式編程可以在Native原生應(yīng)用的基礎(chǔ)上通過(guò)一些Hybrid框架實(shí)現(xiàn)本地和JS的交互處理。在不影響性能的情況下,實(shí)現(xiàn)應(yīng)用的動(dòng)態(tài)化。
技術(shù)實(shí)現(xiàn)原理
Hybrid技術(shù)將靜態(tài)資源存于Native,目錄結(jié)構(gòu)可以如下面劃分,當(dāng)然不是絕對(duì)的,基本要求是將對(duì)應(yīng)版本的Hybrid插件下載到本地,存放方便就好。

在正式的開(kāi)發(fā)中,還要考慮增量機(jī)制,因?yàn)椴煌陌姹緯?huì)對(duì)應(yīng)著不同的業(yè)務(wù)邏輯,真實(shí)的增量機(jī)制需要服務(wù)器端的配合,版本映射表是每次大版本APP發(fā)布時(shí)由服務(wù)器端生成。當(dāng)APP啟動(dòng)時(shí),APP會(huì)讀取版本信息,如果發(fā)現(xiàn)本地版本號(hào)比線上的小,便會(huì)下載對(duì)應(yīng)的zip文件,然后解壓之后并且替換整個(gè)原有的文件,本次增量結(jié)束,因?yàn)樗械陌姹疚募粫?huì)重復(fù),APP回滾時(shí)可用回到任意想去的版本,也可以對(duì)任意版本做BUG修復(fù)。
以上,我們得知,Hybrid和Native交互可以通過(guò)兩種方式:Url Schema和JavaScriptCore等地交互。H5與Native交互的橋梁為Webview,“聯(lián)系”的方式以u(píng)rl schema的方式,在用戶安裝app后,app可以自定義url schema,并且把自定義的url注冊(cè)在調(diào)度中心。
demoschema://hybridapi?callback=hybrid_1446276509894¶m=%7B%22data1%22%3A1%2C%22data2%22%3A2%7D
App調(diào)用H5:將一組API綁定在webView的window對(duì)象上,App通過(guò)iOS原生方法調(diào)用window對(duì)象中的js方法。
H5與App通信:App實(shí)現(xiàn)對(duì)Webview URL的觀察者模式,H5 通過(guò)改變URL的哈希值,通過(guò)解析哈希值的變化執(zhí)行相應(yīng)的操作。
另一種是JavaScriptCore,具體的可以看之前寫(xiě)的文章JavaScriptCore框架。
context[@"makeUIColor"] = ^(NSDictionary *rgbColor){
float red = [rgbColor[@"red"] floatValue];
float green = [rgbColor[@"green"] floatValue];
float blue = [rgbColor[@"blue"] floatValue];
return [UIColor colorWithRed:(red / 255.0)
green:(green / 255.0)
blue:(blue / 255.0)
alpha:1];
};
JSValue *color = [context evaluateScript:@"makeUIColor({red: 50, green: 150, blue: 250})"];
NSLog(@"color:%@",[color toObject]);
通過(guò)這種方式就可以在JavaScript中調(diào)用Objective-C。
當(dāng)然,除此之外也可以用JSBridge技術(shù)實(shí)現(xiàn)。
JS中:
button.onclick = function(e) {
e.preventDefault();
var data = 'Hello from JS button';
log('JS sending message', data);
window.external.test1(data, 'haha');
}
通過(guò)JSBridge,執(zhí)行本地類中的test1方法。此處只是一個(gè)引子,詳細(xì)的會(huì)在另一篇文章中單獨(dú)引出。
至于H5和Native的跳轉(zhuǎn)問(wèn)題,可以采用統(tǒng)跳協(xié)議來(lái)完成。這又是另外一個(gè)問(wèn)題了。當(dāng)然也可以在JS里定義跳轉(zhuǎn)地址,通過(guò)JS交互來(lái)處理。
Cordova
寫(xiě)了那么久,感覺(jué)現(xiàn)在才進(jìn)入主題。
Cordova提供了一組設(shè)備相關(guān)的API,通過(guò)這組API,移動(dòng)應(yīng)用能夠以JavaScript訪問(wèn)原生的設(shè)備功能,如攝像頭、麥克風(fēng)等。Cordova還提供了一組統(tǒng)一的JavaScript類庫(kù),以及為這些類庫(kù)所用的設(shè)備相關(guān)的原生后臺(tái)代碼。
測(cè)試使用可以到Github上下載源碼,也可以使用命令:
cordova create hello com.example.hello HelloWorld
cd hello
cordova platform add ios
這樣就創(chuàng)建了hello文件夾下的測(cè)試目錄(com.example.hello 為應(yīng)用程序的id名,與Xcode中類似,可以在 config.xml 中修改,如果不指定的話默認(rèn)為 io.cordova.hellocordova)。
目錄文件說(shuō)明:
config.xml :cordova的配置文件
hooks/ :存放自定義cordova命令的腳本文件。
platforms/ :各個(gè)平臺(tái)原生工程代碼,會(huì)在build時(shí)被覆蓋勿修改
plugins/ :插件目錄(主要是提供各個(gè)平臺(tái)的原生API)
www/ :用H5編寫(xiě)的源代碼目錄,build時(shí)會(huì)被放入各個(gè)平臺(tái)的assets\www目錄。
www/index.html :App入口html文件
在Xcode編譯運(yùn)行的話,使用的是 Staging 下面的html頁(yè)面。
命令安裝需要安裝cordova命令
brew install node //該命令執(zhí)行后,自動(dòng)裝好node和npm。
brew upgrade node //更新node(可不執(zhí)行)
為了解決校驗(yàn)碼不正確問(wèn)題。npm 使用國(guó)內(nèi)鏡像的方法 (三種辦法任意一種都能解決問(wèn)題,建議使用第三種,將配置寫(xiě)死,下次用的時(shí)候配置還在):
1.通過(guò)config命令
npm config set registry http://registry.cnpmjs.org npm info underscore (如果上面配置正確這個(gè)命令會(huì)有字符串response)
2.命令行指定
npm --registry http://registry.cnpmjs.org info underscore
3.編輯 ~/.npmrc 加入下面內(nèi)容
registry = http://registry.cnpmjs.org
之后:
sudo npm install -g cordova
打開(kāi)platform/ios里的HelloWorld.xcodeproj即可測(cè)試。
下面就是源碼分析了,因?yàn)橐獙?duì)照著源碼來(lái)說(shuō),大家可以到這里,參考詳細(xì)的源碼分析。通過(guò)這里,寫(xiě)一個(gè)混合式App應(yīng)該不是問(wèn)題了。
最后,祝大家看的愉快!