RN熱更新——codepush

一、安裝注冊(cè)code-push

1.安裝code-push
$ npm install -g code-push-cli
2.注冊(cè)賬號(hào)
$ code-push register

這時(shí)候會(huì)自動(dòng)啟動(dòng)瀏覽器打開(kāi)網(wǎng)頁(yè)并提供一個(gè)codePush AccessKey鳍征,然后命令行里出現(xiàn)需要輸入access key

Enter your access key:

輸入access key?登錄

3.添加一個(gè)CodePush應(yīng)用(myProject是應(yīng)用名字)
$ code-push app add ?myProject

出現(xiàn)

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

如上有兩個(gè)發(fā)布鍵值。一個(gè)Production是對(duì)應(yīng)生產(chǎn)環(huán)境的,二Staging是對(duì)應(yīng)開(kāi)發(fā)環(huán)境的。當(dāng)然我們還可以添加其他的發(fā)布鍵值伤靠。
這個(gè)值在后面我們集成工程里面要用到。

二、react-native應(yīng)用接入code-push

1.安裝react-native-code-push

在項(xiàng)目根目錄運(yùn)行

$ npm install react-native-code-push --save
2.cocoapods導(dǎo)入code-push
  • ios

修改Podfile文件宴合,添加:

  pod 'CodePush', :path => './node_modules/react-native-code-push'

運(yùn)行

  $ pod install
  • android

  • RNPM
    安裝 RNPM(依次運(yùn)行)
    如果 React Native 版本 >= 0.27 (因?yàn)?rnpm link 已經(jīng)被合并到React Native CLI)

     $ react-native link react-native-code-push
    

否則
$ npm i -g rnpm
$ rnpm link react-native-code-push

  • 手動(dòng)
    在android/settings.gradle文件里添加
    include ':app'
    include ':react-native-code-push'
    project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
    在android/app/build.gradle文件里添加
    dependencies {
    ...
    compile project(':react-native-code-push')
    }
    在android/app/build.gradle文件里添加
    ...
    apply from: "../../node_modules/react-native/react.gradle"
    apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
    ...
    修改MainApplication.java文件
    ...
    // 1. Import the plugin class.
    import com.microsoft.codepush.react.CodePush;

     // public class MainActivity extends ReactActivity {                                     // For React Native v0.19 - v0.28
     public class MainApplication extends Application implements ReactApplication {        // For React Native >= 0.29
    
         private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
             ...
             // 2. Override the getJSBundleFile method in order to let
             // the CodePush runtime determine where to get the JS
             // bundle location from on each app start
             @Override protected String getJSBundleFile() {
                 return CodePush.getJSBundleFile();
             }
    
             @Override protected List<ReactPackage> getPackages() {
                 // 3. Instantiate an instance of the CodePush runtime and add it to the list of
                 // existing packages, specifying the right deployment key. If you don't already
                 // have it, you can run "code-push deployment ls <appName> -k" to retrieve your key.
                 return Arrays.<ReactPackage>asList(
                     new MainReactPackage(),
                     new CodePush("deployment-key-here", MainApplication.this, BuildConfig.DEBUG)
                 );
             }
         };
     }
    

在android/app/build.gradle文件中(應(yīng)用版本codepush需要三位數(shù))
android{
defaultConfig{
versionName "1.0.0"
}
}
Background React Instances
This section is only necessary if you're explicitly launching a React Native instance without an Activity
(for example, from within a native push notification receiver). For these situations, CodePush must be told how to find your React Native instance.*
In order to update/restart your React Native instance, CodePush must be configured with a ReactInstanceHolder
before attempting to restart an instance in the background. This is usually done in your Application
implementation.
修改MainApplication.java文件
// For React Native >= v0.29
...
// 1. Declare your ReactNativeHost to extend ReactInstanceHolder.
// ReactInstanceHolder is a subset of ReactNativeHost, so no additional implementation is needed.
import com.microsoft.codepush.react.ReactInstanceHolder;
public class MyReactNativeHost extends ReactNativeHost implements ReactInstanceHolder {
// ... usual overrides
}
// 2. Provide your ReactNativeHost to CodePush.
public class MainApplication extends Application implements ReactApplication {

        private final MyReactNativeHost mReactNativeHost = new MyReactNativeHost(this);

        @Override public void onCreate() {
            CodePush.setReactInstanceHolder(mReactNativeHost);
            super.onCreate();
        }
    }

    // For React Native v0.19 - v0.28
    // 1. Provide your ReactNativeHost to CodePush.
    public class MainApplication extends Application {
        // ... initialize your instance holder
        @Override public void onCreate() {
            CodePush.setReactInstanceHolder(mReactNativeHost);
            super.onCreate();
        }
    }

以上的操作焕梅,即可成功集成CodePush。

3.配置相關(guān)文件
  • IOS
1.修改js程序入口文件

