React Native應(yīng)用部署/熱更新/常見(jiàn)問(wèn)題-CodePush最新集成總結(jié)

什么是CodePush

CodePush是一個(gè)微軟開(kāi)發(fā)的云服務(wù)器。通過(guò)它,開(kāi)發(fā)者可以直接在用戶(hù)的設(shè)備上部署手機(jī)應(yīng)用更新。CodePush相當(dāng)于一個(gè)中心倉(cāng)庫(kù),開(kāi)發(fā)者可以推送當(dāng)前的更新(包括JS/HTML/CSS/IMAGE等)到CoduPush,然后應(yīng)用將會(huì)查詢(xún)是否有更新。

接入流程

  • 安裝 CodePush CLI
  • 注冊(cè) CodePush賬號(hào)
  • 在CodePush服務(wù)器注冊(cè)App
  • RN代碼中集成CodePush
  • 原生應(yīng)用中配置CodePush
  • 發(fā)布更新的版本

1. 安裝 CodePush CLI

安裝CodePush指令,直接在終端上輸入如下命令即可,注意:這個(gè)CodePush指令只需要全局安裝一次即可,如果第一次安裝成功了,那后面就不在需要安裝

npm install -g code-push-cli
image.png

2、注冊(cè) CodePush賬號(hào)

注冊(cè)CodePush賬號(hào)也很簡(jiǎn)單,同樣是只需簡(jiǎn)單的執(zhí)行下面的命令,同樣這個(gè)注冊(cè)操作也是全局只需要注冊(cè)一次即可

code-push register

注意:當(dāng)執(zhí)行完上面的命令后,會(huì)自動(dòng)打開(kāi)一個(gè)授權(quán)網(wǎng)頁(yè),讓你選擇使用哪種方式進(jìn)行授權(quán)登錄,這里我們統(tǒng)一就選擇使用GitHub即可

image.png

當(dāng)注冊(cè)成功后,CodePush會(huì)給我們一個(gè)key



我們直接復(fù)制這個(gè)key,然后在終端中將這個(gè)key填寫(xiě)進(jìn)去即可,填寫(xiě)key登錄成功顯示效果如下


image.png

我們使用下面的命令來(lái)驗(yàn)證我的登錄是否成功
code-push login
image.png

CodePush注冊(cè)登錄相關(guān)命令

  • code-push login 登陸
  • code-push loout 注銷(xiāo)
  • code-push access-key ls 列出登陸的token
  • code-push access-key rm <accessKye> 刪除某個(gè) access-key

3、在CodePush服務(wù)器注冊(cè)App

為了讓CodePush服務(wù)器有我們的App,我們需要CodePush注冊(cè)App,輸入下面命令即可完成注冊(cè),這里需要注意如果我們的應(yīng)用分為iOS和Android兩個(gè)平臺(tái),這時(shí)我們需要分別注冊(cè)兩套key
應(yīng)用添加成功后就會(huì)返回對(duì)應(yīng)的productionStaging 兩個(gè)key,production代表生產(chǎn)版的熱更新部署,Staging代表開(kāi)發(fā)版的熱更新部署,在ios中將staging的部署key復(fù)制在info.plist的CodePushDeploymentKey值中,在android中復(fù)制在Application的getPackages的CodePush中

添加iOS平臺(tái)應(yīng)用

code-push app add iOSrn_app ios react-native

image.png

添加Android平臺(tái)應(yīng)用

code-push app add Androidrn_app Android react-native
image.png

我們可以輸入如下命令來(lái)查看我們剛剛添加的App

code-push app list
image.png

CodePush管理App的相關(guān)命令:

  • code-push app add 在賬號(hào)里面添加一個(gè)新的app
  • code-push app remove 或者 rm 在賬號(hào)里移除一個(gè)app
  • code-push app rename 重命名一個(gè)存在app
  • code-push app list 或則 ls 列出賬號(hào)下面的所有app
  • code-push app transfer 把a(bǔ)pp的所有權(quán)轉(zhuǎn)移到另外一個(gè)賬號(hào)
  • code-push release-react <appName> <platform> -t 版本 -d 環(huán)境 --des 描述 -m true (強(qiáng)制更新)// 發(fā)布
  • code-push deployment clear <appName> Production or Staging // 清除歷史部署記錄
  • code-push rollback <appName> Production --targetRelease v4(codepush服務(wù)部署的版本號(hào)) // 回滾

// 應(yīng)用信息相關(guān)

  • code-push deployment add <appName> 部署
  • code-push deployment rm <appName> 刪除部署
  • code-push deployment rename <appName> 重命名
  • code-push deployment ls <appName> 列出應(yīng)用的部署情況
  • code-push deployment ls <appName> -k 查看部署的key
  • code-push deployment history <appName> <deploymentName> 查看歷史版本

4、RN代碼中集成CodePush

首先我們需要安裝CodeoPush組件,然后通過(guò)link命令添加原生依賴(lài),最后在RN根組件中添加熱更新邏輯代碼
安裝組件

npm install react-native-code-push --save
image.png

添加原生依賴(lài),這里添加依賴(lài)我們使用自動(dòng)添加依賴(lài)的方式(RN0.60版本以上的 cli里集成了AutoLink,不用手動(dòng)link資源了)

react-native link react-native-code-push
image.png

我們?cè)赗N項(xiàng)目的根組件(例如App.js)中添加熱更新邏輯代碼如下

~
import codePush from "react-native-code-push";
const codePushOptions = { checkFrequency: codePush.CheckFrequency.MANUAL };
export default class App extends Component<{}> {

  componentDidMount(){
    codePush.sync({
      updateDialog: true,
      installMode: codePush.InstallMode.IMMEDIATE,
      mandatoryInstallMode:codePush.InstallMode.IMMEDIATE,
      //deploymentKey為剛才生成的,用Platform判斷下平臺(tái)(填寫(xiě)你自己的)
      deploymentKey: Platform.OS === 'ios'?'sYvpLUxuBU9FxICqJ5sccL2GDUPZcc988a73-c917-4dba-bd40-1837998442a6':'fqdFCqLyL4XclNZjWvNN3KNhImR5cc988a73-c917-4dba-bd40-1837998442a6',
      });
  }
~

5,模擬器上運(yùn)行項(xiàng)目

react-native run-ios
react-native run-android

5.1 如圖下所顯打包過(guò)程中可能遇到的\color{red}{報(bào)錯(cuò)}

image.png

錯(cuò)誤發(fā)生在java編譯器執(zhí)行過(guò)程中
image.png

image.png

看到出來(lái)是剛剛引入的Code-Push包,實(shí)例化的時(shí)候getString方法獲取我們之前的DeploymentKey失敗.
getString是android 開(kāi)發(fā)中Context類(lèi)上的一個(gè)獲取字符串的方法,在RN中會(huì)從根目錄下/android/app/src/main/res/values/strings.xml文件中獲取值。

我們打開(kāi)strings.xml文件后添加這樣一行代碼:

<string moduleConfig="true" name="CodePushDeploymentKey"><string moduleConfig="true" name="CodePushDeploymentKey">xxxxxxx你剛剛注冊(cè)DeploymentKey</string></string>

例如

image.png

再次react-native run-android即可成功運(yùn)行

6. deployment-key的設(shè)置與獲取bundle路徑 (關(guān)于Grande

  • 在上述代碼中我們?cè)趧?chuàng)建CodePush實(shí)例的時(shí)候需要設(shè)置一個(gè)deployment-key,因?yàn)閐eployment-key分生產(chǎn)環(huán)境與測(cè)試環(huán)境兩種,所以建議大家在build.gradle中進(jìn)行設(shè)置。在build.gradle中的設(shè)置方法如下:
    打開(kāi)android/app/build.gradle文件,找到android { buildTypes {} }然后添加如下代碼即可:
buildTypes {
    release {
        minifyEnabled enableProguardInReleaseBuilds
        proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        signingConfig signingConfigs.config
       + buildConfigField "String", "CODE_PUSH_KEY", CODE_PUSH_KEY_PRODUCTION
       + buildConfigField "boolean", "IS_CODE_PUSH", "true"
    }
    debug {
       + buildConfigField "String", "CODE_PUSH_KEY", CODE_PUSH_KEY_STAGING
       + buildConfigField "boolean", "IS_CODE_PUSH", "true"
    }
}

心得:另外,我們也可以將deployment-key存放在gradle.properties中:

CODE_PUSH_KEY_PRODUCTION="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
CODE_PUSH_KEY_STAGING="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
image.png
在android/app/build.gradle設(shè)置好deployment-key之后呢,我們就可以這樣使用了:

MainApplication.java下的ReactNativeHost方法中添加

