React Native WebView優化(iOS)

問題

在React Native中打開一個WebView會有非常明顯的白屏時間。

 

分析問題

在網上看了一些關於WebView的優化,參考下面這個WebView打開過程:

WebView啓動時間

我們可以總結爲:

1、節約初始化的時間,預先初始化一個WebView。

2、原生端請求頁面資源,優化白屏時間。

3、頁面離線化,原生端直接從本地加載網頁,優化白屏時間。

 

這三種方案都需要原生端進行改造,而且搞的不好可能出現內存泄漏的風險。頁面離線化體驗是最好的,但實現最複雜。

根據實際的業務場景,比如我們只想優化幾個主頁界面WebView的打開速度,筆者嘗試把1和2結合起來使用,在用戶進入需要打開WebView的頁面前,先初始化並加載好一個頁面,當用戶觸發打開WebView時直接把初始化好的頁面呈現出來。

想法是美好的,但是能否真的可行呢,先得驗證一下,我們從iOS端開始。

 

實驗思路

iOS裏打開一個webView(現在用的是WKWebView組件,它在iOS 8開始用來替換以前的UIWebView組件)需要三個步驟:

1、實例化一個WKWebView對象。

2、使用這個WKWebView對象加載URL。

3、把這個WKWebView當作子視圖加入到父視圖中。

 

我們實驗組的思路是在父視圖加載完畢以後,就執行前兩步,在父視圖裏放一個按鈕,用戶點擊按鈕的時候執行第三部。當然還要弄一個對照組,就是用戶點擊按鈕的時候執行1,2,3步,然後我們來對比兩個組打開WebView的時間。

 

實驗組:

先初始化WebView並加載頁面,用戶點擊以後顯示WebView。

代碼:

界面:

當我們點擊打開百度按鈕時,界面會白屏1s左右,然後百度的網頁就顯示出來了。

 

對照組:

先不初始化WebView,用戶點擊以後進行初始化,加載和顯示WebView。

代碼:

和上面實驗組當代碼相比,我們只是移動了[self initWebView]這行代碼的調用位置。

界面和實驗組一樣。

我們點擊打開百度的按鈕時,會出現白屏,3s以後纔會顯示百度頁面。

 

實驗總結

通過這個實驗,我們知道這樣做是完全可行的,特別是針對特定頁面。比如我們的APP主要頁面就是用WebView呈現的。但是我們在React Native裏如何做到這一點呢?我們先來看看RN裏使用WebView的情況。

 

react-native-wkwebview

https://github.com/CRAlpha/react-native-wkwebview

這個RN組件在RN本身不支持WKWebView時相當有用,但是目前有了https://github.com/react-native-community/react-native-webview以後,這個組件估計是不怎麼維護了,不過沒有關係,我們來看看這個組件是如何使用WebView的,並嘗試給這個組件添加一個上面我們實現的功能,比如提供一個函數可以預先初始化好一個WebView,然後使用組件時通過傳遞參數指定打開預先初始化好的WebView。

這個組件原生代碼的核心文件如下:

CRAWKWebView.m實現了WKWebView,以及裏面的各種方法。它提供了一個函數initWithProcessPool來實例化一個真正的WKWebview。

CRAWKWebViewManager.m按照React-Native的規範,實現了一個可以和JS交互的對象。這個對象裏,調用initWithProcessPool獲得正在的WKWebview。

使用組件時,比如這樣寫:

<WKWebView style={styles.webView} source={{uri: 'http://www.baidu.com'}} />

實際對應的Native代碼如下圖,是這個view函數。

也就是說,每次render一個WKWebView組件,就會生成一個新的CRAWKWebView。我們來改造一下,讓這個函數返回一個成員變量看看會發生什麼。

如下圖,我們新加一個pWebView屬性,然後在view函數裏返回這個_pWebView。

那這個pWebView變量在哪裏進行初始化呢?我們可以導出一個函數讓JS代碼來初始化,如下圖,添加一個initWebView函數:

這個函數對_pWebView進行初始化。然後我們就可以在js代碼裏就進行調用了。

如下圖所示,我們一開始就調用WKWebViewManager對webView進行初始化,然後渲染一個WKWebView在界面上。同時界面上會有一個按鈕,點擊按鈕會再次渲染一個新的WKWebView組件。

點擊Press me之前

點擊Press me按鈕以後會這樣顯示,如下圖:

網頁一瞬間顯示到下面去了,上面的卻不見了~。這個現象剛好說明,我們的修改生效了,我們讓每個WKWebView組件都返回了是同一個View。但是這個View一下從上面到了下面,還不知道是咋回事。

這樣我們就可以針對特定需要打開的WebView進行優化了,具體怎麼做呢?上面演示的每次只返回同一個webView明顯不滿足需求呀。

 

疑惑

1、iOS裏一個viewController是如何被其他view進行代理的,生命週期是如何進行的。

2、如果銷燬我新建的一個WebView。

 

總結

1、對iOS APP的基本構成有基礎認識,比如入口函數,UIWindow對象,它的rootViewController。UIViewController等,學會了單視圖開發流程。Object-C的函數聲明和調用能看懂了。

2、對iOS APP如何實現多View切換還未了解,各種用到的系統類不熟悉。

3、對RN的允許機制有了更多的瞭解,RN運行的時候有一個jsruntime在運行JS代碼,JS的代碼通過UI組件、函數和native代碼進行交互,但是隻能交互特定的native組件,如果這個組件沒有,就需要自己實現。自己實現的過程複雜度並不低於直接寫原生。這就給開發者設置了一個障礙,如果你的業務複雜,對性能細節追求卓越,RN不是一個好的選擇。如果你的業務能直接使用官方的和社區現有的組件就能實現,那使用RN能節約開發時間,但是如果你的業務會擴展到需要自己開發原生組件,那麼就不太適合使用RN了。

4、RN 0.60以後和前面的版本差別比較大,導致升級困難。

4、每一樣東西要系統的學都很困難,如何快速搞清楚一個概念需要從多個角度去觀察,好的講解能讓人快速理解新的概念。

 

 

參考文章:

https://tech.meituan.com/2017/06/09/webviewperf.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章