React-Native 之 CodePush 熱更新

React-Native CodePush 之 配置Android

使用RN開發(fā)項(xiàng)目雖然已經(jīng)開發(fā)了很久了雾消,但親自操手配置 CodePush 還是第一次迅办,話不多說開始今天的 CodePush 配置之旅生巡;


簡介
CodePush 是由 Microsoft 提供的一個(gè)用于實(shí)現(xiàn) React Native 應(yīng)用程序熱更新的解決方案盒揉。它允許你在不通過應(yīng)用商店發(fā)布新版本的情況下,將更新推送到現(xiàn)有的安裝應(yīng)用程序潜秋。以下是 CodePush 的一些關(guān)鍵概念和用法:

  1. 部署環(huán)境: 在 CodePush 中曲掰,你可以創(chuàng)建不同的部署環(huán)境疾捍,例如 "Staging" 和 "Production"。每個(gè)環(huán)境都有自己的部署密鑰和更新栏妖。這有助于分離測試和生產(chǎn)環(huán)境的更新乱豆。
  2. 部署密鑰: 每個(gè)部署環(huán)境都有一個(gè)唯一的部署密鑰,用于標(biāo)識該環(huán)境的更新吊趾。你需要在應(yīng)用程序中配置正確的部署密鑰宛裕,以獲取相應(yīng)環(huán)境的更新。
  3. 發(fā)布更新: 使用 code-push release-react 命令發(fā)布新的更新论泛。該命令可以將 React Native 項(xiàng)目的 JavaScript bundle 和資源文件上傳到 CodePush 服務(wù)器揩尸。

開始實(shí)操

開發(fā)文檔傳送門。
1. 需要在項(xiàng)目的根目錄使用npm 下載依賴包

npm install --save react-native-code-push

2. 需要更改android的原生代碼

1)android/settings.gradle在 文件中屁奏,進(jìn)行以下添加

include ':app', ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')

2)在文件中 android/app/build.gradle 岩榆,將 codepush.gradle 文件添加為其他生成任務(wù)定義

apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"

3)MainApplication.java 更新文件,則通過以下更改使用 CodePush:

// 1. 導(dǎo)入插件
import com.microsoft.codepush.react.CodePush;

public class MainApplication extends Application implements ReactApplication {
    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        ...
        // 2. 重寫 getJSBundleFile 方法以讓 CodePush運(yùn)行時(shí)確定從那里獲取JS
        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
        }
    };
}

添加部署密鑰

先去后臺創(chuàng)建app 微軟管理平臺(備注:創(chuàng)建完成app之后坟瓢,會自動(dòng)生成Staging和Production環(huán)境)
第一步 - 使用 appcenter-cli勇边,進(jìn)行創(chuàng)app環(huán)境密鑰
安裝 App Center CLI:

npm install -g appcenter-cli

第二步 - 登入

// 回車之后,按照提示輸入yes载绿,然后會自動(dòng)打開瀏覽給出密碼粥诫,只需要復(fù)制粘貼回終端再回車就OK了
appcenter login

第三步 - 獲取 owner名稱 和 app名稱

appcenter apps list

第四步 - 選擇你要的配置的app項(xiàng)目油航,進(jìn)行創(chuàng)建SIT和PROD環(huán)境的密鑰(一定要核對好 owner名稱 和 app名稱的單詞大小寫)

// appcenter codepush release-react -a jackteng666-gmail.com/MyApp -d Staging SIT環(huán)境(測試環(huán)境)
范例:
appcenter codepush release-react -a 123456-@gamil.com/MyApp -d Staging

// appcenter codepush release-react -a 123456-@gamil.com/MyApp -d Production PROD環(huán)境(生產(chǎn)環(huán)境)
范例:
appcenter codepush release-react -a 123456-@gamil.com/MyApp -d Production

第五步 - 獲取密鑰

appcenter codepush deployment list --app 123456-@gamil.com/MyApp -k

不出意外的話崭庸,到這一步已經(jīng)創(chuàng)建好兩個(gè)環(huán)境的密鑰并且返回兩個(gè)環(huán)境的密鑰,接下來就是在app中配置密鑰


photo_2023-11-16_23-49-05.jpg

密鑰的配置分兩種形式谊囚,a. 固定環(huán)境 b.多種環(huán)境怕享,這些根據(jù)自己的業(yè)務(wù)需求選擇
a. 固定環(huán)境:
在 android/app/src/main/res/values/strings.xml 進(jìn)行添加

 <resources>
     <string name="app_name">AppName</string>
     <string moduleConfig="true" name="CodePushDeploymentKey">替換自己需要的環(huán)境密鑰</string>
 </resources>

b.多種環(huán)境
在 android/app/build.gradle 進(jìn)行添加

android {
    ...
    buildTypes {
        debug {
            ...
            resValue "string", "CodePushDeploymentKey", '""'
            ...
        }
        releaseStaging {
            ...
            resValue "string", "CodePushDeploymentKey", '"<INSERT_STAGING_KEY>"'
            matchingFallbacks = ['release']
            ...
        }
        release {
            ...
            resValue "string", "CodePushDeploymentKey", '"<INSERT_PRODUCTION_KEY>"'
            ...
        }
    }
    ...
}

到這一步app密鑰已經(jīng)配置好了,接下來就是寫js代碼進(jìn)行發(fā)布和測試熱更新
詳細(xì)介紹可以看這里API Reference

import CodePush from 'react-native-code-push';
...
export default CodePush(App);

如果不想在啟動(dòng)app的時(shí)候镰踏,檢查的話函筋,也可以單獨(dú)寫成組建,在需要的地方進(jìn)行加載;

import React, { useState, useEffect } from "react";
import codePush from "react-native-code-push";

const CheckUpdate = () => {
 
   /** 執(zhí)行CodePush更新 */
   const processCodepushUpdate = () => {
       codePush.notifyAppReady(); // 加這行避免自動(dòng)rollback, https://docs.microsoft.com/zh-tw/appcenter/distribution/codepush/rn-api-ref#codepushnotifyappready
       codePush
           .sync(
               {
                   installMode: codePush.InstallMode.ON_NEXT_RESUME, // 非強(qiáng)制:下次喚起時(shí)安裝新版本
                   mandatoryInstallMode: codePush.InstallMode.ON_NEXT_RESUME, // 強(qiáng)制:下次喚起時(shí)安裝新版本
                   minimumBackgroundDuration: 0, // 背景停留多久后觸發(fā)按照新版本(預(yù)設(shè)0)
                   rollbackRetryOptions: { delayInHours: 1, maxRetryAttempts: 50 }, // rollback重試設(shè)定
               },
               (status) => {
                   // codePush.SyncStatus.CHECKING_FOR_UPDATE 0 : 正在查詢 CodePush 服務(wù)器是否有更新奠伪。
                   // codePush.SyncStatus.AWAITING_USER_ACTION 1 : 有更新可用跌帐,并向最終用戶顯示確認(rèn)對話框首懈。(僅在updateDialog使用時(shí)適用)
                   // odePush.SyncStatus.DOWNLOADING_PACKAGE 2 : 在從 CodePush 服務(wù)器下載可用更新。
                   // codePush.SyncStatus.INSTALLING_UPDATE 3 : 已下載可用更新并將安裝
                   // codePush.SyncStatus.UP_TO_DATE 4 :應(yīng)用程序已完全更新到配置的部署
                   // codePush.SyncStatus.UPDATE_IGNORED 5 : 應(yīng)用程序有一個(gè)可選更新谨敛,最終用戶選擇忽略該更新究履。(僅在updateDialog使用時(shí)適用)
                   // codePush.SyncStatus.UPDATE_INSTALLED 6 : 已安裝可用更新,并將在syncStatusChangedCallback函數(shù)返回后立即運(yùn)行或在下次應(yīng)用程序恢復(fù)/重新啟動(dòng)時(shí)運(yùn)
                   // codePush.SyncStatus.SYNC_IN_PROGRESS 7: 正在進(jìn)行的sync操作阻止當(dāng)前調(diào)用的執(zhí)行脸狸。
                   // codePush.SyncStatus.UNKNOWN_ERROR -1 : 同步操作發(fā)現(xiàn)未知錯(cuò)誤最仑。
                   switch (status) {
                       case codePush.SyncStatus.DOWNLOADING_PACKAGE:
                           console.log("在從 CodePush 服務(wù)器下載可用更新");
                           break;
                       case codePush.SyncStatus.INSTALLING_UPDATE:
                           console.log("有更新可用,已下載可用更新并將安裝");
                           break;
                       case codePush.SyncStatus.UPDATE_INSTALLED:
                           console.log("已安裝可用更新炊甲,并將在syncStatusChangedCallback函數(shù)返回后立即運(yùn)行或在下次應(yīng)用程序恢復(fù)/重新啟動(dòng)時(shí)運(yùn)");
                           codePush.restartApp();
                           break;
                   }
               },
               ({ receivedBytes, totalBytes }) => {
                   // 計(jì)算出下載百分比
                   const percent = Math.floor((receivedBytes / totalBytes) * 100);
               }
           )
           .catch((error) => {
                console.log(JSON.stringify(error))
           });
   };

   useEffect(() => {
        processCodepushUpdate();
   }, []);

   return ...
};

export default CheckUpdate;

到這一步熱更新框架基本上完成了泥彤,接下來就是測試熱更新

發(fā)布版本指令:

當(dāng)前發(fā)布的是SIT環(huán)境,PROD環(huán)境同理

appcenter codepush release-react -a 123456-@gamil.com/MyApp -t "*" -d Staging --description "v1.0.0 測試更新" --sourcemap-output --output-dir ./build/android

備注:
-t 是指目標(biāo)版本卿啡,意思是只有是指定的目標(biāo)版本才會觸發(fā)更新吟吝,比如說,現(xiàn)在你的用戶用的版本是1.1.1 和 1.0.0這兩種版本颈娜,那么 -t "1.1.1" 就是發(fā)布之后爸黄,只有版本為1.1.1的用戶才會觸發(fā)熱更新
如果不需要指定目標(biāo)版本就輸入 -t "*" 通配符為全部版本 或者不輸入 -t

當(dāng)終端返回以下內(nèi)容,則表示已經(jīng)發(fā)布成功了(SIT環(huán)境)

Successfully released an update containing the "build/android/CodePush" directory to the "Staging" deployment of the "MyApp" app.

查看發(fā)布?xì)v史

appcenter codepush deployment history -a 123456-@gamil.com/MyApp Staging
photo_2023-11-17_00-24-27.jpg

到這里最新版本的代碼已經(jīng)發(fā)布到codPush服務(wù)器上了揭鳞,接下來就可以用已經(jīng)有熱更新代碼版本的app來測試了炕贵;

最簡單的方式就是
1、把當(dāng)前版本打包給Android手機(jī)安裝野崇,然后再改代碼(能夠明顯看到不一樣的界面称开,比較好分辨是否更新成功),然后再重新發(fā)布一次乓梨;
2鳖轰、重新打開APP檢查是否有更新提示(上面的組建,可以根據(jù)自己的想法寫出彈窗和顯示進(jìn)度條)

我當(dāng)前遇到一個(gè)錯(cuò)誤狀態(tài)碼是 codePush.SyncStatus.UNKNOWN_ERROR -1 : 同步操作發(fā)現(xiàn)未知錯(cuò)誤扶镀。蕴侣,這個(gè)錯(cuò)誤會有很多種情況,比較難查臭觉。我的app上導(dǎo)致這個(gè)狀態(tài)的原因是:

{
    "nativeStackAndroid":[{"lineNumber":49,"file":"CodePush.java","methodName":"h","class":"com.microsoft.codepush.react.a"},{"lineNumber":25,"file":"CodePushNativeModule.java","methodName":"a","class":"com.microsoft.codepush.react.CodePushNativeModule$c"},{"lineNumber":3,"file":"CodePushNativeModule.java","methodName":"doInBackground","class":"com.microsoft.codepush.react.CodePushNativeModule$c"},{"lineNumber":389,"file":"AsyncTask.java","methodName":"call","class":"android.os.AsyncTask$3"},{"lineNumber":266,"file":"FutureTask.java","methodName":"run","class":"java.util.concurrent.FutureTask"},{"lineNumber":1167,"file":"ThreadPoolExecutor.java","methodName":"runWorker","class":"java.util.concurrent.ThreadPoolExecutor"},{"lineNumber":641,"file":"ThreadPoolExecutor.java","methodName":"run","class":"java.util.concurrent.ThreadPoolExecutor$Worker"},{"lineNumber":929,"file":"Thread.java","methodName":"run","class":"java.lang.Thread"}],
    "userInfo":null,
    "message":"Error in getting binary resources modified time",
    "code":"EUNSPECIFIED"
}

解決方式是在 android/app/build.gradle 的 defaultConfig 中增加:
原文

resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())

然后重新編譯打包給Android機(jī)安裝昆雀,然后再重新改代碼,進(jìn)行發(fā)布測試熱更新

總結(jié):

1蝠筑、使用 npm 安裝 react-native-code-push 依賴
2狞膘、更改android的原生代碼進(jìn)行codePush連線
3、使用 微軟管理平臺 創(chuàng)建app
4什乙、使用 appcenter-cli 進(jìn)行指令管控
5挽封、使用 react-native-code-push 進(jìn)行編碼更新
6、發(fā)布更新測試
7臣镣、解決更新失敗的問題

以上是codePush一個(gè)簡單實(shí)用辅愿,如想更詳細(xì)更多功能智亮,建議查看官網(wǎng)文檔;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末点待,一起剝皮案震驚了整個(gè)濱河市鸽素,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌亦鳞,老刑警劉巖馍忽,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異燕差,居然都是意外死亡遭笋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門徒探,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓦呼,“玉大人,你說我怎么就攤上這事测暗⊙氪” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵碗啄,是天一觀的道長质和。 經(jīng)常有香客問我,道長稚字,這世上最難降的妖魔是什么饲宿? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮胆描,結(jié)果婚禮上瘫想,老公的妹妹穿的比我還像新娘。我一直安慰自己昌讲,他們只是感情好国夜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著短绸,像睡著了一般车吹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸠按,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天礼搁,我揣著相機(jī)與錄音,去河邊找鬼目尖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扎运,可吹牛的內(nèi)容都是我干的瑟曲。 我是一名探鬼主播饮戳,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼洞拨!你這毒婦竟也來了扯罐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤烦衣,失蹤者是張志新(化名)和其女友劉穎歹河,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體花吟,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秸歧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了衅澈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片键菱。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖今布,靈堂內(nèi)的尸體忽然破棺而出经备,到底是詐尸還是另有隱情,我是刑警寧澤部默,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布侵蒙,位于F島的核電站,受9級特大地震影響傅蹂,放射性物質(zhì)發(fā)生泄漏蘑志。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一贬派、第九天 我趴在偏房一處隱蔽的房頂上張望急但。 院中可真熱鬧,春花似錦搞乏、人聲如沸波桩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镐躲。三九已至,卻和暖如春侍筛,著一層夾襖步出監(jiān)牢的瞬間萤皂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工匣椰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留裆熙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像入录,于是被迫代替她去往敵國和親蛤奥。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容