@Override
protected String getJSBundleFile() {
    // gradlew assembleRelease會(huì)把所有用到的JavaScript代碼都打包內(nèi)置到APK中
    if (BuildConfig.IS_CODE_PUSH) {
        return CodePush.getJSBundleFile(); // code-push熱更新
    }
    //return UpdateContext.getBundleUrl(MainApplication.this); // pushy熱更新
} 

7.修改versionName和引入code-push設(shè)置。

在 android/app/build.gradle中有個(gè) android.defaultConfig.versionName屬性,我們需要把 應(yīng)用版本改成 1.0.0(默認(rèn)是1.0,但是codepush需要三位數(shù))。

android{
    defaultConfig{
        versionName "1.0.0"
    }
}
//文件最下方
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"  

\android\app\src\main\java\com\ysty_app3\MainApplication.java添加包

import com.microsoft.codepush.react.CodePush;

至此Code Push for Android的SDK已經(jīng)集成完成。

8、發(fā)布更新的版本

在使用之前需要考慮的是檢查更新時(shí)機(jī),更新是否強(qiáng)制,更新是否要求即時(shí)等

更新時(shí)機(jī)

一般常見(jiàn)的應(yīng)用內(nèi)更新時(shí)機(jī)分為兩種,一種是打開(kāi)App就檢查更新,一種是放在設(shè)置界面讓用戶(hù)主動(dòng)檢查更新并安裝

  • 打開(kāi)APP就檢查更新
    最為簡(jiǎn)單的使用方式在React Natvie的根組件的componentDidMount方法中通過(guò)
    codePush.sync()(需要先導(dǎo)入codePush包:import codePush from 'react-native-code-push')方法檢查并安裝更新,如果有更新包可供下載則會(huì)在重啟后生效。不過(guò)這種下載和安裝都是靜默的,即用戶(hù)不可見(jiàn)。如果需要用戶(hù)可見(jiàn)則需要額外的配置。具體可以參考codePush官方API文檔,部分代碼,完整代碼請(qǐng)參照文檔上面
 codePush.sync({
      updateDialog: true,//code-push 接管更新
      installMode: codePush.InstallMode.IMMEDIATE,
      mandatoryInstallMode:codePush.InstallMode.IMMEDIATE,
      //deploymentKey為剛才生成的,用Platform判斷下平臺(tái)
      deploymentKey: Platform.OS === 'ios'?'IOSKey':'andoridKey',
      });

上面的配置在檢查更新時(shí)會(huì)彈出提示對(duì)話框, mandatoryInstallMode表示強(qiáng)制更新,

  • 用戶(hù)點(diǎn)擊檢查更新按鈕
    在用戶(hù)點(diǎn)擊檢查更新按鈕后進(jìn)行檢查,如果有更新則彈出提示框讓用戶(hù)選擇是否更新,如果用戶(hù)點(diǎn)擊立即更新按鈕,則會(huì)進(jìn)行安裝包的下載(實(shí)際上這時(shí)候應(yīng)該顯示下載進(jìn)度,這里省略了)下載完成后會(huì)立即重啟并生效(也可配置稍后重啟),部分代碼如下
codePush.checkForUpdate(deploymentKey).then((update) => {
    if (!update) {
        Alert.alert("提示", "已是最新版本--", [
            {
                text: "Ok", onPress: () => {
                console.log("點(diǎn)了OK");
            }
            }
        ]);
    } else {
        codePush.sync({
                deploymentKey: deploymentKey,
                updateDialog: {
                    optionalIgnoreButtonLabel: '稍后',
                    optionalInstallButtonLabel: '立即更新',
                    optionalUpdateMessage: '有新版本了,是否更新?',
                    title: '更新提示'
                },
                installMode: codePush.InstallMode.IMMEDIATE,

            },
            (status) => {
                switch (status) {
                    case codePush.SyncStatus.DOWNLOADING_PACKAGE:
                        console.log("DOWNLOADING_PACKAGE");
                        break;
                    case codePush.SyncStatus.INSTALLING_UPDATE:
                        console.log(" INSTALLING_UPDATE");
                        break;
                }
            },
            (progress) => {
                console.log(progress.receivedBytes + " of " + progress.totalBytes + " received.");
            }
        );
    }
 }

更新是否要求即時(shí)
在更新配置中通過(guò)指定installMode來(lái)決定安裝完成的重啟時(shí)機(jī),亦即更新生效時(shí)機(jī)

  • codePush.InstallMode.IMMEDIATE :安裝完成立即重啟更新

  • codePush.InstallMode.ON_NEXT_RESTART :安裝完成后會(huì)在下次重啟后進(jìn)行更新

  • codePush.InstallMode.ON_NEXT_RESUME :安裝完成后會(huì)在應(yīng)用進(jìn)入后臺(tái)后重啟更新

    如何發(fā)布CodePush更新包

工程根目錄新增 bundles文件夾:

mkdir bundles

1.自動(dòng)生成bundles文件發(fā)布:

code-push release-react 《app名稱(chēng)》《平臺(tái)》 -t 《版本號(hào)》 -d Production --des "描述" -m true
例如
code-push release-react weather android --t 1.0.0 -d Production --dev false --des "1.優(yōu)化操作流程,2.我裂開(kāi)" --m false

2.手動(dòng)生成bundles文件發(fā)布, 首先在根目錄創(chuàng)建bundles文件夾(每次重新生成文件時(shí)需刪除上次的文件)

  • 單js文件
1. 創(chuàng)建bundles里的文件
打包命令
react-native bundle --platform 平臺(tái) --entry-file 啟動(dòng)文件 --bundle-output 打包js輸出文件 --assets-dest 資源輸出目錄 --dev 是否調(diào)試 

打包整個(gè)項(xiàng)目的js文件,例如: 
react-native bundle --platform android --entry-file index.js --bundle-output ./bundles/index.android.bundle --dev false

2. 發(fā)布更新
發(fā)布命令: 
code-push release <應(yīng)用名稱(chēng)> <Bundles所在目錄> <對(duì)應(yīng)的應(yīng)用版本> --deploymentName 更新環(huán)境 --description 更新描述 --mandatory 是否強(qiáng)制更新

例如:
code-push release CodePushDemo-android ./bundles/index.android.bundle 1.0.0 --deploymentName Production --description "熱更新" --mandatory true
  • js文件+圖片資源,–assets-dest 后就是放圖片的文件夾路徑
打包命令:–assets-dest 后就是放圖片的文件夾路徑
react-native bundle --platform android --entry-file index.js --bundle-output ./bundles/index.android.bundle --assets-dest ./bundles --dev false

發(fā)布bundles文件:
code-push <release/debug> <projectName(與注冊(cè)的app同名)><bundle文件名> <版本號(hào)> --deploymentName 更新環(huán)境 --description 更新描述 --mandatory 是否強(qiáng)制更新
例如:
code-push release CodePushDemo-android ./bundles 1.0.0  //省略默認(rèn)是發(fā)布Staging
code-push release CodePushDemo-android ./bundles 1.0.0 -d Production --des "熱更新" --mandatory true

需要注意的是:

  • 輸出的bundle文件名不叫其他,而是 index.android.bundle,是因?yàn)?在debug模式下,
    工程讀取的bundle就是叫做 index.android.bundle。
  • 平臺(tái)可以選擇 android 或者 ios。

查看發(fā)布信息

查看已a(bǔ)dd appName
code-push app list 
查看部署的歷史版本信息
code-push deployment ls CodePushDemo-android -k

9,自定義更新窗口

我們?cè)俅未蜷_(kāi) app是就可以看到,code-push彈出的 更新提示彈框

image.png

這是code-push提供的彈窗,如果需要自定義文字

修改更新彈出框內(nèi)容
進(jìn)入node_modules->react-native-code-push->Codepush.js修改以下內(nèi)容

image.png

需要更多自定義設(shè)置參考https://blog.csdn.net/weixin_42613755/article/details/104964557

可能出現(xiàn)的問(wèn)題(react-native run-android)
  1. What went wrong:
    Execution failed for task ':app:mergeDebugResources'.
    Could not read path 'E:\cli3\weather2\android\app\build\intermediates\incremental\mergeDebugResources\merged.dir\values'.
    cd android 執(zhí)行 gradlew clean解決
  2. [Error:Execution failed for task ':app:transformClassesWithDexForDebug]

在項(xiàng)目android/app/build.gradle下添加

 defaultConfig {
        ...
        multiDexEnabled true
}

本片內(nèi)容借鑒至https://segmentfault.com/a/1190000016273902?utm_source=tag-newest
可訪問(wèn) 查閱關(guān)于ios端的熱更新

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容