WebViewJavascriptBridge 簡單使用及原理分析

概述

? 從兩個方面來講:

? js不能直接調(diào)用oc的方法

?oc可以通過

?- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ ? ? ?__nullable)(__nullable id, NSError * __nullable error))completionHandler;

? 這個方法調(diào)用js 的代碼

我們從 github上面的demo https://github.com/marcuswestin/WebViewJavascriptBridge

來分析一下這個庫是如何實現(xiàn)js交互的绪钥。

詳解

一. ?js調(diào)用native方法

在概述中說過灿里,js是不能直接調(diào)用native的method所以,需要借助- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType程腹,這個方法大家不陌生匣吊,每次在重新定向URL的時候,這個方法就會被觸發(fā),通常情況色鸳,我們會在這里做一些攔截完成js和本地的間接交互什么的社痛。那么WebViewJavascriptBridge也不另外,也是這么做命雀。


順序分析代碼 : ? 首先看 ExampleApp.html ?文件中所實現(xiàn)的按鈕事件 兩個按鈕時間分別是bridge.send() 方法 ? 和 ? bridge.callHandle()方法 ? ? ? 在 WebViewJavascriptBridge.js 這個文件中可以看到

callHandler 和 send 方法

最終都是調(diào)用了doSend 方法 ? 分析下這個方法蒜哀,變量callbackId是個字符串,responseCallBacks[] 一看就知道是個字典 吏砂,這個字典把回調(diào)的方法responseCallback給保存起來撵儿,這Key(也就是callbackId)是唯一的,通過計數(shù)和時間應(yīng)該知道這個字符串應(yīng)該是唯一的狐血,message也是一個字典淀歇,這是給message添加了一個新的key-value。干嘛呢氛雪?我也不知道,我們來看看sendMessageQueue是什么耸成,大家一看push就知道應(yīng)該是個數(shù)組报亩。他吧一個字典放到一個消息隊列中(數(shù)組隊列),讓后產(chǎn)生一個src(url scheme)井氢。

不了解js的同學(xué)(例如我) 只需要知道 改變了iframe的src ?之后 ?uiwebview 會執(zhí)行下邊的方法

UIWebView的回調(diào)方法

所以我們就可以關(guān)注WebViewJavascriptBridge.m文件中的這個方法中做了些什么事

WebViewJavascriptBridge.m

這里經(jīng)過判斷之后會走到 223 行代碼 ?后邊return NO; 的原因想必大家也清楚了 ?是因為我們要執(zhí)行的是 oc的代碼了 ?所以會阻斷 js 代碼弦追。 ?這里執(zhí)行了一段js代碼 ?點進去

-(void)webViewJavascriptFetchQueyCommand 方法

執(zhí)行的js語句 WebViewJavascriptBridge._fetchQueue();

然后去WebViewJavascriptBridge.js中找到這個方法

WebViewJavascriptBridge.js

返回一個字典 ?就是我們在最初 要發(fā)送消息時存儲起來的字典 現(xiàn)在我們把要傳遞的數(shù)據(jù)拿出來 ? ? 那里面有哪些東西,我么來看看

handlerName:handlerName,

data:data,

callbackId:callbackId

拿到字典繼續(xù)向下執(zhí)行 ? 下邊這個方法

WebViewJavascriptBridgeBase.m

總體來看 就是對我們拿出來的數(shù)據(jù)進行一系列的類型驗證 (_log方法是打印數(shù)據(jù)信息的 可以忽略) ? 回顧前面的代碼 我們就應(yīng)該知道這里的responseId為空 ?所以執(zhí)行 ?86 -- 114 ?行的代碼

WebViewJavascriptBridgeBase.m

