react-native熱更新之code-push


文章部分內容參考:https://blog.csdn.net/qq_33323251/article/details/79437932

但是我在這個基礎上進行了補充

code-push已經遷移到 APP Center 

-------------- 

React Native的出現為移動開發領域帶來了兩大革命性的創新:

  1. 整合了移動端APP的開發,不僅縮短了APP的開發時間,也提高了APP的開發效率。
  2. 為移動APP動態更新提供了基礎。

本文將向大家分享React Natvie應用部署/動態更新方面的內容。

React Native支持大家用React Native技術開發APP,並打包生成一個APP。在動態更新方面React Native只是提供了動態更新的基礎,對將應用部署到哪里,如何進行動態更新並沒有支持的那么完善。好在微軟開發了CodePush,填補React Native 應用在動態更新方面的空白。CodePush 是微軟提供的一套用於熱更新 React Native 和 Cordova 應用的服務。下面將向大家分享如何使用CodePush實時更新你的應用,后期會分享不采用CodePush,如何自己去實現React Native應用熱更新。

CodePush簡介(https://appcenter.ms/

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

React Native應用程序由JavaScript文件和任何附帶圖像組成,這些圖像由打包程序捆綁在一起並作為特定於平台的二進制文件(即.ipa或.apk文件)的一部分進行分發。應用程序發布后,更新JavaScript代碼(例如修復錯誤,添加新功能)或圖像資產,需要您重新編譯和重新分發整個二進制文件,當然,這包括與商店相關的任何審核時間你要發布到。
CodePush插件通過使您的JavaScript和圖像與您發布到CodePush服務器的更新保持同步,有助於立即在最終用戶面前進行產品改進。通過這種方式,您的應用可以獲得離線移動體驗的好處,以及一旦可用,就可以獲得側面加載更新的“類似網絡”的敏捷性。這是雙贏的!
為了確保您的最終用戶始終擁有應用程序的正常版本,CodePush插件會維護以前更新的副本,以便在您意外推送包含崩潰的更新時,它可以自動回滾。這樣,您可以放心,在您有機會回滾服務器之前,您的新發布的敏捷性不會導致用戶被阻止。這是一個雙贏的局面!
注意:任何與本機代碼相關的產品更改(例如,修改AppDelegate.m / MainActivity.java文件,添加新插件)都無法通過CodePush分發,因此必須通過相應的商店進行更新。

 

CodePush 可以進行實時的推送代碼更新:

  • 直接對用戶部署代碼更新
  • 管理 Alpha,Beta 和生產環境應用
  • 支持 React Native 和 Cordova
  • 支持JavaScript 文件與圖片資源的更新

CodePush開源了react-native版本,react-native-code-push托管在GitHub上。

安裝與注冊CodePush

使用CodePush之前首先要安裝CodePush客戶端。本文以OSX 10.11.5作為平台進行演示。

安裝 CodePush CLI (CodePush CLI具體用法指南)

管理 CodePush 賬號需要通過 NodeJS-based CLI。
只需要在終端輸入 npm install -g code-push-cli,就可以安裝了。
安裝完畢后,輸入 code-push -v查看版本,如看到版本代表成功。
目前我的版本是 2.1.9

PS. 
npm為NodeJS的包管理器,如果你沒安裝NodeJS請先安裝。(關於nodejs、npm詳細講解及安裝

創建一個CodePush 賬號

在終端輸入code-push register,會打開如下注冊頁面讓你選擇授權賬號,其實也就是跳轉到官網https://appcenter.ms/sign-in

可以選擇用微軟賬號登錄或GitHub賬號登錄

通過之后,code-push會告訴你 “access key”,復制到終端完成注冊。

然后終端輸入code-push login進行登陸,登陸成功后,你的session文件將會寫在 /Users/你的用戶名/.code-push.config

登陆成功
登陸

PS.相關命令

  • code-push login 登陸
  • code-push loout 注銷
  • code-push access-key ls 列出登陸的token
  • code-push access-key rm <accessKye> 刪除某個 access-key

在CodePush服務器注冊app

為了讓CodePush服務器知道你的app,我們需要向它注冊app: 在終端輸入code-push app add <appName>即可完成注冊。

 code-push-add-app


注冊完成之后會返回一套deployment key,該key在后面步驟中會用到。

心得:如果你的應用分為Android和iOS版,那么在向CodePush注冊應用的時候需要注冊兩個App獲取兩套deployment key,如:


  
  
  
          
  1. code- push app add MyApp-Android
  2. code- push app add MyApp-iOS

PS.相關命令

  • code-push app add 在賬號里面添加一個新的app
  • code-push app remove 或者 rm 在賬號里移除一個app
  • code-push app rename 重命名一個存在app
  • code-push app list 或則 ls 列出賬號下面的所有app
  • code-push app transfer 把app的所有權轉移到另外一個賬號


 

集成CodePush SDK

Android

下面我們通過如下步驟在Android項目中集成CodePush。
第一步:在項目中安裝 react-native-code-push插件,終端進入你的項目根目錄然后運行
npm install --save react-native-code-push

第二步:在Android project中安裝插件。
CodePush提供了兩種方式:RNPM 和 Manual,本次演示所使用的是RNPM。
運行npm i -g rnpm,來安裝RNPM。

在React Native v0.27及以后版本RNPM已經被集成到了 React Native CL中,就不需要再進行安裝了。

第三步: 運行 rnpm link react-native-code-push。這條命令將會自動幫我們在anroid文件中添加好設置。iOS、Android都配好了 successful linked ,下面的步驟已經自動完成了你只檢查下就行。

         
          react-native-code-push has been successfully linked

在終端運行此命令之后,終端會提示讓你輸入deployment key,這是你只需將你的deployment Staging key輸入進去即可,如果不輸入則直接單擊enter跳過即可。

第四步: 在 android/app/build.gradle文件里面添如下代碼:


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

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


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

第五步: 運行 code-push deployment ls -k <appName>獲取 部署秘鑰。默認的部署名是 staging,所以 部署秘鑰(deployment key ) 就是 staging


 

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

 
        
public class MainApplication extends Application implements ReactApplication {

private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {

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


// 設置為 true 將不彈出 toast
private boolean SHUTDOWN_TOAST = false;
// 設置為 true 將不打印 log
private boolean SHUTDOWN_LOG = false;

@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}

@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RNFetchBlobPackage(),
new WeChatPackage(),
new UpdatePackage(),
new RNDeviceInfo(),
new RNI18nPackage(),
new RNCWebViewPackage(),
new RNGestureHandlerPackage(),
new WeChatPackage(),
new ReactVideoPackage(),
new VectorIconsPackage(),
new SplashScreenReactPackage(),
new LinearGradientPackage(),
new ImagePickerPackage(),
new JPushPackage(SHUTDOWN_TOAST, SHUTDOWN_LOG),
new CodePush(BuildConfig.CODE_PUSH_KEY, MainApplication.this, BuildConfig.DEBUG)
);
}

@Override
protected String getJSMainModuleName() {
return "index";
}
};

