先上圖一張:
前言
作為一種混合開(kāi)發(fā)的模式锣光,Hybrid APP底層依賴(lài)于Native提供的容器(UIWebview),上層使用Html&Css&JS做業(yè)務(wù)開(kāi)發(fā)铝耻,底層透明化誊爹、上層多多樣化蹬刷,這種場(chǎng)景非常有利于前端介入,H5的低成本频丘、高效率办成、跨平臺(tái)等特性非常適合業(yè)務(wù)快速迭代。
在設(shè)計(jì)Hybrid之初搂漠,首先是要考慮本地化包的版本管理,如下圖所示而克,正常APP啟動(dòng)會(huì)如下邏輯:
1.網(wǎng)頁(yè)資源提前加載到本地
在App啟動(dòng)時(shí)會(huì)請(qǐng)求一個(gè)配置文件员萍,包含版本號(hào)和包地址,舉例我們的文件如下:
{"errorMsg": "", "code": 0, "data": [{"zipDownloadUrl": "https://192.168.10.10/cdn/updatepkg/matrix_v2.2.606.zip", "version": "2.2.606", "packageName": "dist"}]}
這個(gè)配置文件每次啟動(dòng)會(huì)去下載拣度,并比對(duì)version跟本地的version是否一致碎绎,不一致則下載,一致則略過(guò)蜡娶。
部分對(duì)用戶(hù)體驗(yàn)要求較高的頁(yè)面使用原生開(kāi)發(fā)
我和我的團(tuán)隊(duì)在對(duì)用戶(hù)體驗(yàn)要求較高的頁(yè)面(比如首頁(yè))混卵,我們最好還是使用原生開(kāi)發(fā)。這也是Hybrid的真正意義所在吧窖张。但隨之也會(huì)產(chǎn)生一個(gè)新的問(wèn)題:原生頁(yè)面和H5的跳轉(zhuǎn)實(shí)現(xiàn)幕随。
1.http和https的處理
由于現(xiàn)在對(duì)網(wǎng)絡(luò)安全的重視(當(dāng)然蘋(píng)果也由于要求)赘淮,越來(lái)越多的App加入了https的支持。有一種非常普遍的問(wèn)題需要我們注意:跨域睦霎。舉個(gè)例子梢卸,我們的UIWebView加載的頁(yè)面是https://www.baidu.com,但baidu.com這個(gè)頁(yè)面中的某段js代碼會(huì)執(zhí)行頁(yè)面跳轉(zhuǎn)副女,而跳轉(zhuǎn)的協(xié)議是hybrid戴陡,也就是諸如hybrid://AViewController類(lèi)似的URL地址。App意識(shí)到這可能是一段不安全的代碼沟涨,因此不給于執(zhí)行恤批,之前就是遇到了這個(gè)問(wèn)題導(dǎo)致我們App不能響應(yīng)任何【H5->原生】跳轉(zhuǎn)。那如何“魚(yú)和熊掌兼得”呢裹赴,解決方案有兩種喜庞,各有利弊:
在調(diào)用UIWebView的loadRequest方法時(shí)诀浪,先去判斷本地有沒(méi)有資源,有的話加載本地資源延都,這樣其實(shí)就變相的走了http協(xié)議或者file協(xié)議雷猪,就不存在https跨域的問(wèn)題。但是對(duì)于UIWebView的js請(qǐng)求我們還是要進(jìn)行攔截晰房,走本地的https請(qǐng)求即可春宣。這個(gè)方案的優(yōu)點(diǎn)在于,由于html文件資源在本地所以加載資源速度比較快嫉你,用戶(hù)體驗(yàn)不錯(cuò);缺點(diǎn)就是我們必須通過(guò)URLProtocol重新定義所有的請(qǐng)求躏惋,這就需要我們?cè)赗equest請(qǐng)求的時(shí)候避免在httpbody或者h(yuǎn)ttpbodystream中設(shè)置參數(shù)幽污,轉(zhuǎn)而在header中設(shè)置。另外一種解決方案是簿姨,請(qǐng)求的時(shí)候?qū)RL地址直接從https替換成http距误,這樣的好處就是不需要定義所有的網(wǎng)絡(luò)請(qǐng)求,但由于html文件資源在遠(yuǎn)端所以加載資源速度比較慢扁位。
2.參數(shù)的傳遞
在原生和H5之間跳轉(zhuǎn)的時(shí)候准潭,參數(shù)傳遞都作為URL地址的一部分,例如AViewController中有屬性u(píng)sername和tel域仇,那我們?cè)谔D(zhuǎn)到AViewController是路由的寫(xiě)法應(yīng)該是類(lèi)似:
hybrid://AViewController?username=123&tel=1526181629x
這個(gè)很好理解刑然,但有種情況,如果接受的是個(gè)url暇务,并且url中也有參數(shù)怎么辦泼掠?舉例
hybrid://AViewController?url=http://www.baidu.com?username=123&tel=1526181629x
那請(qǐng)問(wèn),tel是AViewController的參數(shù)還是url自帶的參數(shù)垦细?這是個(gè)問(wèn)題择镇。解決方案其實(shí)也很簡(jiǎn)單:一層層encode,比如有一個(gè)url那就encode一次括改,如果url中還帶url那再encode一次腻豌。decode的時(shí)候也是一樣,一層一層decode嘱能。
使用原生SDK編寫(xiě)一套可供js調(diào)用的API
路由除了可以用于原生頁(yè)面和H5頁(yè)面跳轉(zhuǎn)吝梅,還可以用于調(diào)用本地的一些功能,下面是我們App預(yù)設(shè)的一些服務(wù):
// 打開(kāi)新頁(yè)面
#define SERVICE_OPENNEWPAGE @"hybrid://openNewPage?param="
// 更新導(dǎo)航欄
#define SERVICE_UPDATEUIHEADER @"hybrid://updateNavigationBar?param="
// 回退
#define SERVICE_PAGEBACK @"hybrid://back?param="
// 獲取定位
#define SERVICE_GETLOCATION @"hybrid://getLocation?param="
// 獲取網(wǎng)絡(luò)類(lèi)型焰檩,狀態(tài)
#define SERVICE_NETWORKTYPE @"hybrid://getNetWorkType?param="
因此只要在html中指明如上的鏈接即可憔涉。有時(shí)我們需要在調(diào)用服務(wù)成功后給個(gè)反饋,那就需要在native調(diào)H5的方法析苫,幸好JSContext幫我們實(shí)現(xiàn)了這個(gè)想法兜叨。
如圖穿扳,當(dāng)一個(gè)Request 發(fā)起后(這個(gè)Request 可以是UIWebView中的某個(gè)鏈接點(diǎn)擊產(chǎn)生,也可以UIWebView的Ajax請(qǐng)求)国旷,通過(guò)Watermelon 進(jìn)行攔截矛物,如果是正常的HTTP請(qǐng)求則放過(guò),如果是我們定義的scheme則單獨(dú)做處理跪但。OHHttpStub是基于NSURLProtocol實(shí)現(xiàn)的URL Request 攔截系統(tǒng)履羞。方法
+(id)stubRequestsPassingTest:(OHHTTPStubsTestBlock)testBlock withStubResponse:(OHHTTPStubsResponseBlock)responseBlock;
而參數(shù)testBlock就是需要攔截的Request請(qǐng)求,攔截后我們可以自己實(shí)現(xiàn)自己的Request請(qǐng)求屡久,并返回?cái)?shù)據(jù)給responseBlock忆首。至于這里為什么使用OHHttpStub不使用原生的NSURLProtocol是為了避免與其他的使用NSURLProtocol 的三方庫(kù)(比如Bulgly)沖突。當(dāng)攔截成功后被环,我們?cè)侔呀Y(jié)果分發(fā)給WebView糙及。
總結(jié):事實(shí)上,Hybrid的核心有3個(gè)
1.離線資源包的管理筛欢。
2.webview對(duì)所有請(qǐng)求的攔截(Native核心功能)
3.交互協(xié)議的制定
一些問(wèn)題遇到的問(wèn)題:
事實(shí)上浸锨,在iOS開(kāi)發(fā)當(dāng)中,你會(huì)發(fā)現(xiàn)如果你采用了WKwebview會(huì)后會(huì)出現(xiàn)各種各樣的問(wèn)題版姑,比如說(shuō)跨域的問(wèn)題(可以多了解http協(xié)議本身柱搜,這個(gè)問(wèn)題已經(jīng)解決),比如說(shuō)某些彈框失敗的問(wèn)題包括cookie的問(wèn)題剥险,當(dāng)然這都是wk范疇的問(wèn)題聪蘸,有些在我后來(lái)的實(shí)踐當(dāng)中已經(jīng)解決了,有些還沒(méi)有表制,我后面有時(shí)間的話會(huì)把這些解決方案逐一分享給大家宇姚。當(dāng)然目前針對(duì)上述問(wèn)題我發(fā)現(xiàn)包括當(dāng)前開(kāi)源的無(wú)論是豆瓣還是騰訊團(tuán)隊(duì)的iOS版Hybrid框架都沒(méi)有解決這個(gè)問(wèn)題,統(tǒng)一采用的UIwebview控件夫凸,我個(gè)人以為使用WKwebview一定是大勢(shì)所趨浑劳,所有問(wèn)題一定會(huì)要解決畢竟技術(shù)是需要一步步來(lái)推動(dòng)的。最后來(lái)讓大家看一下我們之前團(tuán)隊(duì)做的這個(gè)開(kāi)源的Hybrid框架源碼夭拌,代碼寫(xiě)的很一般魔熏,希望大家不要噴,它只是給了一個(gè)設(shè)計(jì)思路以供大家參考而已: