1. 程式人生 > >在React Native中整合熱更新

在React Native中整合熱更新

最近,在專案DYTT集成了熱更新,簡單來說,就是不用重新下載安裝包即可達到更新應用的目的,也不算教程吧,這裡記錄一下。

1.熱更新方案

目前網上大概有兩個比較廣泛的方式,分別是

前者是由ReactNative中文網推出的程式碼熱更新服務,後者是由微軟老大哥推出的,當然不僅僅是為React Native,還包括其他原生方式。

綜合考慮之下,選擇了react-native-code-push

2.安裝code-push

1.安裝code-push

npm install -g code-push-cli

2.註冊登入賬號

code-push register

這時候會自動啟動瀏覽器開啟網頁並提供一個codePush AccessKey,然後命令列裡出現需要輸入access key

輸入之後就登入成功了。

(貌似在本機上以後都不用登入了,暫不清楚保持登入持續多久)

3.新增一個CodePush應用

code-push app add myProject android react-native
注意填寫app的名稱,OS( android/ ios),平臺( react-native),並且 androidios需要建立兩個應用

建立完成會出現兩個key

name Deployment Key
Production (一串37位的key)
Staging (一串37位的key)

Production是對應生產環境的,Staging是對應開發環境的。

這個對於我們來說其實沒什麼區別,只是為了方便測試,所以搞了兩個環境

3.react-native應用接入code-push

1.安裝react-native-code-push

yarn add react-native-code-push

link

react-native link react-native-code-push

2.原生配置

目前只測試了androidios有興趣的可以自行測試

上面提到了兩個key值,現在需要配置在原生目錄裡

1.開啟android/app/build.gradle

android {
    ...
    buildTypes {
        debug {
            ...
            // Note: CodePush updates should not be tested in Debug mode as they are overriden by the RN packager. However, because CodePush checks for updates in all modes, we must supply a key.
            buildConfigField "String", "CODEPUSH_KEY", '""'
            ...
        }
    releaseStaging {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_STAGING_KEY>"'//注意這裡的引號
        ...
    }

    release {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_PRODUCTION_KEY>"'
        ...
    }
}
...

}

如果遇到打包錯誤,可加上matchingFallbacks = ['release', 'debug'],不知道是不是個別情況,如果沒有的請忽略。

修改versionName為3位數的版本號(code-push要求)

defaultConfig {
        applicationId "com.dytt"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 2
        versionName "2.1.0"//預設為2位版本號
        // ndk {
        //     abiFilters "armeabi-v7a", "x86"
        // }
    }
release {
            //...
            matchingFallbacks = ['release', 'debug']//加上這一句
            buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_PRODUCTION_KEY>"'
            //...
        }

2.開啟MainApplication.java

@Override
protected List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
        ...
        new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG), // Add/change this line.
        ...
    );
}

這樣就實現了key的動態部署,即在什麼環境下使用什麼key

以上文件參考自https://github.com/Microsoft/react-native-code-push/blob/master/docs/multi-deployment-testing-android.md

4.客戶端更新策略

1.匯入react-native-code-push

這裡需要在應用的根元件上新增CodePush配置

import CodePush from "react-native-code-push";

如果你的環境支援Decorator(修飾符),可以這樣

@codePush(options: CodePushOptions)
class MyApp extends Component<{}> {}

普通的寫法

class MyApp extends Component<{}> {}
MyApp = codePush(codePushOptions)(MyApp);
export default MyApp;

這裡的codePushOptions是更新的配置選項

  • checkFrequency (codePush.CheckFrequency) 指定您要檢查更新的時間,預設為codePush.CheckFrequency.ON_APP_START
  • installMode (codePush.InstallMode) 指定何時安裝可選更新,預設為codePush.InstallMode.ON_NEXT_RESTART
  • ...

詳細的配置可參考https://github.com/Microsoft/react-native-code-push/blob/master/docs/api-js.md

