移動(dòng)互聯(lián)網(wǎng)時(shí)代星立,混合編程對(duì)于前端同學(xué)來說是不可回避的課題爽茴,相信大部分同學(xué)都有曾做過并且使用上堪稱熟練,但是面試的時(shí)候绰垂,你的回答真的能用面試官感到滿意么室奏?
一、什么是混合編程劲装?
基于webview的h5具有跨平臺(tái)的特性胧沫,但是在體驗(yàn)上跟原生native組件比起來要遜色不少(至少目前是這樣),并且功能上也會(huì)有局限(例如消息推送占业,獲取設(shè)備網(wǎng)絡(luò)狀態(tài)等等)绒怨,另外,一些安全性要求較高的敏感數(shù)據(jù)也不宜放在網(wǎng)頁中谦疾。所以我們需要混合編程南蹂,結(jié)合使用兩者,發(fā)揮各自的優(yōu)勢(shì)念恍。
混合編程在形式上也有不同的偏重點(diǎn)六剥,目前市面上流行的ionic、phoneGap和h5+(hbuilder)峰伙,已經(jīng)將h5和native的橋接通信封裝得密不透風(fēng)疗疟,并且實(shí)現(xiàn)了足夠多的native接口讓使用者選擇調(diào)用(打包的時(shí)候還可以選擇打包),使用者更多的是使用h5技術(shù)去開發(fā)瞳氓,無需native的同事支持策彤,這種形式的側(cè)重點(diǎn)在h5上,native只需要搭建一個(gè)殼顿膨,適合沒有足夠人力的小團(tuán)隊(duì)锅锨;而技術(shù)叽赊、人力資源雄厚的公司恋沃,更愿意自己實(shí)現(xiàn)一套H5和native的通信鏈路,靈活的定制需要的native接口供少量的h5頁面使用必指,更多的功能交由原生團(tuán)隊(duì)進(jìn)行開發(fā)囊咏,這種形式的側(cè)重點(diǎn)就在native上了。
并不是說公司自身實(shí)現(xiàn)一套h5和native的互調(diào)機(jī)制側(cè)重點(diǎn)就一定在native上塔橡,這完全看公司的戰(zhàn)略梅割,有資源實(shí)現(xiàn)自己的一套東西,當(dāng)然能更加靈活
說了這么多葛家,不知道你有沒有發(fā)現(xiàn)户辞,混合編程的核心在于實(shí)現(xiàn)一套h5和native的通信鏈路(互調(diào)機(jī)制),如果你只是把自己定位為一個(gè)使用者癞谒,也許并不用關(guān)心這其中的實(shí)現(xiàn)細(xì)節(jié)底燎,但可以肯定的是刃榨,在面試的時(shí)候,你在這個(gè)話題上跟面試官扯不上幾句双仍,還是那句話枢希,跳出自己的思維舒適區(qū),深入原理
二朱沃、h5和native是如何互調(diào)的
native調(diào)用js有現(xiàn)成的方法苞轿,方式比較簡單:
/***********native 調(diào) js***************/
// Swift
webview.stringByEvaluatingJavaScriptFromString("Math.random()")
// OC
[webView stringByEvaluatingJavaScriptFromString:@"Math.random();"];
/*************android 調(diào) js************************/
// java調(diào)js
webView.loadUrl("javascript:Math.random();");
js調(diào)用native,android平臺(tái)和ios平臺(tái)的支持程度不太一樣逗物。
在android平臺(tái)中搬卒,有三種方式:
1)通過注解的方式向webview當(dāng)中注入java方法
// java代碼
class JSInterface {
@JavascriptInterface //注意這個(gè)代碼一定要加上
public String getUserData() {
return "UserData";
}
}
webView.addJavascriptInterface(new JSInterface(), "AndroidJS");
// js代碼
alert(AndroidJS.getUserData()) //UserDate
- 在android webview中重寫原生的promat、console.log或者alert(一般是重寫promat翎卓,因?yàn)檫@個(gè)方法用得少)
class MyChromeClient extends WebChromeClient {
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
// 這里就可以對(duì)js的prompt進(jìn)行處理秀睛,通過result返回結(jié)果
}
@Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
}
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
}
}
- 監(jiān)聽偽協(xié)議請(qǐng)求,在ios中只能采取這種方式莲祸,所以適合讓ios來現(xiàn)身說法
在ios平臺(tái)中蹂安,監(jiān)聽偽協(xié)議實(shí)現(xiàn)js對(duì)native的調(diào)用:
在UIWebView內(nèi)發(fā)起的所有網(wǎng)絡(luò)請(qǐng)求,都可以通過delegate函數(shù)在Native層得到通知锐帜,那么我們可以定義一個(gè)偽協(xié)議田盈,例如:jsBridge://
,然后在delegate中監(jiān)聽所有的網(wǎng)絡(luò)請(qǐng)求缴阎,一旦發(fā)現(xiàn)是jsBridge開頭的允瞧,將直接轉(zhuǎn)入響應(yīng)的調(diào)用邏輯中,這種曲線救國的方式蛮拔,在android平臺(tái)上也同樣適用述暂。
發(fā)起這樣的網(wǎng)絡(luò)請(qǐng)求,我們可以通過location.href建炫,也可以載入一個(gè)隱藏的iframe畦韭,通過location.href的方式請(qǐng)求有一個(gè)明顯的漏洞,當(dāng)多個(gè)請(qǐng)求連續(xù)發(fā)起的時(shí)候肛跌,在native層只能監(jiān)聽到最后一個(gè)請(qǐng)求艺配,其它請(qǐng)求調(diào)用都將被忽略,所以應(yīng)當(dāng)采取iframe的方式
適配層:
如你所見衍慎,混合編程中转唉,h5的調(diào)用代碼是統(tǒng)一的,那是因?yàn)樵谀憧床灰姡ɑ蛘卟幌肟匆姡┑牡胤轿壤Γ瑒e人進(jìn)行了android和ios平臺(tái)的適配赠法,并封裝了底層調(diào)用方式
這里就不貼代碼了,感興趣的同學(xué)可以當(dāng)做一個(gè)課外作業(yè)讓去實(shí)現(xiàn)這套適配代碼乔夯, 可以參考本章開頭處提供的參考資料砖织,有贊團(tuán)隊(duì)已經(jīng)在文末貼出了他們的代碼封裝原朝。而且,就在你天天提交代碼的倉庫中镶苞,說不定已經(jīng)有某個(gè)大牛同事已經(jīng)實(shí)現(xiàn)了一套成熟的封裝喳坠,你還沒來得及研讀
三、webview窗口頁面跳轉(zhuǎn)
雖說理解了h5跟native的通信機(jī)制之后茂蚓,接口的調(diào)用并不難理解壕鹉,但是由于對(duì)native的機(jī)制不太了解,經(jīng)常有同學(xué)分不清webview中的頁面跳轉(zhuǎn)
location.href
和調(diào)用native的方法重新創(chuàng)建一個(gè)webview窗口進(jìn)行的頁面切換有何區(qū)別聋涨,所以這個(gè)問題有必要來說明一下
我們知道晾浴,通過location.href
進(jìn)行的url跳轉(zhuǎn),當(dāng)前webview容器里面重新載入新的資源內(nèi)容牍白,但是在native應(yīng)用中脊凰,是通過navigator
的push
和pop
來管理窗口的,當(dāng)從列表頁跳轉(zhuǎn)到詳情頁的時(shí)候茂腥,新建一個(gè)詳情窗口狸涌,push
到navigator
中,新的詳情窗口將層疊在列表窗口中最岗,當(dāng)從詳情頁返回時(shí)帕胆,詳情窗口將會(huì)被從navigator
中pop
出來(并進(jìn)行銷毀),列表窗口重新成為當(dāng)前可見的活動(dòng)窗口
我們?cè)谶M(jìn)行混合編程的時(shí)候般渡,不希望在頁面跳轉(zhuǎn)的時(shí)候懒豹,沿用瀏覽器在當(dāng)前窗口重新載入資源內(nèi)容的體驗(yàn)方式(往往有一個(gè)空白頁的過程);而是采取調(diào)用native的新建窗口方法驯用,打開一個(gè)新的webview窗口脸秽,載入新的頁面鏈接內(nèi)容,這樣就可以擁有native的過渡動(dòng)畫體驗(yàn)
以上討論的是多頁面應(yīng)用蝴乔,但單頁spa應(yīng)用中记餐,通過location.history模擬的路由跳轉(zhuǎn),通過ajax載入的功能頁面淘这,也可以在一個(gè)webview窗口中模擬native的過渡動(dòng)畫
千萬別再混淆
location.href
和窗口跳轉(zhuǎn)了剥扣,前者只有一個(gè)webview巩剖,后者有多個(gè)webview窗口铝穷。
另外,單頁spa應(yīng)用也是可以模擬窗口跳轉(zhuǎn)的過渡動(dòng)畫的
總結(jié)
如果你只是會(huì)用佳魔,那么公司很樂于把你招進(jìn)來干點(diǎn)臟活累活曙聂;但是如果你理解深沉的實(shí)現(xiàn)機(jī)制,公司會(huì)希望將你招進(jìn)來搭建底層框架鞠鲜,甚至是作為一個(gè)前端架構(gòu)師指揮大家干活