前言
《Cordova》框架大家應(yīng)該都不陌生逆瑞,它是用來構(gòu)建JSBridge的一個(gè)框架荠藤,除了Cordova以外,我們耳熟能詳?shù)倪€有《WebViewJavascriptBridge》框架也是用來解決這個(gè)問題获高。他們有個(gè)共同特點(diǎn)哈肖,就是不約而同的使用了URL攔截的方式構(gòu)建的bridge。然而URL攔截的方式并不安全念秧,但是這兩個(gè)框架使用起來是安全的淤井,那么以Cordova為例,它是怎么處理這個(gè)問題的出爹?還是說就沒有處理庄吼?關(guān)于這個(gè)問題,實(shí)際上Cordova框架內(nèi)部是做了處理的严就,本篇主要針對Cordova對于URL攔截方式進(jìn)行通信做了哪些優(yōu)化(曲線救國)
進(jìn)行分析总寻。
Cordova在iOS端是怎么通信的,我之前的文章《cordova-ios源碼解析》講的很清楚了梢为,在iOS端主要是圍繞著一個(gè)queue數(shù)組進(jìn)行的渐行,具體怎么進(jìn)行的本篇不做分析了轰坊,具體可以看前面提到的文章了解下。
本篇主要圍繞以下三點(diǎn)進(jìn)行分析為什么叫曲線救國:
- 1.js在給native發(fā)送假請求的時(shí)候做了什么
- 2.實(shí)際上js是怎樣將各種參數(shù)傳遞給native的
- 3.pokeNative優(yōu)化了什么
js在給native發(fā)送假請求的時(shí)候做了什么
真相都在cordova.js里面祟印,作為一個(gè)未入門的前端來說肴沫,對于cordova.js只能做一個(gè)簡要分析,主要是針對上面提到的三點(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插件的時(shí)候,代碼會走進(jìn)cordova.js里面的這個(gè)方法套鹅,push()函數(shù)實(shí)際上就是OC中的addObject:操作站蝠,commendQueue為cordova.js內(nèi)維護(hù)的全局?jǐn)?shù)組,commandQueue.push就是像commendQueue數(shù)組的最后面添加了一個(gè)對象卓鹿,也就是被轉(zhuǎn)為json格式的command對象菱魔。那么實(shí)際上在前端連續(xù)多次頻繁的調(diào)用插件的時(shí)候,插件的command信息都會被存儲在commandQueue中而不是把每一個(gè)通信都要去做一個(gè)假請求吟孙。通過if (!isInContextOfEvalJs && commandQueue.length == 1)這個(gè)判斷可以看到如果commandQueue中的調(diào)用次數(shù)不為一澜倦,也就是說可能有多個(gè)的時(shí)候,是不會執(zhí)行pokeNatie()的杰妓,pokeNative實(shí)際為發(fā)送假請求的具體實(shí)現(xiàn)藻治,后面會講到。從而也就避免了插件被頻繁調(diào)用所引起的通信丟失的情況稚失。
那么問題來了栋艳,插件的調(diào)用都被存儲在了commandQueue中,native端怎么獲取句各。這也是我們要討論的第二個(gè)問題。
實(shí)際上js是怎樣將各種參數(shù)傳遞給native的
那么這個(gè)問題我們需要分析下另一個(gè)函數(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ù)凿宾,這個(gè)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é)束的時(shí)候發(fā)生了第二次調(diào)用楞件,這個(gè)時(shí)候已經(jīng)執(zhí)行了commandQueue.length = 0;函數(shù)衫生,也就是說commandQueue已經(jīng)被清空了,那么就會執(zhí)行pokeNative()函數(shù)土浸,去發(fā)一個(gè)假請求給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)于添加了個(gè)定時(shí)器,也就是在50毫秒之后再執(zhí)行pokeNative()函數(shù)还最,這樣也就是做了一個(gè)50毫秒的間隔脱篙,從而避免了快速的兩次調(diào)用族操。這一塊pokeNative()函數(shù)內(nèi)部代碼注釋也有解釋,通信效率會降低7%,但是畢竟這種情況不多胶果,而且7%也在我們能接受的范圍內(nèi)。
總結(jié)
通過上面的三部分瓢捉,應(yīng)該很明顯的看到了為了構(gòu)建這個(gè)bridge并保證他的安全性逼裆,是下了一番苦工的」际幔基于URL攔截的方式粱甫,隨著JSCore和WKWebView的新特性的出現(xiàn)也正在被逐漸的取締,但是Cordova框架不單單給我們提供了一種通信方式作瞄,更多的是它的設(shè)計(jì)思想茶宵,以及對hybrid框架的交互設(shè)計(jì)理念,如果有一天需要我們自己來做hybrid框架宗挥,我認(rèn)為除了改變一下通信方式以外乌庶,對于Cordova框架的其他部分都是很值得我們?nèi)W(xué)習(xí)的。
本文屬于原創(chuàng)契耿,轉(zhuǎn)載注明出處瞒大。