要知道的事
ios的webview有2個(gè)類(lèi),一個(gè)叫UIWebView,另一個(gè)是WKWebView。WKWebView是取代UIWebView出現(xiàn)的,在app開(kāi)發(fā)者若不需要兼容ios8之前版本,都應(yīng)該使用WKWebVIew。
WKWebView 是蘋(píng)果在 iOS 8 中引入的新組件,目的是給出一個(gè)新的高性能的 Web View 解決方案,擺脫過(guò)去 UIWebView 的老舊笨重特別是內(nèi)存占用量巨大的問(wèn)題,它使用Nitro JavaScript引擎,這意味著所有第三方瀏覽器運(yùn)行JavaScript將會(huì)跟safari一樣快.
UIWebView使用
app調(diào)用js:?webView.stringByEvaluatingJavaScriptFromString()?
js調(diào)用app:
UIWebView沒(méi)有辦法直接使用js調(diào)用app,但是可以通過(guò)攔截request的方式間接實(shí)現(xiàn)js調(diào)用app方法。
在網(wǎng)頁(yè)中加載一個(gè) Custom URL Scheme 的鏈接(直接設(shè)置 window.location 或者新建一個(gè) iframe 去加載這個(gè) URL),原生中攔截?UIWebView?的代理方法 - webView:shouldStartLoadWithRequest:navigationType:,然后根據(jù)約定好的協(xié)議做相應(yīng)的處理。
app調(diào)js可以有返回值,但是js調(diào)app是通過(guò)間接的攔截request方式實(shí)現(xiàn),它根本就不算方法調(diào)用,所以應(yīng)該是不存在可以直接產(chǎn)生返回值的
WKWebView使用
app調(diào)用js:WKWebView調(diào)用js方法和UIWebView類(lèi)似,一個(gè)是evaluateJavaScript,一個(gè)是stringByEvaluatingJavaScriptFromString。獲取返回值的方式不同,WKWebView用的是回叫函數(shù)block獲取返回值
js調(diào)用app:
1. 間接的攔截request方式實(shí)現(xiàn),攔截WKWebView代理方法:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
2.?引用??蘋(píng)果在 WKWebView 中的 js runtime 里事先注入了一個(gè) window.webkit.messageHandlers.OOXX.postMessage() 方法,我們可以使用這個(gè)方法直接向 Native 層傳值,異常方便。 ?
WebViewJavascriptBridge源碼解讀
WebViewJavascriptBridgeBase:① 用來(lái)進(jìn)行 bridge 初始化和消息處理的核心類(lèi);② 這個(gè)類(lèi)是在支持?WKWebView?后從??WebViewJavascriptBridge?中獨(dú)立出來(lái)的邏輯,專(zhuān)門(mén)用來(lái)處理 bridge 相關(guān)的邏輯,不再與具體的 Web View 相關(guān)聯(lián)了
WebViewJavascriptBridge:① 橋接的入口,針對(duì)不同類(lèi)型的 Web View (UIWebView、WKWebView、WebView)進(jìn)行分發(fā);② 針對(duì)?UIWebView?和?WebView?做的一層封裝,主要用來(lái)執(zhí)行 JS 代碼,以及實(shí)現(xiàn)?UIWebView?和?WebView的代理方法,并通過(guò)攔截 URL 來(lái)通知?WebViewJavascriptBridgeBase?做相應(yīng)操作
WKWebViewJavascriptBridge:針對(duì)?WKWebView?做的一層封裝,主要用來(lái)執(zhí)行 JS 代碼,以及實(shí)現(xiàn)?WKWebView?的代理方法,并通過(guò)攔截 URL 來(lái)通知?WebViewJavascriptBridgeBase?做相應(yīng)操作
WebViewJavascriptBridge_JS:JS 端負(fù)責(zé)“收發(fā)消息”的代碼
主要流程
一、初始化

(1)?Objective-C 中的初始化
初始化 UIWebView;初始化 WebViewJavascriptBridge,設(shè)置 web view 代理;初始化 WebViewJavascriptBridgeBase,初始化相關(guān)的屬性
(2)?注冊(cè) handler 供 JS 調(diào)用——把注冊(cè)過(guò)的 handler 保存起來(lái) :
[self.bridge registerHandler:@"share" handler:^(id data, WVJBResponseCallback responseCallback) { }];
(3)?Objective-C 中通過(guò)調(diào)用?UIWebView?的?loadRequest:?方法加載 網(wǎng)頁(yè)URL
(4)?網(wǎng)頁(yè)一加載就會(huì)執(zhí)行 web 頁(yè)中的 bridge 初始化代碼,也就是調(diào)用上面提到的?setupWebViewJavascriptBridge(bridge)函數(shù):
1》保存要執(zhí)行的自定義初始化函數(shù),比如注冊(cè) JS 中的 handler;
2》通過(guò)添加一個(gè) iframe 加載初始化鏈接?https://__bridge_loaded__
(5)?原生 WebViewJavascriptBridge 類(lèi)中代理方法會(huì)攔截?https://__bridge_loaded__?的加載,在 web view 中執(zhí)行本地 WebViewJavascriptBridge_JS.m 文件中的代碼,初始化?window.WebViewJavascriptBridge對(duì)象:
1》在 JS 中創(chuàng)建一個(gè)?WebViewJavascriptBridge?對(duì)象,并設(shè)置成?window?的一個(gè)屬性;
2》定義幾個(gè)用于管理消息的全局變量;
3〉給?WebViewJavascriptBridge?對(duì)象定義幾個(gè)處理消息的方法和函數(shù);
4》執(zhí)行原生端?startupMessageQueue?中保存的消息,也就是本地 JS 文件還未加載時(shí)就發(fā)送了的消息
(6)?初始化完畢
二、JS調(diào)用OC

WebViewJavascriptBridgeBase中JS調(diào)用OC方法關(guān)鍵代碼:

三、OC調(diào)用JS

WebViewJavascriptBridge_JS中OC調(diào)用JS方法關(guān)鍵代碼:

參考鏈接: