ReactNative熱更新解決方案(包含插件)

新做了一個ReactNative的項目,中文網的熱更新不太符合我的業務需求,所以自己上手做了一個~~~~

一、原理

熱更新原理很簡單,RN提供了getJSBundleFile方法,此方法返回一個路徑,路徑裏包含代碼構建合併的index.android.bundle文件和資源文件(drawable開頭的)。所以將已經下載好的文件路徑返回,再重啓APP就完成了熱更新。

 

二、實踐

今天把熱更新所有的代碼打包成了一個插件,希望能幫助到各位。

插件中有些代碼來源於網上各個大佬,如有雷同,我只能說聲感謝!

git

https://github.com/Txiaomo/react-native-hot-deployment

npm

https://www.npmjs.com/package/react-native-hot-deployment

 

完整實踐如下

 1.首先應用進行插件安裝,git上有安裝步驟及相關方法。

 2.在項目package.json文件裏面配置

"package:hotpushFile": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output bundle_zip/index.android.bundle --assets-dest bundle_zip"

在項目根目錄新建文件夾bundle_zip   並不一定要這個命名,但是命名要與上圖中新加的命令裏面的名字保持一致

熱更新的時候運行 npm run package:hotpushFile 這樣編譯過後的js文件與項目資源文件就是被放進bundle_zip文件裏,然後我們需要將文件夾壓縮爲bundle.zip (此命名唯一,需要更改命名請在插件的Download文件裏面自行修改) 壓縮的目的是爲了下載的資源包更小

 我這裏是使用jenkins構建的,所以壓縮文件的步驟是由運維幫忙完成的,壓縮完成後放在服務器一個固定的目錄。運維幫忙創建了這個文件的下載鏈接。我們可以在項目裏將下載地址寫死

2.需要後端配置接口如下 

因爲我們app提示升級需要告知用戶升級的內容,所以我們一般會選擇用一個前端頁面來維護app的升級管理。前端頁面如下

這樣我們app在啓動後或者登錄時就可以請求後端接口,將接口給的app版本與當前版本作對比來查看app是否需要升級!

代碼如下

MainApplication中

import android.content.SharedPreferences;

import android.content.pm.PackageInfo;

import android.content.pm.PackageManager;

import java.io.File;

public class MainApplication extends Application implements ReactApplication {

    private SharedPreferences sharedPreferences;

    private String newVersion = "";

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {

        @Override

        protected String getJSBundleFile() {

            PackageManager pm = getApplicationContext().getPackageManager();

            PackageInfo pi;

            try {

                pi = pm.getPackageInfo(getApplicationContext().getPackageName(), 0);

                newVersion = pi.versionName;

            } catch (PackageManager.NameNotFoundException e) {

                e.printStackTrace();

            }

        sharedPreferences=getSharedPreferences("appVersion.xml",MODE_PRIVATE);

        String oldVersion=sharedPreferences.getString("version","0.0.0");

        String jsBundleFile = getFilesDir().getAbsolutePath()+"/index.android.bundle";

        File file = new File(jsBundleFile);

        int oldVersionBack=Integer.parseInt(oldVersion.replaceAll("\\.",""));

        int newVersionBack=Integer.parseInt(newVersion.replaceAll("\\.",""));

        if((oldVersion.equals("0.0.0")|| oldVersionBack>=newVersionBack)&& file != null             && file.exists()) {

            return jsBundleFile;

        } else {

            return super.getJSBundleFile();

        }
    }
}

 

const { HotPushVersion, Download, DownloadApk, RestartApp } = NativeModules;

//根據後端接口返回類型來判斷更新方式
if (hotpush) {
   /**
    * 下載zip熱更新壓縮包
    */
   Download.downloading(url);
   this.listener = DeviceEventEmitter.addListener("downloadZipStatus", e => {
     if (e && e.status === "success") {
         //下載並解壓成功
       /**
        * version:更新的版本號
        */
       HotPushVersion.updataVersion(version);
        console.log("重啓應用中");
       RestartApp.Restart();
     } else if (e && e.status === "error") {
         //下載失敗
     } else if (e && e.status === "decompressionError") {
         //解壓失敗
     } else if (e && e.status) {
       console.log("下載進度====>" + e.status + "%");
     } else {
       console.log("=================>");
     }
   });
 } else {    
    /**     
     * 下載apk     
     * 接收兩個參數,第一個爲安裝包下載的url,第二個爲描述     
     */
    DownloadApk.downloading(url, "PDA"); 
 }

如有不懂的,歡迎提問

 

 

討論。。。

之所以要打包圖片資源文件,是因爲返回了一個新的index.android.bundle文件路徑的時候,RN默認會從這個路徑讀取圖片,如果沒有圖片,那麼app上也不會顯示。上文中提供的插件有一個問題,我採用的方式是每次打包所有的資源文件,然後熱更新的時候也是下載的所有資源文件。不過由於是zip壓縮文件,其實也不會太大。不過我想找到一種每次更新只需要下載新圖片的方式。路過的大神們有想法請留言...

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