這部分是重點花竞,到底他是怎么要調(diào)用本地function的劲件,callbackId大家熟悉吧,判斷是否為空约急,不為空給他指定一個block零远,這個不說了,block指定厌蔽,此時不調(diào)用(手動調(diào)用才會執(zhí)行)牵辣,這個剛才說了用來處理native的function處理的result用于把處理后的值返回給js的,接著往下去奴饮,看到handler這個方法會從message找到handlerName纬向,這里我們看一下多了一個_messageHandlers字典,從這個字典獲取一個block(WVJBHandler是一個block)戴卜,直接執(zhí)行了逾条。那我們看看_messageHandlers是怎么被添加block的:

WebViewJavascriptBridge.m

那又是誰調(diào)用了這個方法:(在文件 ExampleAppViewController.m的viewdidload中),這里有方法testObjecCallback

ExampleUIWebViewController

剛才都是倒推的投剥,如果我們反過來师脂,首先肯定是viewdidload初始化,初始化之后會把這個block加入到_messageHandlers的數(shù)組中,之后因為js調(diào)用動態(tài)讀取這個block調(diào)用危彩,在調(diào)用之前攒磨,我們又把一個block付值給回掉處理的responseCallback的block,這個block在handler被調(diào)用時而被調(diào)用汤徽,有點繞娩缰。 略微有點繞。 ? 現(xiàn)在我們看一下 這個responseCallback ?怎么賦值的 ?

WebViewJavascriptBridgeBase.m

順著方法往下看 ?執(zhí)行到下邊這個方法

WebViewJavascriptBridgeBase.m

對傳進來的數(shù)據(jù) ? @{ @"responseId":callbackId, @"responseData":responseData };處理之后 再執(zhí)行 js語句 ? @"WebViewJavascriptBridge._handleMessageFromObjC('%@');"

看看js的方法 ?

WebViewJavascriptBridge.js

這個里面應(yīng)該很容易看到 ?代碼進入待66 行 ? 因為傳進來的數(shù)據(jù)中responseId 顯然不為空 ?而這里面的responseCallback 方法 ?和responseCallbacks 數(shù)組又是何處來的呢谒府? ?大家可能已經(jīng)忘了 拼坎,回到文首 ?doSend 方法(返回去看看) ?除了包裝一個message 字典存起來 還有 ?把 responseCallback 存在了 responseCallBacks[] ? 中, 所以等到原生的方法執(zhí)行完之后 ?再調(diào)用這個方法 (在最初 button點擊事件里面已經(jīng)實現(xiàn)了 ) 實現(xiàn)相互通信完疫。

這里稍微總結(jié)下 便于理解

1.首先是在UIWebViewController 里面實例化 一個bridge ? ? 通過bridge 注冊一個 handler ?然后保存在messageHandlers中 ?

2. 點擊網(wǎng)頁的button的時候 ?把信息保存起來生成一個message 字典 三個key(handlerName 泰鸡, data,callbackId(后邊通過這個來找到之前的responseCallback方法)) ? 并且把 其中的responseCallback 保存起來 ? ?并且改變iframe.src ?

3. 這個時候 webView 執(zhí)行代理方法 ? ?在這里面取出 2步 存起來的信息 ?然后給1步的handler中的responseCallback賦值 ? 并且執(zhí)行 1步注冊的方法 ? ?

? 所以結(jié)果就是 執(zhí)行oc的回調(diào)方法 ?然后在oc的回調(diào)方法里面再去執(zhí)行 ?剛剛被賦值的 responseCallback方法(這個方法的響應(yīng)結(jié)果體現(xiàn)在web中) ? 至于這個responseCallback被賦值的過程就是通過第二步的callbackId 找到相應(yīng)的方法賦過去壳鹤。

二. native調(diào)用js

