1. 程式人生 > >React Native 詳細實現熱部署、增量差異化熱更新

React Native 詳細實現熱部署、增量差異化熱更新

一.前言

Android原生App中我們實現熱修復有很多種選擇:Tinker、hotFix、Qzone的熱更新等等。基本的思路都是大同小異的。React Native中的熱更新有點像App的版本更新,也就是根據查詢server端的版本和手機端目前App的版本進行對比,然後來執行是否更新的操作。根本原因在於React Native的載入啟動機制:React Native會將一系列資源打包成js bundle檔案,系統載入js bundle檔案,解析並渲染。所以,React Native熱更新的根本原理就是更換js bundle檔案,並重新載入,新的內容就完美的展示出來了。微軟為我們提供了CodePush來簡化熱更新的操作,但是由於速度等原因在國內並沒有備受青睞。本篇內容就以自己伺服器來更新的方式實現。

前面簡單的說了些基本原理,接下來先上一張具體的更新流程圖:

上面流程圖中展示瞭如何實現更新的步驟,可以總結為如下幾點:

進入App根據版本檢查是否需要更新:

(1)更新:

下載最新JsBundle檔案以及所需要的圖片資源等,下載完成後解析最新JsBundle檔案。

(2)不更新:

判斷本地是否還有快取的JsBundle檔案:

1>存在:

本地存在JsBundle,即有過熱更新操作。那麼App直接載入在快取目錄下的JsBundle檔案。

2>不存在:

本地不存在JsBundle,即之前從未有過熱更新操作。那麼App只能使用初始化時打包在assets目錄下的index.android.bundle檔案。

Ok,根據上面的流程,我們來看下程式碼實現過程:

二.具體實現

2.1.檢查是否需要更新

實現步驟即請求伺服器中的版本號,然後與本地版本號進行對比,此處我為了程式碼清晰易懂,直接執行下載更新的流程。

2.2.Android為我們提供了下載工具類:DownLoadManager,我們使用它來執行下載

首先去判斷是否存在有下載的更新壓縮包,如果有,則先刪除舊的,然後下載最新壓縮包。

2.3.下載完成後,DownLoadManager會發出一個DownloadManager.ACTION_DOWNLOAD_COMPLETE的廣播,在收到廣播後,對比下載任務ID

因為我們下載的是Zip壓縮檔案(Zip壓縮檔案體積下,有效控制了由於更新檔案大以及圖片資源佔用給使用者帶來消耗流量的問題

),所以我們需要先解壓

2.4.解壓Zip

2.5.解壓完成後,載入最新Bundle和圖片資源

如何控制RN載入Bundle的方式呢?沒錯,0.26版本之後的RN系統在ReactApplication下的ReactNativeHost為我們提供了getJsBundleFile方法,在該方法中預設返回null,即載入assets下的bundle檔案。我們可以根據條件來載入不同目錄下的bundle檔案即可

在當我們下載好最新更新檔案後,跳轉到RN介面,即會執行getJSBundleFile方法來執行載入Bundle檔案的方式。在實際應用當中,我們可以在Splash頁面去執行檢查更新下載,然後在跳轉到RN介面時,最新檔案就會呈現出來。

如何獲取最新的bundle檔案和圖片資源呢?我們在RN專案根目執行以下命令來得到bundle檔案和圖片資源:

react-native bundle --entry-file index.android.js --bundle-output ./bundle/index.android.bundle--platform android--assets-dest./bundle--dev false

(1)--entry   入口js檔案,android系統就是index.android.js,iOS系統就是index.ios.js

(2)--bundle-output   生成的bundle檔案路徑

(3)--platform   平臺

(4)--assets-dest  圖片資源的輸出目錄

(5)--dev   是否為開發版本,打正式版的安裝包時我們將其賦值為false

執行命令之前,首先要在根目錄下建立好bundle資料夾,bundle檔案和圖片資源將會輸出到已建立好的bundle資料夾下。

解壓後的最新更新檔案:

到此,我們便完成了程式碼的熱更新工作。

三.優化補丁包更新

大家可能會說,如果bundle太大的情況下怎麼辦呢?沒錯,這個問題同樣在部落格開始也提到了。打包成zip也是為了減小更新檔案體積,減少使用者流量消耗,同樣,我們也可以生成用生成補丁包的方式來進一步減小更新包zip的體積。

初始專案釋出時,生成並保留一份index.android.bundle檔案。
有版本更新時,生成新的index.android.bundle檔案,使用google-diff-match-patch對比兩個檔案,並生成差異補丁檔案。app下載補丁檔案,再使用google-diff-match-patch和assets目錄下的初始版本合併,生成新的index.android.bundle檔案。ok,來看下核心程式碼:

3.1.生成補丁包

3.2.下載完成,解壓後執行mergePatAndAsset方法將Assets目錄下的index.android.bundle和pat檔案合併

3.3.合併

從上述程式碼中我們看到,合併分為如下過程:

(1)獲取Assets目錄下的bundle檔案,轉換為字串

(2)解析.pat檔案將其轉換為字串

(3)呼叫patch_fromText獲取patches補丁包

(4)呼叫patch_apply方法將第四步中生成patches補丁包與第一步中獲取的bundle合併生成新的bundle

(5)儲存bundle

3.4.讀取pat檔案的方法:

3.5.讀取Assets目錄下的bundle檔案:

以上步驟執行完成後,我們就獲取到了新的bundle檔案,繼而載入新的bundle檔案,實現React Native熱更新。

四.效果演示

為了演示,先來看更新前的介面:

點選載入最新Bundle,下載最新的,然後載入最新介面:

以上就是使用React Native關於熱更新的內容,其實還有很多不足地方,例如對更新檔案進行加密,防止被惡意修改等等一些內容還需要不斷完善。