2.更新策略

預設情況下,CodePush會在app每次啟動的時候去檢測是否有更新,如果有,app會自動下載並在下次開啟app時安裝

這種更新方式是靜默的,使用者根本察覺不到。

如果我們需要給一點更新提示,可以使用預設的彈出框,也就是react-native自帶的Alert,點選後立即安裝

class MyApp extends Component {}
MyApp = codePush({
    updateDialog: true,
    installMode: codePush.InstallMode.IMMEDIATE
})(MyApp);

當然,你可以對彈出框做少量的自定義,比如標題,按鈕的文字等

updateDialog: {
  optionalIgnoreButtonLabel: '稍後',
  optionalInstallButtonLabel: '立即更新',
  optionalUpdateMessage: '有新版本了,是否更新?',
  title: '更新提示'
},

這些是預設的更新方式,那麼如何自定義呢。

我們可以用到CodePush.checkForUpdate來手動檢查更新,然後彈出一個自定義視窗

const RemotePackage = await CodePush.checkForUpdate(deploymentKey);
if(RemotePackage){
  this.modal.init(RemotePackage);//開啟彈窗
}
這裡需要注意的是,在 checkForUpdate(或其他需要填寫deploymentKey的地方)的時候,如果在 debug模式下,如果不填寫 deploymentKey,會提示缺少 deploymentKey,我們可以臨時寫一個固定的方便測試。在正式環境下,這裡是不需要填寫,它會根據系統自動獲取我們在之前配置的那些 deploymentKey

然後可以通過RemotePackage.downloadLocalPackage.install來完成下載和安裝

install = async () => {
    LayoutAnimation.easeInEaseOut();
    this.setState({status:1})//download
    const LocalPackage = await this.RemotePackage.download((progress)=>{
        this.setState({
            receivedBytes:progress.receivedBytes
        })
        Animated.timing(
            this.width,
            {
                toValue: parseFloat(progress.receivedBytes / progress.totalBytes).toFixed(2),
                duration: 150
            }
        ).start();
    })
    this.setState({status:2})//downloadComplete
    await LocalPackage.install(LocalPackage.isMandatory?CodePush.InstallMode.IMMEDIATE:CodePush.InstallMode.ON_NEXT_RESUME);
    if(!LocalPackage.isMandatory){
        this.setState({status:3})
        this.setVisible(false);
    }else{
        ToastAndroid && ToastAndroid.show('下次啟動完成更新', ToastAndroid.SHORT);
    }
}

具體實現可以參考專案DYTT

3.打包Release

cd android

生成Release(Production)包

gradlew assembleRelease

生成Release(Staging)包

gradlew assembleReleaseStaging

其實都一樣,只是環境區別

5.釋出code-push更新

這一步很簡單,集成了打包和釋出

code-push release-react dyttAndroid android --t 2.1.0 --dev false --d Production --des "1.修復了已知BUG\n 2.測試code push" --m true

這裡注意--t 2.1.0,有以下幾種規則

1.2.3 僅僅只有1.2.3的版本
  • 所有版本

1.2.x 主要版本1,次要版本2的任何修補程式版本

1.2.3 - 1.2.7 1.2.3版本到1.2.7版本

>=1.2.3 <1.2.7 大於等於1.2.3版本小於1.2.7的版本

~1.2.3 大於等於1.2.3版本小於1.3.0的版本

^1.2.3 大於等於1.2.3版本小於2.0.0的版本

--d表示開發版本,可選擇ProductionStaging

--m表示是否強制更新

當然還有很多操作,比如刪除某些更新,回滾等,可以參考官方文件https://github.com/Microsoft/react-native-code-push

小節

總的來說,這次熱更新整合還是挺容易,裡面碰到的幾個誤區在上面也已經提到過,歡迎大家多多關注我的專案DYTT^^

原文地址:https://segmentfault.com/a/1190000017856985