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骇两。
成功后可以看到:
相關(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示血。
2.在build Settings頁簽中單擊 + 按鈕然后選擇添加User-Defined Setting棋傍,然后輸入CODEPUSH_KEY(名稱隨意),然后填入deployment key难审。
3.打開 Info.plist文件瘫拣,在CodePushDeploymentKey中輸入$(CODEPUSH_KEY),并修改Bundle versions為三位告喊,如下圖
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