前言
《Cordova》框架大家應(yīng)該都不陌生,它是用來構(gòu)建JSBridge的一個框架,除了Cordova以外,我們耳熟能詳?shù)倪€有《WebViewJavascriptBridge》框架也是用來解決這個問題。他們有個共同特點(diǎn),就是不約而同的使用了URL攔截的方式構(gòu)建的bridge。然而URL攔截的方式并不安全,但是這兩個框架使用起來是安全的,那么以Cordova為例,它是怎么處理這個問題的?還是說就沒有處理?關(guān)于這個問題,實(shí)際上Cordova框架內(nèi)部是做了處理的,本篇主要針對Cordova對于URL攔截方式進(jìn)行通信做了哪些優(yōu)化(曲線救國)進(jìn)行分析。
Cordova在iOS端是怎么通信的,我之前的文章《cordova-ios源碼解析》講的很清楚了,在iOS端主要是圍繞著一個queue數(shù)組進(jìn)行的,具體怎么進(jìn)行的本篇不做分析了,具體可以看前面提到的文章了解下。
本篇主要圍繞以下三點(diǎn)進(jìn)行分析為什么叫曲線救國:
- 1.js在給native發(fā)送假請求的時候做了什么
- 2.實(shí)際上js是怎樣將各種參數(shù)傳遞給native的
- 3.pokeNative優(yōu)化了什么
js在給native發(fā)送假請求的時候做了什么
真相都在cordova.js里面,作為一個未入門的前端來說,對于cordova.js只能做一個簡要分析,主要是針對上面提到的三點(diǎn),看代碼。
function iOSExec() {
//刪除了一些不在本篇討論范圍內(nèi)的代碼
var command = [callbackId, service, action, actionArgs];
commandQueue.push(JSON.stringify(command));
if (!isInContextOfEvalJs && commandQueue.length == 1) {
pokeNative();
}
}
在js端調(diào)用cordova插件的時候,代碼會走進(jìn)cordova.js里面的這個方法,push()函數(shù)實(shí)際上就是OC中的addObject:操作,commendQueue為cordova.js內(nèi)維護(hù)的全局?jǐn)?shù)組,commandQueue.push就是像commendQueue數(shù)組的最后面添加了一個對象,也就是被轉(zhuǎn)為json格式的command對象。那么實(shí)際上在前端連續(xù)多次頻繁的調(diào)用插件的時候,插件的command信息都會被存儲在commandQueue中而不是把每一個通信都要去做一個假請求。通過if (!isInContextOfEvalJs && commandQueue.length == 1)這個判斷可以看到如果commandQueue中的調(diào)用次數(shù)不為一,也就是說可能有多個的時候,是不會執(zhí)行pokeNatie()的,pokeNative實(shí)際為發(fā)送假請求的具體實(shí)現(xiàn),后面會講到。從而也就避免了插件被頻繁調(diào)用所引起的通信丟失的情況。
那么問題來了,插件的調(diào)用都被存儲在了commandQueue中,native端怎么獲取。這也是我們要討論的第二個問題。
實(shí)際上js是怎樣將各種參數(shù)傳遞給native的
那么這個問題我們需要分析下另一個函數(shù),看代碼:
iOSExec.nativeFetchMessages = function() {
if (failSafeTimerId) {
clearTimeout(failSafeTimerId);
failSafeTimerId = 0;
}
if (!commandQueue.length) {
return '';
}
var json = '[' + commandQueue.join(',') + ']';
commandQueue.length = 0;
return json;
};
這是native端收到cordova.js的pokeNative發(fā)出的假請求會調(diào)用的函數(shù),這個json對象存儲的正是commandQueue中的插件調(diào)用信息,那么不難看出,實(shí)際上Cordova內(nèi)通信參數(shù)并不是在URL上傳遞,而是JS端告訴Native過來取,大概意思就是我這有好多都取過去吧。實(shí)際上只pokeNative()了一次,那么插件調(diào)用就都被native端取走了,這樣也就避免了快速的頻繁的發(fā)假請求而導(dǎo)致通信丟失問題。
pokeNative優(yōu)化了什么
實(shí)際上經(jīng)過了上面兩步,還是不夠安全的,因?yàn)橛幸环N情況,那就是當(dāng)前端的第一次調(diào)用剛好結(jié)束的時候發(fā)生了第二次調(diào)用,這個時候已經(jīng)執(zhí)行了commandQueue.length = 0;函數(shù),也就是說commandQueue已經(jīng)被清空了,那么就會執(zhí)行pokeNative()函數(shù),去發(fā)一個假請求給native端,這樣就導(dǎo)致了連續(xù)的兩次假請求發(fā)生。實(shí)際上這一塊cordova.js也是做了處理的,詳情在pokeNative()里面,看代碼:
function pokeNative() {
//代碼刪減部分
failSafeTimerId = setTimeout(function() {
if (commandQueue.length) {
// CB-10106 - flush the queue on bridge change
if (!handleBridgeChange()) {
pokeNative();
}
}
}, 50);
}
setTimeout()函數(shù)在javaScript里面相當(dāng)于添加了個定時器,也就是在50毫秒之后再執(zhí)行pokeNative()函數(shù),這樣也就是做了一個50毫秒的間隔,從而避免了快速的兩次調(diào)用。這一塊pokeNative()函數(shù)內(nèi)部代碼注釋也有解釋,通信效率會降低7%,但是畢竟這種情況不多,而且7%也在我們能接受的范圍內(nèi)。
總結(jié)
通過上面的三部分,應(yīng)該很明顯的看到了為了構(gòu)建這個bridge并保證他的安全性,是下了一番苦工的?;赨RL攔截的方式,隨著JSCore和WKWebView的新特性的出現(xiàn)也正在被逐漸的取締,但是Cordova框架不單單給我們提供了一種通信方式,更多的是它的設(shè)計(jì)思想,以及對hybrid框架的交互設(shè)計(jì)理念,如果有一天需要我們自己來做hybrid框架,我認(rèn)為除了改變一下通信方式以外,對于Cordova框架的其他部分都是很值得我們?nèi)W(xué)習(xí)的。
本文屬于原創(chuàng),轉(zhuǎn)載注明出處。