RN應(yīng)用是appDelegate.m
原生應(yīng)用是ReactView.m

  #ifdef DEBUG
      jsCodeLocation = [NSURL URLWithString:@"http://192.168.1.103:8081/index.ios.bundle?platform=ios"];
  #else
      jsCodeLocation = [CodePush bundleURLForResource:@"index"];
  #endif
2.修改info.plist文件
  <key>CodePushDeploymentKey</key>
  <string>前面添加應(yīng)用得到的發(fā)布key(注意這里要選擇是正式版的key還是測(cè)試版的key卦洽,不是發(fā)布到appstore可以用Staging的key)</string>

命令行里面輸入

$ code-push

可以看到code-push各個(gè)命令

三贞言、更新策略(js)

1、導(dǎo)入react-native-code-push

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

2阀蒂、策略

默認(rèn)情況下该窗,CodePush會(huì)在app每次啟動(dòng)的時(shí)候去檢測(cè)是否有更新,如果有蚤霞,app會(huì)自動(dòng)下載并在下次打開(kāi)app時(shí)安裝

class MyApp extends Component {}
MyApp = codePush(MyApp);

// For ES7
import codePush from "react-native-code-push";

@codePush
class MyApp extends Component {}

每次打開(kāi)app時(shí)檢測(cè)更新并下載酗失,下次打開(kāi)app時(shí)安裝

// Sync for updates everytime the app resumes.
class MyApp extends Component {}
MyApp = codePush({
    checkFrequency: codePush.CheckFrequency.ON_APP_RESUME,
    installMode: codePush.InstallMode.ON_NEXT_RESUME
})(MyApp);

實(shí)時(shí)檢測(cè)更新并下載,下載完成后立即安裝

// Active update, which lets the end user know
// about each update, and displays it to them
// immediately after downloading it
class MyApp extends Component {}
MyApp = codePush({
    updateDialog: true,
    installMode: codePush.InstallMode.IMMEDIATE
})(MyApp);

記錄app檢測(cè)昧绣、下載规肴、安裝的狀態(tài)(可以實(shí)現(xiàn)進(jìn)度條當(dāng)做友好提示)

// Make use of the event hooks to keep track of
// the different stages of the sync process.
class MyApp extends Component {
    codePushStatusDidChange(status) {
        switch(status) {
            case codePush.SyncStatus.CHECKING_FOR_UPDATE:
                console.log("Checking for updates.");
                break;
            case codePush.SyncStatus.DOWNLOADING_PACKAGE:
                console.log("Downloading package.");
                break;
            case codePush.SyncStatus.INSTALLING_UPDATE:
                console.log("Installing update.");
                break;
            case codePush.SyncStatus.UP_TO_DATE:
                console.log("Installing update.");
                break;
            case codePush.SyncStatus.UPDATE_INSTALLED:
                console.log("Update installed.");
                break;
        }
    }
    codePushDownloadDidProgress(progress) {
        console.log(progress.receivedBytes + " of " + progress.totalBytes + " received.");
    }
}
MyApp = codePush(MyApp);
CodePushOptions
  • checkFrequency (codePush.CheckFrequency) - 檢測(cè)更新的時(shí)機(jī)
方法 描述
ON_APP_START(0) app啟動(dòng)后
ON_APP_RESUME(1) app從后臺(tái)切換過(guò)來(lái)時(shí)
ON_APP_MANUAL(2) 不能自動(dòng)檢測(cè),只有在調(diào)用 codePush.sync()時(shí)觸發(fā)
  • deploymentKey (String) - 部署key夜畴,可以在js里動(dòng)態(tài)修改
  • installMode (codePush.InstallMode) - 安裝時(shí)機(jī)
方法 描述
IMMEDIATE(0) 立即安裝并重啟app
ON_NEXT_RESTART(1) 下次啟動(dòng)app時(shí)安裝
ON_NEXT_RESUME(2) app從后臺(tái)切換過(guò)來(lái)時(shí)安裝
  • mandatoryInstallMode (codePush.InstallMode) - 同codePush.InstallMode.IMMEDIATE
  • minimumBackgroundDuration (Number) - app在后臺(tái)切換過(guò)來(lái)安裝的最小秒數(shù)拖刃,配合installMode.ON_NEXT_RESUME使用
  • updateDialog (UpdateDialogOptions) - 對(duì)話框
屬性 描述
appendReleaseDescription(Boolean) 是否發(fā)送通知消息顯示給用戶,默認(rèn)為false
descriptionPrefix(String) 描述的前綴斩启,默認(rèn)為“Description:”
mandatoryContinueButtonLabel(String) 強(qiáng)制更新下的繼續(xù)按鈕的文本,默認(rèn)為“Continue”
mandatoryUpdateMessage(String) 強(qiáng)制更新的通知消息文本醉锅,默認(rèn)為“An update is available that must be installed.”
optionalIgnoreButtonLabel(String) 忽略按鈕的文本兔簇,默認(rèn)為“Ignore”
optionalUpdateMessage(String) 通知消息文本,默認(rèn)為“An update is available. Would you like to install it?”
title(String) 對(duì)話框的標(biāo)題硬耍,默認(rèn)為“Update available”
optionalUpdateMessage 通知消息文本

