React Native -Code Push 筆記

CodePush簡介

CodePush 是微軟提供的一套用于熱更新 React Native 和 Cordova 應用的服務赂毯。
CodePush 是提供給 React Native 和 Cordova 開發(fā)者直接部署移動應用更新給用戶設備的云服務脊僚。CodePush 作為一個中央倉庫,開發(fā)者可以推送更新 (JS, HTML, CSS and images)柄冲,應用可以從客戶端 SDK 里面查詢更新吻谋。CodePush 可以讓應用有更多的可確定性,也可以讓你直接接觸用戶群现横。在修復一些小問題和添加新特性的時候漓拾,不需要經(jīng)過二進制打包,可以直接推送代碼進行實時更新戒祠。

第一步 安裝CodePush終端

npm install -g code-push-cli

第二步 注冊登錄

code-push register
code-push login

注冊登錄的時候會打開瀏覽器 這個時候選擇相應的第三方登錄認證就好,我覺得每個程序員基本都會選擇github
接著拷貝注冊得到的token,復制到終端,按回車鍵登錄即可
登錄成功后可以看到如下內(nèi)容:

Successfully logged-in. Your session file was written to /Users/hfmoney/.code-push.config. You can run the code-push logout command at any time to delete this file and terminate your session.

第三步 安裝Code-Push SDK

以下集成以RNPM方式集成 個人覺得比較方便
在終端cd到你的RN項目目錄下

npm install --save react-native-code-push@latest
react-native link react-native-code-push

第四步 添加你的項目 (以下以<appName>代替你的項目名稱)

運行

code-push app add <appName> ios react-native 

來創(chuàng)建iOS端的App,
或者運行

code-push app add <appName> android react-native

創(chuàng)建Android端的App骇两。
成功后可以看到:


548793-359b4e1bd9f0cdc4.png

相關(guān)命令還有如下:

Usage: code-push app <command>
命令:
  add       創(chuàng)建一個新的App
  remove    刪除App
  rm        刪除App
  rename    重命名已經(jīng)存在App
  list      列出與你賬戶關(guān)聯(lián)的所有App
  ls        列出與你賬戶關(guān)聯(lián)的所有App
  transfer  將一個App的所有權(quán)轉(zhuǎn)讓給另一個帳戶

第五步 在項目中集成Code Push

因本人是iOS開發(fā)者,故而下面安卓項目的集成為網(wǎng)上資料查得,未經(jīng)驗證,如有紕漏,還望指正.

iOS端集成

1.使用Xcode打開項目,Xcode的項目導航視圖中的PROJECT下選擇你的項目姜盈, 選擇Info頁簽 低千,在Configurations節(jié)點下單擊 + 按鈕 ,選擇Duplicate "Release Configaration , 輸入Staging示血。


1496288208995.jpg.png

2.在build Settings頁簽中單擊 + 按鈕然后選擇添加User-Defined Setting棋傍,然后輸入CODEPUSH_KEY(名稱隨意),然后填入deployment key难审。


[圖片上傳中...(1496288455133.jpg.png-7d4e10-1528962850840-0)]
1496288455133.jpg.png

3.打開 Info.plist文件瘫拣,在CodePushDeploymentKey中輸入$(CODEPUSH_KEY),并修改Bundle versions為三位告喊,如下圖


1496288738755.jpg.png

Android端集成

1.在 android/app/build.gradle文件里面添如下代碼

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

2.然后在/android/settings.gradle中添加如下代碼:

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

3.運行 code-push deployment -k ls <appName>獲取 部署秘鑰麸拄。默認的部署名是 staging,所以 部署秘鑰(deployment key ) 就是 staging黔姜。

4.添加配置拢切。當APP啟動時我們需要讓app向CodePush咨詢JS bundle的所在位置,這樣CodePush就可以控制版本秆吵。更新 MainApplication.java文件:

public class MainApplication extends Application implements ReactApplication {
  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    protected boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }
    @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)
      );
    }
  };
  @Override
  public ReactNativeHost getReactNativeHost() {
      return mReactNativeHost;
  }
}

5.在上述代碼中我們在創(chuàng)建CodePush實例的時候需要設置一個deployment-key,因為deployment-key分生產(chǎn)環(huán)境與測試環(huán)境兩種,所以建議大家在build.gradle中進行設置失球。在build.gradle中的設置方法如下:

 buildTypes {
        debug{
            //省略了其他配置
            buildConfigField "String", "CODEPUSH_KEY", '""'
        }
        releaseStaging {
            buildConfigField "String", "CODEPUSH_KEY", '"此處填寫Staging key"'
        }
        release {
            //省略了其他配置
            buildConfigField "String", "CODEPUSH_KEY", '"此處填寫Production key"'
        }
    }

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

code_push_key_production=erASzHa1-wTdODdPJDh6DBF2Jwo94JFH08Kvb
code_push_key_staging=mQY75RkFbX6SiZU1kVT1II7OqWst4JFH08Kvb

然后在就可以在android/app/build.gradle可以通過下面方式來引用它了:

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
android {
    ...
    buildTypes {
        debug {
            ...
            // CodePush updates should not be tested in Debug mode
            ...
        }

        releaseStaging {
            ...
            buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_production")+'"'
            ...
        }

        release {
            ...
            buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_staging")+'"'
            ...
        }
    }
    ...
}

在android/app/build.gradle設置好deployment-key之后呢,我們就可以這樣使用了:

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

6.修改VersionName
在 android/app/build.gradle中有個 android.defaultConfig.versionName屬性,我們需要把 應用版本改成 三位帮毁,比如1.0,需要修改成1.0.0

android{
    defaultConfig{
        versionName "1.0.0"
    }
}

第六步 JS代碼

最為簡單的使用方式在React Natvie的根組件的componentDidMount方法中通過
codePush.sync()(需要先導入codePush包:import codePush from 'react-native-code-push')方法檢查并安裝更新豺撑,如果有更新包可供下載則會在重啟后生效烈疚。不過這種下載和安裝都是靜默的,即用戶不可見聪轿。如果需要用戶可見則需要額外的配置爷肝。具體可以參考codePush官方API文檔,下面是個人的一些實踐過的配置:

codePush.sync({
      updateDialog: {
        appendReleaseDescription: true,
        descriptionPrefix:'\n\n更新內(nèi)容:\n',
        title:'更新',
        mandatoryUpdateMessage:'',
        mandatoryContinueButtonLabel:'更新',
      },
      mandatoryInstallMode:codePush.InstallMode.IMMEDIATE,
      deploymentKey: CODE_PUSH_PRODUCTION_KEY,
    });
sync為自動模式陆错,調(diào)用此方法CodePush會幫你完成一系列的操作灯抛。其它方法都是在手動模式下使用的。
codePush.sync 
codePush.sync(options: Object, syncStatusChangeCallback: function(syncStatus: Number), downloadProgressCallback: function(progress: DownloadProgress)): Promise<Number>; 
通過調(diào)用該方法CodePush會幫我們自動完成檢查更新音瓷,下載对嚼,安裝等一系列操作。除非我們需要自定義UI表現(xiàn)绳慎,不然直接用這個方法就可以了纵竖。
sync方法,提供了如下屬性以允許你定制sync方法的默認行為

deploymentKey (String): 部署key杏愤,指定你要查詢更新的部署秘鑰靡砌,默認情況下該值來自于Info.plist(Ios)和MianActivity.java(Android)文件,你可以通過設置該屬性來動態(tài)查詢不同部署key下的更新珊楼。
installMode (codePush.InstallMode): 安裝模式通殃,用在向CodePush推送更新時沒有設置強制更新(mandatory為true)的情況下,默認codePush.InstallMode.ON_NEXT_RESTART即下一次啟動的時候安裝厕宗。
mandatoryInstallMode (codePush.InstallMode):強制更新,默認codePush.InstallMode.IMMEDIATE画舌。
minimumBackgroundDuration (Number):該屬性用于指定app處于后臺多少秒才進行重啟已完成更新堕担。默認為0。該屬性只在installMode為InstallMode.ON_NEXT_RESUME情況下有效骗炉。
updateDialog (UpdateDialogOptions) :可選的照宝,更新的對話框,默認是null,包含以下屬性
appendReleaseDescription (Boolean) - 是否顯示更新description句葵,默認false
descriptionPrefix (String) - 更新說明的前綴厕鹃。 默認是” Description: “
mandatoryContinueButtonLabel (String) - 強制更新的按鈕文字. 默認 to “Continue”.
mandatoryUpdateMessage (String) - 強制更新時,更新通知. Defaults to “An update is available that must be installed.”.
optionalIgnoreButtonLabel (String) - 非強制更新時乍丈,取消按鈕文字. Defaults to “Ignore”.
optionalInstallButtonLabel (String) - 非強制更新時剂碴,確認文字. Defaults to “Install”.
optionalUpdateMessage (String) - 非強制更新時,更新通知. Defaults to “An update is available. Would you like to install it?”.
title (String) - 要顯示的更新通知的標題. Defaults to “Update available”.

或者是在用戶點擊檢查更新按鈕后進行檢查轻专,如果有更新則彈出提示框讓用戶選擇是否更新忆矛,如果用戶點擊立即更新按鈕,則會進行安裝包的下載(實際上這時候應該顯示下載進度请垛,這里省略了)下載完成后會立即重啟并生效(也可配置稍后重啟)

let deploymentKey = '這里寫入你的key值'
codePush.checkForUpdate(deploymentKey).then((update) => {
                            if (!update) {
                                Alert.alert("提示", "已是最新版本--", [
                                    {
                                        text: "Ok", onPress: () => {
                                        console.log("點了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.");
                                    }
                                );
                            }
                    })

第七步 打包

首先 要打包bundle 以下以iOS端為例 在項目中的ios目錄下 新建一個bundle文件夾,然后在終端運行(注意是項目的路徑下,不是ios的路徑下)

react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle

react-native bundle --entry-file 啟動文件 --platform 平臺 --dev 是否調(diào)試 --bundle-output 打包js輸出文件 --assets-dest 資源輸出目錄
然后在xcode中 加入bundle文件夾 右鍵菜單 點擊Add Files to'<appName>'把文件夾加入到項目中

此外宗收,還需要對AppDelegate.m文件進行修改:

//    #ifdef DEBUG
//        jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
//    #else
        jsCodeLocation = [CodePush bundleURL];
//    #endif

否則更新重啟后還是舊版的App漫拭。

然后在用xcode打包上架或者發(fā)測試包

第八步 更新

code-push release-react <appName> <platform>

例如

code-push release-react <appName>-iOS ios
code-push release-react <appName>-Android android

詳細操作可以是

code-push release-react <appName>-iOS ios  --t 1.0.0 --dev false --d Production --des "1.優(yōu)化操作流程" --m true

其中參數(shù)--t為二進制(.ipa與apk)安裝包的的版本;--dev為是否啟用開發(fā)者模式(默認為false)混稽;--d是要發(fā)布更新的環(huán)境分Production與Staging(默認為Staging)采驻;--des為更新說明;--m 是強制更新匈勋。

 code-push release <appName> <bundle目錄> <targetBinaryVersion>
[--deploymentName <deploymentName>]默認staging
[--description <description>]更新描述(string)默認為null
[--mandatory]是否強制更新礼旅,默認false
[--disabled] 該版本客戶端是否可以獲得更新,默認為false
[--rollout]此更新推送的用戶的百分比(string)洽洁,默認值為null

修改更新

code-push patch <appName> <deploymentName>

--label, -l 指定標簽版本更新痘系,默認最新版本 [string] [默認值: null]
--description, --des 描述 [string] [默認值: null]
--disabled, -x 該修改更新,客戶端是否可以獲得更新 [boolean] [默認值: null]
--mandatory, -m 是否強制更新 [boolean] [默認值: null]
--rollout, -r 此更新推送用戶的百分比饿自,此值僅可以從先前的值增加碎浇。 [string] [默認值: null]

示例:
code-push patch <appName> Production --des "Updated description" -r 50 修改"<appName>"的"Production"部署中最新更新的描述 ,并且更新推送范圍為50%
code-push patch <appName> Production -l v3 --des "Updated description for v3" 修改"<appName>"的"Production"部署中標簽為v3的更新的描述

總結(jié)

CodePush也存在著一些缺點:

服務器在國外璃俗,在國內(nèi)訪問奴璃,網(wǎng)速不是很理想。
其升級服務器端程序并不開源的城豁,后期微軟會不會對其收費還是個未知數(shù)苟穆。
如果在沒有更好的動態(tài)更新React Native應用的方案的情況下,并且這些問題還在你的接受范圍之內(nèi)的話,那么CodePush可以作為動態(tài)更新React Native應用的一種選擇雳旅。
后期會向大家分享不采用CodePush跟磨,自己搭建服務器并實現(xiàn)React Native應用的動態(tài)更新相關(guān)的方案。

官方文檔

code push github: https://github.com/Microsoft/react-native-code-push
code push官網(wǎng):http://microsoft.github.io/code-push/
code push cli手冊:http://microsoft.github.io/code-push/docs/cli.html
code push javaScript Api: https://github.com/Microsoft/react-native-code-push/blob/master/docs/api-js.md#codepush

參考相關(guān)

http://www.reibang.com/p/9e3b4a133bcc
http://www.reibang.com/p/67de8aa052af
http://www.reibang.com/p/e1a9302cfdff
https://blog.csdn.net/sinat_17775997/article/details/74016662

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末攒盈,一起剝皮案震驚了整個濱河市抵拘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌型豁,老刑警劉巖僵蛛,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異迎变,居然都是意外死亡充尉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門衣形,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驼侠,“玉大人,你說我怎么就攤上這事谆吴〉乖矗” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵句狼,是天一觀的道長笋熬。 經(jīng)常有香客問我,道長鲜锚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任苫拍,我火速辦了婚禮芜繁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绒极。我一直安慰自己骏令,他們只是感情好,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布垄提。 她就那樣靜靜地躺著榔袋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铡俐。 梳的紋絲不亂的頭發(fā)上凰兑,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機與錄音审丘,去河邊找鬼吏够。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的锅知。 我是一名探鬼主播播急,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼售睹!你這毒婦竟也來了桩警?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤昌妹,失蹤者是張志新(化名)和其女友劉穎捶枢,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捺宗,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡柱蟀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蚜厉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片长已。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖昼牛,靈堂內(nèi)的尸體忽然破棺而出术瓮,到底是詐尸還是另有隱情,我是刑警寧澤贰健,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布胞四,位于F島的核電站,受9級特大地震影響伶椿,放射性物質(zhì)發(fā)生泄漏辜伟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一脊另、第九天 我趴在偏房一處隱蔽的房頂上張望导狡。 院中可真熱鬧,春花似錦偎痛、人聲如沸旱捧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枚赡。三九已至,卻和暖如春谓谦,著一層夾襖步出監(jiān)牢的瞬間贫橙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工反粥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留料皇,地道東北人谓松。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像践剂,于是被迫代替她去往敵國和親鬼譬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

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