在9012的最後一篇寫到了在rn中安卓的webview的通訊原理,而做爲0202年的第一篇,繼續討論上年rn中webview通訊剩下的部分。react
對於webview,瞭解過的人都知道在ios端會存在兩種類型的webview(UIWebview和WKWebview),而他們之間的區別主要以下:ios
在ios中,應用層會設置rn中webview的某個屬性,而weview會經過webview.iso.js進行處理,若是該屬性是原生底層直接擁有的,那麼就直接往下傳遞,若是該屬性不是底層所擁有的,則須要經過在webview.ios.js層處理成底層組件所擁有的屬性,而後再往下傳遞下去,由RCTWebview或者RCTWKWebview進行處理。web
例如:
source屬性:webview層設置了source -----> webview.ios.js往下傳遞 ------> RCTWebviewManager.m能接受到該屬性,而後繼續往下傳遞 -----> RCTWebview進行處理該屬性;segmentfault
onLoadStart屬性:webview層設置了onLoadStart ----> webview.ios.js對該屬性進行處理,包裝成_onLoadingStart,而後傳給RCTWebviewManager ----> RCTWebviewManager.m能接受到該屬性,而後繼續往下傳遞 -----> RCTWebview進行處理該屬性;瀏覽器
語法形式:緩存
- (void)injectJavaScript:(NSString *)script { [_webView stringByEvaluatingJavaScriptFromString:script]; }
當js層傳遞js字符串給ios的時候,ios就會用stringEvaluatingJavascriptFromString這個方法執行這個script。app
對於uiwebview來講,通常有三個生命週期他們分別是:post
在webview之中通訊最爲重要,經過postMessage向rn層傳遞信息,rn層只須要message就行,相反也行。該實現的邏輯是在資源加載完成的時候執行的,就是在webviewDidFinishLoad
性能
內嵌頁面向rn傳遞信息和接受信息:ui
window.postMessage(data); document.addEventListener('message', (event) => {});
rn層向內嵌頁面傳遞信息:
<Webview onMessage={event => {}} ref={(_ref) => {this.webview = _ref}} ... /> this.webview.postMessage(data)
細心的朋友此處應該能夠發現出這裏的postMessage和平時咱們調用的不太同樣:
通常狀況下:window.postMessage(data, origin);
內嵌在webview之中:window.postMessage(data);
緣由是由於在uiwebview之中從新定義了window.postMessage,原來的postmessage已經被賦予到originMessage之中,因此若是在內嵌頁面中出現了postmessage(data),放在瀏覽器會報錯,放在rn的webview就會沒事。
當頁面資源加載完成以後,就會觸發webviewDidFinishLoad這個生命週期,在這個生命週期內,會作幾件事情:
其中從新定義postmessage的js代碼:
大概的意思就是將內嵌頁面調用postmessage的信息存在messagequeue之中(以字符串形式放進去),而後經過定義window.location的值來傳遞信息給原生成,其中window.location的格式是:
'%@://%@?' + encodeURIComponent(messageQueue.shift());" ,當中的兩個%@會被RCTJSNavigationScheme和kPostMessageHost代替從而造成新的url地址(不是經常使用的http協議的地址,是指定的特殊協議)
例如:'react-js-navigation://postMessage?' + encodeURIComponent('{"A":1}') ===> "react-js-navigation://postMessage?%7B%22A%22%3A1%7D";因爲內嵌頁面沒有window,因此只能用document來監聽webview傳來的信息。
postmessage的信息如何傳遞給原生層:每當webview之中出現url的請求,都會觸發shouldStartLoadWithRequest,此時就會由
大概就是判斷url的host是否爲kPostMessageHost,若是是則認爲是postmessage傳來的,而後執行_onMessage方法,而這個方法事由上層js定義的:
webview如何將信息傳遞給內嵌頁面:
大概就是經過document.dispatchEvent發起一個事件,而後在內嵌頁面之中由document進行監聽;
下面就是整一塊uiwebview的通訊流程:
因此若是要js層調用原生層能力,能夠經過協議請求,而後在原生對該協議進行攔截處理,從而判斷是否調用原生能力。
以上就是對uiwebview的一個比較淺的概述,下一篇會繼續介紹一下rn中wkwebview的通訊原理。