codePushStatusDidChange

用于監(jiān)聽(tīng)檢測(cè)垄琐、下載、安裝的狀態(tài)——SyncStatus

方法 描述
CHECKING_FOR_UPDATE (0) 查詢更新
AWAITING_USER_ACTION (1) 有更新并且有對(duì)話框顯示給最終用戶(這只是適用updateDialog時(shí)使用)
DOWNLOADING_PACKAGE (2) 正在下載
INSTALLING_UPDATE (3) 正在安裝
UP_TO_DATE (4) 更新完成
UPDATE_IGNORED (5) 提示更新后经柴,用戶選擇了忽視(這只是適用updateDialog時(shí)使用)
UPDATE_INSTALLED (6) 已經(jīng)安裝,并將運(yùn)行syncStatusChangedCallback函數(shù)返回后立即或下次啟動(dòng)更新狸窘,在InstallMode SyncOptions中指定。
SYNC_IN_PROGRESS (7) 有一個(gè)正在進(jìn)行的同步操作運(yùn)行,防止當(dāng)前的調(diào)用被執(zhí)行坯认。
UNKNOWN_ERROR (-1) 同步操作遇到了一個(gè)未知錯(cuò)誤翻擒。

codePushDownloadDidProgress

下載進(jìn)度

返回參數(shù) 描述
totalBytes (number) 預(yù)計(jì)大小
receivedBytes(number) 已下載大小

disallowRestart/allowRestart

class OnboardingProcess extends Component {
  ...
  componentWillMount() {
    // Ensure that any CodePush updates which are
    // synchronized in the background can't trigger
    // a restart while this component is mounted. codePush.disallowRestart();
  }
  componentWillUnmount() {
    // Reallow restarts, and optionally trigger
    // a restart if one was currently pending.
    codePush.allowRestart();
  }
  ...
}

四、發(fā)布版本

1牛哺、打包
$ code-push release myProject ./bundle/index.jsbundle 1.20.1 --mandatory true

myProject代表我們要更新的項(xiàng)目名稱陋气,就是前面我們注冊(cè)的index.jsbundle是我們要更新的內(nèi)容,1.20.1是我們?cè)赼ppstore發(fā)布的版本號(hào)引润,注意這個(gè)地方是我們程序二進(jìn)制文件的版本號(hào)巩趁,其實(shí)這句命令就是:更新myProject 1.20.1的版本二進(jìn)制文件,只有1.20.1的版本才能收到更新淳附。最后面的參數(shù)是是否強(qiáng)制更新议慰。這段命令沒(méi)有指定更新的環(huán)境是正式環(huán)境還是測(cè)試環(huán)境蠢古,默認(rèn)的是測(cè)試環(huán)境,如果要發(fā)布到正式環(huán)境需要指定一下

 code-push release wanna ./bundle/index.jsbundle 1.20.1 -d "Production" --mandatory true别凹。 

后面還可以在后面添加參數(shù)比如1.20.1版本的多少用戶可以更新–rollout 20草讶,代表百分之20的myProject 1.20.1的用戶可以收到這個(gè)更新

2、修改發(fā)布后版本的參數(shù)

比如上面番川,我們發(fā)布更新到了1.20.1的測(cè)試版本到涂,更新百分之20的用戶,可是我們發(fā)布完成之后颁督,想更新百分之30的用戶:

$ code-push patch wanna 1.20.1 --rollout 20

code-push for redux -- react-native-code-push-saga

注意:

  • 蘋(píng)果不允許應(yīng)用內(nèi)有彈框提示更新
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末践啄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子沉御,更是在濱河造成了極大的恐慌屿讽,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吠裆,死亡現(xiàn)場(chǎng)離奇詭異伐谈,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)试疙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)诵棵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人祝旷,你說(shuō)我怎么就攤上這事履澳。” “怎么了怀跛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵距贷,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我吻谋,道長(zhǎng)忠蝗,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任漓拾,我火速辦了婚禮阁最,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘骇两。我一直安慰自己闽撤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布脯颜。 她就那樣靜靜地躺著哟旗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闸餐,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天饱亮,我揣著相機(jī)與錄音,去河邊找鬼舍沙。 笑死近上,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拂铡。 我是一名探鬼主播壹无,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼感帅!你這毒婦竟也來(lái)了斗锭?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤失球,失蹤者是張志新(化名)和其女友劉穎岖是,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體实苞,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡豺撑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了黔牵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聪轿。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖猾浦,靈堂內(nèi)的尸體忽然破棺而出陆错,到底是詐尸還是另有隱情,我是刑警寧澤跃巡,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布危号,位于F島的核電站牧愁,受9級(jí)特大地震影響素邪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜猪半,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一兔朦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧磨确,春花似錦沽甥、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春恨诱,著一層夾襖步出監(jiān)牢的瞬間媳瞪,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工照宝, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛇受,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓厕鹃,卻偏偏與公主長(zhǎng)得像兢仰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子剂碴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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