過程不是直接調(diào)用js盛龄,也是通過js調(diào)用Native過程一樣的處理方式》际模可以看到 最后調(diào)用的就是WebViewJavascriptBridgeBase ?中的這個方法 ? - (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName; ?

WebViewJavascriptBridgeBase.m

把 data ?handlerName ?callbackId ?判空并且存在message 并且把resopnseCallback 方法存起來 ? 然后 后邊同上文一樣 ? 最后執(zhí)行到 JS的這個方法

WebViewJavascriptBridge.js

不過這次執(zhí)行的是 71 - 90 行的代碼 ? ? 兩個判斷 ?

1 ?如果有callbakId存在 ?那么就給實現(xiàn) responseCallback ?這個方法(并不調(diào)用) ?

2 ?如果message.handlerName存在 ? 那么就取出messageHandlers中 message.handlerName 對應(yīng)的方法 ?這個方法一般是在js代碼中注冊過的

ExampleApp.html

這里最后 如果既有handler 又有callback ? ?就會把第一步實現(xiàn)的方法賦值給handler的 responseCallback ? ? ?然后在執(zhí)行到handler的最后一句 ?responseCallback(responseData) ?時候 再執(zhí)行 ?執(zhí)行這個回調(diào)余舶。

三. ?使用 ?

一般來說 都不會這么復(fù)雜的傳輸數(shù)據(jù) ?一般只需要單向的去傳遞數(shù)據(jù) ?不會有很多的callback 來回的調(diào)用。至于oc 的初始化 和 html的初始化 對照github上面的demo進行就可以了 锹淌。 ? ? ?

大多數(shù)情況下 都是 js在調(diào)用原生的 方法 ? 所以 一般都是我們在 我們的方法中作如下的工作

[_eBridge registerHandler:@"backToHomeHandle" handler:^(id data, ? ? ? ? ? ? ? ?WVJBResponseCallback responseCallback) {

? ? ? ? [weakSelf.navigationController popToRootViewControllerAnimated:YES];

}];

這里 ?@"backToHomeHandle" 就是約定的方法名 ?block回調(diào)中就是當js代碼調(diào)用該方法時 我們的原生界面要做出的響應(yīng)匿值。然后 和 前端的同學(xué) 約定好 數(shù)據(jù)結(jié)構(gòu) ? 讓他們在適當?shù)臅r候 調(diào)用我們的方法即可。工作中用到了 學(xué)習(xí)了下 供大家參考赂摆⌒荆可以領(lǐng)略一下這個庫里面對block回調(diào) 以及 js函數(shù)式編程的運用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末烟号,一起剝皮案震驚了整個濱河市绊谭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌汪拥,老刑警劉巖龙誊,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異喷楣,居然都是意外死亡趟大,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門铣焊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逊朽,“玉大人,你說我怎么就攤上這事曲伊∵椿洌” “怎么了追他?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長岛蚤。 經(jīng)常有香客問我邑狸,道長,這世上最難降的妖魔是什么涤妒? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任单雾,我火速辦了婚禮,結(jié)果婚禮上她紫,老公的妹妹穿的比我還像新娘硅堆。我一直安慰自己,他們只是感情好贿讹,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布渐逃。 她就那樣靜靜地躺著,像睡著了一般民褂。 火紅的嫁衣襯著肌膚如雪茄菊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天赊堪,我揣著相機與錄音面殖,去河邊找鬼。 笑死雹食,一個胖子當著我的面吹牛畜普,可吹牛的內(nèi)容都是我干的期丰。 我是一名探鬼主播群叶,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼钝荡!你這毒婦竟也來了街立?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤埠通,失蹤者是張志新(化名)和其女友劉穎赎离,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體端辱,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡梁剔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了舞蔽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荣病。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖渗柿,靈堂內(nèi)的尸體忽然破棺而出个盆,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布颊亮,位于F島的核電站柴梆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏终惑。R本人自食惡果不足惜绍在,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望狠鸳。 院中可真熱鬧揣苏,春花似錦、人聲如沸件舵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铅祸。三九已至坑质,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間临梗,已是汗流浹背涡扼。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留盟庞,地道東北人吃沪。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像什猖,于是被迫代替她去往敵國和親票彪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容