一、安裝注冊(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)有彈框提示更新