@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}

@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}

熱更新有兩張方案 中文社區提供的Pushy微軟提供CodePush

 

關於deployment-key的設置 (關於Grande

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

打開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中:


  
  
  
          
  1. CODE_PUSH_KEY_PRODUCTION="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
  2. CODE_PUSH_KEY_STAGING="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# gradle.properties專門用來配置全局鍵值對數據的
# 將它從git版本控制中排除不用擔心keystore文件等敏感信息泄漏
# BuildConfig或代碼中應用取值 ${KEY}
MYAPP_RELEASE_STORE_FILE=./keystores/release.keystore
MYAPP_RELEASE_KEY_ALIAS=release
MYAPP_RELEASE_STORE_PASSWORD=111111
MYAPP_RELEASE_KEY_PASSWORD=111111
VERSION_CODE=6
VERSION_NAME=1.0.0
CODE_PUSH_KEY_PRODUCTION="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
CODE_PUSH_KEY_STAGING="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 

 

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

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

第七步:修改versionName。
在 android/app/build.gradle中有個 android.defaultConfig.versionName屬性,我們需要把 應用版本改成 1.0.0(默認是1.0,但是codepush需要三位數)。


  
  
  
          
  1. android{
  2. defaultConfig{
  3. versionName "1.0.0"
  4. }
  5. }

至此Code Push for Android的SDK已經集成完成。

iOS

CodePush官方提供RNPM、CocoaPods與手動三種在iOS項目中集成CodePush的方式,接下來我就以RNPM的方式來講解一下如何在iOS項目中集成CodePush。

第一步:在項目中安裝react-native-code-push插件,終端進入你的項目根目錄然后運行


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

第二步: 運行 rnpm link react-native-code-push。這條命令將會自動幫我們在ios中添加好設置。

在終端運行此命令之后,終端會提示讓你輸入deployment key,這是你只需將你的deployment Staging key輸入進去即可,如果不輸入則直接單擊enter跳過即可。

關於deployment-key的設置

在我們想CodePush注冊App的時候,CodePush會給我們兩個deployment-key分別是在生產環境與測試環境時使用的,我們可以通過如下步驟來設置deployment-key。

----------------------

先講一下Xcode配置相關知識


配置分為Project和Target,一個Project可以包含多個Target,每個Target可以定義不同的配置,也就是Project的配置整個項目通用,Target的配置優先級較高,是集成自Project 

例如:公司有兩套環境 測試test 和 線上prod,那么我可以定義兩個 superbuy-test 、superbuy-prod (這是一種解決方案當然還有其他的做法,例如預編譯宏 BETA 等...)

rnpm link之后code-push-key配置在了Info.plist文件中(Info.plist相當於Android中的清單文件AndroidMainFest.xml)

如何讓code-push-key自動區分測試環境還是正式環境能? 

Xcode中 User Defined 登場

User Defined 是一個Xcode中十分強大而不常使用的功能,它能夠配置一些你在Interface Builder 中不能配置的屬性,進而很大程度上提高開發效率。在項目中使用User Defined Setting可以定義一些Xcode編譯使用的宏配置,為了實現App的一些常量或屬性值在不同運行環境下配置不同,可以在User Defined Setting中定義一些有關應用程序的配置。 

問題來了:是配置在Project中還是Target中?

答案是都可以,其實你copy一個target,會生成兩個Info.plist文件,所以我選擇配置在target中

 

---------------------- 

1.用Xcode 打開項目 ➜ Xcode的項目導航視圖中的PROJECT下選擇你的Target ➜

選擇Build Settings頁簽 ➜ 單擊 + 按鈕然后選擇添加User-Defined Setting


 

添加User-Defined-Setting

2.然后輸入CODE_PUSH_KEY(名稱可以自定義)


設置    Staging deployment key

提示:你可以通過code-push deployment ls -k <APP_NAME> -k命令來查看deployment key。

3.打開 Info.plist文件,在CodePushDeploymentKey列的Value中輸入$(CODE_PUSH_KEY)

引用CODEPUSH_KEY 

 

4.AppDelegate設置jsLocationPath,由於是兼容pushy和code-push,所以兩種熱更新方式可以切換

怎么切換?添加預編譯宏 


配置 IS_CODE_PUSH=1

but 編譯失敗


有兩個文件一樣的命名,因為Objective-C一直沒有Java中Package的概念,所以對於命名空間開發者都很無奈,都是通過加前綴來區別保證不同名

這是由於Pushy和code-push都引用到了SSZipArchive(三方解壓神器SSZipArchive


使用CodePush進行熱更新

App Store/Play Store審核政策

雖然Google Play和內部分布式應用程序(例如Enterprise,Fabric,HockeyApp)對如何使用CodePush發布更新沒有限制,但iOS App Store及其相應的指南在您將解決方案集成到您的內容之前,應該注意更准確的規則。應用。

3.3.2段,自2015年以來,Apple開發者計划許可協議完全允許對JavaScript和資產進行無線更新 - 在此處可下載的最新版本(20170605)中這一裁決更為廣泛:

解釋的代碼可以下載到應用程序,但只要這樣的代碼:(a)不會通過提供與提交給App的應用程序的預期和廣告目的不一致的特性或功能來改變應用程序的主要目的。存儲,(b)不為其他代碼或應用程序創建商店或店面,並且(c)不繞過操作系統的簽名,沙箱或其他安全功能。

CodePush允許您完全遵從這些規則,只要您推送的更新不會使您的產品與其原始App Store批准的意圖明顯不同。

為了進一步遵守Apple的指導原則,我們建議App Store分發的應用程序updateDialog在調用時不啟用該選項sync,因為在App Store Review Guidelines中,它寫成:

應用不得強制用戶對應用評分,審核應用,下載其他應用或其他類似操作,以便訪問應用的功能,內容或使用。

這不一定是這種情況updateDialog,因為它不會強迫用戶下載新版本,但至少如果你決定展示它,你應該知道這個裁決。

設置更新策略

在使用CodePush更新你的應用之前需要,先配置一下更新控制策略,即:

  • 什么時候檢查更新?(在APP啟動的時候?在設置頁面添加一個檢查更新按鈕?)
  • 什么時候可以更新,如何將更新呈現給終端用戶?

最簡單的方式是在根component中進行上述策略控制。

  1. 在 js中加載 CodePush模塊:import codePush from 'react-native-code-push' 
  2. 在 componentDidMount中調用 sync方法,后台請求更新 codePush.sync()
// 第一種:
codePush.sync();

// 第二種:
codePush.sync({
    updateDialog: false,
    installMode: codePush.InstallMode.IMMEDIATE
});

// 第三種:
CodePush.sync({
    deploymentKey: 'deployment-key-here',
    updateDialog: {
        optionalIgnoreButtonLabel: '稍后',
        optionalInstallButtonLabel: '后台更新',
        optionalUpdateMessage: '有新版本了,是否更新?',
        title: '更新提示'
    },
    installMode: CodePush.InstallMode.IMMEDIATE
});
  • 三種更新的策略: 配置到installMode: 之后即可生效

    • IMMEDIATE 立即更新APP

    • ON_NEXT_RESTART 到下一次啟動應用時

    • ON_NEXT_RESUME 當應用從后台返回時 

如果可以進行更新,CodePush會在后台靜默地將更新下載到本地,等待APP下一次啟動的時候應用更新,以確保用戶看到的是最新版本。

如果更新是強制性的,更新文件下載好之后會立即進行更新。
如果你期望更及時的獲得更新,可以在每次APP從后台進入前台的時候去主動的檢查更新:
在應用的根component的componentDidMount中添加如下代碼:


  
  
  
          
  1. AppState.addEventListener("change", (newState) => {
  2. newState === "active" && codePush.sync();
  3. });

發布更新

CodePush支持兩種發布更新的方式,一種是通過code-push release-react簡化方式,另外一種是通過code-push release的復雜方式。

第一種方式:通過code-push release-react發布更新

這種方式將打包與發布兩個命令合二為一,可以說大大簡化了我們的操作流程,建議大家多使用這種方式來發布更新。

命令格式:

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

eg:


  
  
  
          
  1. code- push release-react MyApp-iOS ios
  2. code- push release-react MyApp-Android android

再來個更高級的:

code-push release-react MyApp-iOS ios  --t 1.0.0 --dev false --d Production --des "1.優化操作流程" --m true 

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

關於code-push release-react更多可選的參數,可以在終端輸入code-push release-react進行查看。

release-react常用命令

# Release a mandatory update with a changelog 強制更新包
code-push release-react MyApp-iOS ios -m --description "Modified the header color"

# Release an update for an app that uses a non-standard entry file name, and also capture
# the sourcemap file generated by react-native bundle
code-push release-react MyApp-iOS ios --entryFile MyApp.js --sourcemapOutput ../maps/MyApp.map

# Release a dev Android build to just 1/4 of your end users 灰度測試覆蓋25%的用戶
code-push release-react MyApp-Android android --rollout 25% --dev true

# Release an update that targets users running any 1.1.* binary Android版本在1.1.*的用戶會得到更新,其他的版本不會更新
code-push release-react MyApp-Android android --targetBinaryVersion "~1.1.0"

CodePush客戶端支持差異更新,因此即使您在每次更新時發布JS包和資源,您的最終用戶也只會實際下載所需的文件。

有關release-react命令如何工作的更多詳細信息,以及它公開的各種參數,請參閱CLI文檔。此外,如果您希望自己處理react-native bundle命令,因此需要更靈活的解決方案release-react,請參閱release命令以獲取更多詳細信息。

 

另外,我們可以通過code-push deployment ls <appName>來查看發布詳情與此次更新的安裝情況。

第二中方式:通過code-push release發布更新

code-push release發布更新呢我們首先需要將js與圖片資源進行打包成 bundle。

生成bundle

發布更新之前,需要先把 js打包成 bundle,如:

第一步: 在 工程目錄里面新增 bundles文件:mkdir bundles

第二步: 運行命令打包 react-native bundle --platform 平台 --entry-file 啟動文件 --bundle-output 打包js輸出文件 --assets-dest 資源輸出目錄 --dev 是否調試
eg:
react-native bundle --platform android --entry-file index.android.js --bundle-output ./bundles/index.android.bundle --dev false

            生成bundle
           生成bundle

需要注意的是:

  • 忽略了資源輸出是因為 輸出資源文件后,會把bundle文件覆蓋了。
  • 輸出的bundle文件名不叫其他,而是 index.android.bundle,是因為 在debug模式下,工程讀取的bundle就是叫做 index.android.bundle。
  • 平台可以選擇 android 或者 ios。

發布更新

打包bundle結束后,就可以通過CodePush發布更新了。在終端輸入
code-push release <應用名稱> <Bundles所在目錄> <對應的應用版本> --deploymentName: 更新環境 --description: 更新描述 --mandatory: 是否強制更新 
eg:
code-push release GitHubPopular ./bundles/index.android.bundle 1.0.6 --deploymentName Production --description "1.支持文章緩存。" --mandatory true

 推送更新到CodePush

 推 .     送更新到CodePush  

 

注意:

  1. CodePush默認是更新 staging 環境的,如果是staging,則不需要填寫 deploymentName。
  2. 如果有 mandatory 則Code Push會根據mandatory 是true或false來控制應用是否強制更新。默認情況下mandatory為false即不強制更新。
  3. 對應的應用版本(targetBinaryVersion)是指當前app的版本(對應build.gradle中設置的versionName "1.0.6"),也就是說此次更新的js/images對應的是app的那個版本。不要將其理解為這次js更新的版本。
    如客戶端版本是 1.0.6,那么我們對1.0.6的客戶端更新js/images,targetBinaryVersion填的就是1.0.6。
  4. 對於對某個應用版本進行多次更新的情況,CodePush會檢查每次上傳的 bundle,如果在該版本下如1.0.6已經存在與這次上傳完全一樣的bundle(對應一個版本有兩個bundle的md5完全一樣),那么CodePush會拒絕此次更新。
    如圖:
    對應一個版本有兩個bundle的md5完全一樣
    對應一個版本有兩個bundle的md5完全一樣

所以如果我們要對某一個應用版本進行多次更新,只需要上傳與上次不同的bundle/images即可。如:
eg:
對1.0.6的版本進行第一次更新:
code-push release GitHubPopular ./bundles/index.android.bundle 1.0.6 --deploymentName Production --description "1.支持文章緩存。" --mandatory true 
對1.0.6的版本進行第二次更新:
code-push release GitHubPopular ./bundles/index.android.bundle 1.0.6 --deploymentName Production --description "1.新添加收藏功能。" --mandatory true

  1. 在終端輸入 code-push deployment history <appName> Staging 可以看到Staging版本更新的時間、描述等等屬性。
    eg:
    code-push release Equipment ./bundles 1.0.1

下面我們啟動事先安裝好的應用,看有什么反應:

            提示更新
           提示更新

應用啟動之后,從CodePush服務器查詢更新,並下載到本地,下載好之后,提示用戶進行更新。這就是CodePush用於熱更新的整個過程。

更多部署APP相關命令

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

調試/故障排除

查看這些日志的最簡單方法是運行code-push debug您當前使用的特定平台的命令(例如code-push debug ios)。這將輸出一個日志流,該日志流將被過濾為指定平台的CodePush消息。這樣可以輕松識別問題,無需使用特定於平台的工具,也可以輕松瀏覽大量日志。

屏幕截圖2016-06-21在10 15 42 am

此外,如果您對它們更熟悉,您還可以使用任何特定於平台的工具來查看CodePush日志。簡單啟動Chrome DevTools控制台,Xcode控制台(iOS),OS X控制台(iOS)和/或ADB logcat(Android),並查找帶有前綴的消息[CodePush]

請注意,默認情況下,在發布版本中iOS上禁用了React Native日志,因此如果要在發布版本中查看它們,則需要對AppDelegate.m文件進行以下更改:

  1. 添加一個#import <React/RCTLog.h>聲明。對於RN <v0.40,請使用:#import "RCTLog.h"

  2. 將以下語句添加到application:didFinishLaunchingWithOptions方法的頂部:

    RCTSetLogThreshold(RCTLogLevelInfo);

JavaScript API Reference

  • allowRestart
  • checkForUpdate
  • disallowRestart
  • getUpdateMetadata
  • notifyAppReady
  • restartApp
  • sync

其實我們可以將這些API分為兩類,一類是自動模式,一類是手動模式。

自動模式

sync為自動模式,調用此方法CodePush會幫你完成一系列的操作。其它方法都是在手動模式下使用的。
codePush.sync 
codePush.sync(options: Object, syncStatusChangeCallback: function(syncStatus: Number), downloadProgressCallback: function(progress: DownloadProgress)): Promise<Number>; 
通過調用該方法CodePush會幫我們自動完成檢查更新,下載,安裝等一系列操作。除非我們需要自定義UI表現,不然直接用這個方法就可以了。
sync方法,提供了如下屬性以允許你定制sync方法的默認行為

  • deploymentKey (String): 部署key,指定你要查詢更新的部署秘鑰,默認情況下該值來自於Info.plist(Ios)和MianActivity.java(Android)文件,你可以通過設置該屬性來動態查詢不同部署key下的更新。
  • installMode (codePush.InstallMode): 安裝模式,用在向CodePush推送更新時沒有設置強制更新(mandatory為true)的情況下,默認codePush.InstallMode.ON_NEXT_RESTART即下一次啟動的時候安裝。
  • mandatoryInstallMode (codePush.InstallMode):強制更新,默認codePush.InstallMode.IMMEDIATE。
  • minimumBackgroundDuration (Number):該屬性用於指定app處於后台多少秒才進行重啟已完成更新。默認為0。該屬性只在installModeInstallMode.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”

手動模式

codePush.allowRestart

codePush.allowRestart(): void; 
允許重新啟動應用以完成更新。
如果一個CodePush更新將要發生並且需要重啟應用(e.g.設置了InstallMode.IMMEDIATE模式),但由於調用了disallowRestart方法而導致APP無法通過重啟來完成更新,
可以調用此方法來解除disallowRestart限制。
但在如下四種情況下,CodePush將不會立即重啟應用:

  1. 自上一次disallowRestart被調用,沒有新的更新。
  2. 有更新,但installModeInstallMode.ON_NEXT_RESTART的情況下。
  3. 有更新,但installModeInstallMode.ON_NEXT_RESUME,並且程序一直處於前台,並沒有從后台切換到前台的情況下。
  4. 自從上次disallowRestart被調用,沒有再調用restartApp

codePush.checkForUpdate

codePush.checkForUpdate(deploymentKey: String = null): Promise<RemotePackage>; 
向CodePush服務器查詢是否有更新。
該方法返回Promise,有如下兩種值:

  • null 沒有更新
    通常有如下情況導致RemotePackage為null:

    1. 當前APP版本下沒有部署新的更新版本。也就是說沒有想CodePush服務器推送基於當前版本的有關更新。
    2. CodePush上的更新和用戶當前所安裝的APP版本不匹配。也就是說CodePush服務器上有更新,但該更新對應的APP版本和用戶安裝的當前版本不對應。
    3. 當前APP已將安裝了最新的更新。
    4. 部署在CodePush上可用於當前APP版本的更新被標記成了不可用。
    5. 部署在CodePush上可用於當前APP版本的更新是"active rollout"狀態,並且當前的設備不在有資格更新的百分比的設備之內。
  • A RemotePackage instance
    有更新可供下載。

eg:


  
  
  
          
  1. codePush.checkForUpdate()
  2. .then((update) => {
  3. if (!update) {
  4. console.log("The app is up to date!");
  5. } else {
  6. console.log("An update is available! Should we download it?");
  7. }
  8. });

codePush.disallowRestart

codePush.disallowRestart(): void; 
不允許立即重啟用於以完成更新。
eg:


  
  
  
          
  1. class OnboardingProcess extends Component {
  2. ...
  3. componentWillMount() {
  4. // Ensure that any CodePush updates which are
  5. // synchronized in the background can't trigger
  6. // a restart while this component is mounted.
  7. codePush.disallowRestart();
  8. }
  9. componentWillUnmount() {
  10. // Reallow restarts, and optionally trigger
  11. // a restart if one was currently pending.
  12. codePush.allowRestart();
  13. }
  14. ...
  15. }

codePush.getUpdateMetadata 
codePush.getUpdateMetadata(updateState: UpdateState = UpdateState.RUNNING): Promise<LocalPackage>; 
獲取當前已安裝更新的元數據(描述、安裝時間、大小等)。
eg:


  
  
  
          
  1. // Check if there is currently a CodePush update running, and if
  2. // so, register it with the HockeyApp SDK (https://github.com/slowpath/react-native-hockeyapp)
  3. // so that crash reports will correctly display the JS bundle version the user was running.
  4. codePush.getUpdateMetadata().then((update) => {
  5. if (update) {
  6. hockeyApp.addMetadata({ CodePushRelease: update.label });
  7. }
  8. });
  9. // Check to see if there is still an update pending.
  10. codePush.getUpdateMetadata(UpdateState.PENDING).then((update) => {
  11. if (update) {
  12. // There's a pending update, do we want to force a restart?
  13. }
  14. });

codePush.notifyAppReady 
codePush.notifyAppReady(): Promise<void>; 
通知CodePush,一個更新安裝好了。當你檢查並安裝更新,(比如沒有使用sync方法去handle的時候),這個方法必須被調用。否則CodePush會認為update失敗,並rollback當前版本,在app重啟時。
當使用sync方法時,不需要調用本方法,因為sync會自動調用。

codePush.restartApp 
codePush.restartApp(onlyIfUpdateIsPending: Boolean = false): void; 
立即重啟app。
當以下情況時,這個方式是很有用的:

  1. app 當 調用 sync 或 LocalPackage.install 方法時,指定的 install mode是 ON_NEXT_RESTART 或 ON_NEXT_RESUME時 。 這兩種情況都是當app重啟或resume時,更新內容才能被看到。
  2. 在特定情況下,如用戶從其它頁面返回到APP的首頁時,這個時候調用此方法完成過更新對用戶來說不是特別的明顯。因為強制重啟,能馬上顯示更新內容。

代碼簽名

代碼簽名是一種為​​捆綁創建數字簽名的方法,以后可以在安裝之前在客戶端進行驗證。

開發人員想知道他們發布的代碼是他們編寫的代碼。代碼簽名是提供此類保證的主要機制,可以幫助減輕或消除一大類中間人攻擊。

首先,開發人員生成一個非對稱密鑰對:私鑰將用於簽署捆綁包; 捆綁簽名驗證的公鑰。該CodePush CLI然后使用私鑰簽名過程中捆綁releaserelease-reactrelease-cordova命令。公鑰隨移動應用程序一起提供。控制密鑰的生成和管理掌握在開發人員手中。

在release命令結束時,cli計算bundle的內容哈希並將此值放入使用私鑰簽名的JWT中。當codepush插件將包下載到設備時,它會檢查.codepushrelease包含JWT 文件,並使用公鑰驗證JWT簽名。如果驗證失敗,則不會安裝更新。

密鑰生成

代碼簽名支持用於簽名的PEM編碼的RSA密鑰(非證書)。您可以通過openssl生成它們,如下所示:

生成私有RSA密鑰並將其寫入private.pem文件 
openssl genrsa -out private.pem  
將private.pem中的公鑰導出到public.pem  
openssl rsa -pubout -in private.pem -out public.pem

 

操作步驟:

  1. 生成新的二進制更新,包括
    • 更新的codepush插件支持代碼簽名
    • 配置你的代碼推送sdk使用你的公鑰(請參閱相關的React Native SDK(iOS, Android)或Cordova SDK部分了解詳情)
  2. 生成一個新的CodePush更新,該更新以新的二進制版本為目標並指定--privateKeyPath(或簡稱-k)參數值

eg:

code-push release-react superbuy-android android  --t 1.0.0 --des "test android code-push,帶有公鑰簽名的更新包要加上參數-privateKeyPath指定私鑰路徑"  -k ./private.pem 

-----------------------------

關於代碼簽名常見錯誤 


這是因為發布更新時沒有指定-k參數,私鑰位置

code-push release-react superbuy-android android  --t 1.0.0 --des "test android code-push,帶有公鑰簽名的更新包要加上參數-privateKeyPath指定私鑰路徑" -k ./private.pem 

 

總結

上文已經介紹了CodePush在動態更新方面的一些特性,但CodePush也存在着一些缺點:

  1. 服務器在國外,在國內訪問,網速不是很理想。
  2. 其升級服務器端程序並不開源的,后期微軟會不會對其收費還是個未知數。
    如果在沒有更好的動態更新React Native應用的方案的情況下,並且這些問題還在你的接受范圍之內的話,那么CodePush可以作為動態更新React Native應用的一種選擇。
    后期會向大家分享不采用CodePush,自己搭建服務器並實現React Native應用的動態更新相關的方案。

------------------ 

code-push常用命令 

  • 安裝: npm install -g code-push-cli

  • 注冊賬號: code-push register

  • 登陸: code-push login

  • 注銷: code-push logout

  • 添加項目: code-push app add [app名稱]

  • 刪除項目: code-push app remove [app名稱]

  • 列出賬號下的所有項目: code-push app list

  • 顯示登陸的token: code-push access-key ls

  • 刪除某個access-key: code-push access-key rm <accessKey>

  • 添加協作人員:code-push collaborator add <appName> next@126.com

  • 部署一個環境: code-push deployment add <appName> <deploymentName>

  • 刪除部署: code-push deployment rm <appName>

  • 列出應用的部署: code-push deployment ls <appName>

  • 查詢部署環境的key: code-push deployment ls <appName> -k

  • 查看部署的歷史版本信息: code-push deployment history <appName> <deploymentName>

  • 重命名一個部署: code-push deployment rename <appName> <currentDeploymentName> <newDeploymentName>

---------------

 實際發布更新時常用操作步驟

  • 登錄: code-push login

  • 列出賬號下的所有項目: code-push app list

  • 列出應用的部署: code-push deployment ls MyApp

  • 查看部署的歷史版本信息: code-push deployment history MyApp Staging 

  • 發布版本更新: code-push release-react MyApp ios -d Staging --des 'UI調整' --t '1.0.0'

  • 把更新推到另一個環境: code-push promote MyApp Staging Production

--------------- 

參考: 
https://docs.microsoft.com/en-us/appcenter/distribution/codepush/
https://github.com/Microsoft/react-native-code-push

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM