准备工作:
- 1、在 AppCenter 注册账号等,创建应用;
- 安装
react-native-code-push
,之后执行pod install
;
一、Android的配置:
-
1、android/settings.gradle:
include ':app', ':react-native-code-push' project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
-
2、android/app/build.gradle:
android { buildTypes { releaseStaging { // 主要增加这两行,其中xxxxxx是创建Android应用的Staging Key matchingFallbacks = ['release'] resValue "string", "CodePushDeploymentKey", '"xxxxxx"' signingConfig signingConfigs.release minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } }
在文末增加:
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
-
3、MainApplication.java:
import com.microsoft.codepush.react.CodePush; private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { .... // 增加这4行 @Override protected String getJSBundleFile() { return CodePush.getJSBundleFile(); } };
二、iOS的配置:
-
1、Info.plist:
<key>CFBundleDisplayName</key> <string>iOS的Staging Key</string>
-
2、AppDelegate.mm:
#import <CodePush/CodePush.h> - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else return [CodePush bundleURL]; #endif }
参考:iOS Setup
三、RN的配置:
-
1、最简单方式,使用高阶组件的形式:
import codePush from "react-native-code-push"; class MyApp extends Component { } MyApp = codePush(MyApp);
默认情况下,CodePush将在每个应用程序启动时检查更新。如果更新可用,它将被静默下载,并在下次应用程序重新启动时安装(由最终用户或操作系统显式重新启动),这确保了对最终用户的最小侵入性体验。如果一个可用的更新是强制性的,那么它将立即安装,确保最终用户尽快得到它。
如果想让应用程序更快地发现更新,也可以选择在每次应用程序从后台恢复时与CodePush服务器同步。如下配置:
const codePushOptions = { checkFrequency: codePush.CheckFrequency.ON_APP_RESUME }; class MyApp extends Component { } MyApp = codePush(codePushOptions)(MyApp);
-
2、手动检查参考:
import { Component } from 'react' import { Dimensions, SafeAreaView, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native' import CodePush from 'react-native-code-push' class UpdatePage extends Component { constructor() { super() this.state = { restartAllowed: true } } codePushStatusDidChange(syncStatus) { switch (syncStatus) { case CodePush.SyncStatus.CHECKING_FOR_UPDATE: this.setState({ syncMessage: 'Checking for update.' }) break case CodePush.SyncStatus.DOWNLOADING_PACKAGE: this.setState({ syncMessage: 'Downloading package.' }) break case CodePush.SyncStatus.AWAITING_USER_ACTION: this.setState({ syncMessage: 'Awaiting user action.' }) break case CodePush.SyncStatus.INSTALLING_UPDATE: this.setState({ syncMessage: 'Installing update.' }) break case CodePush.SyncStatus.UP_TO_DATE: this.setState({ syncMessage: 'App up to date.', progress: false }) break case CodePush.SyncStatus.UPDATE_IGNORED: this.setState({ syncMessage: 'Update cancelled by user.', progress: false }) break case CodePush.SyncStatus.UPDATE_INSTALLED: this.setState({ syncMessage: 'Update installed and will be applied on restart.', progress: false }) break case CodePush.SyncStatus.UNKNOWN_ERROR: this.setState({ syncMessage: 'An unknown error occurred.', progress: false }) break } } codePushDownloadDidProgress(progress) { this.setState({ progress }) } toggleAllowRestart() { this.state.restartAllowed ? CodePush.disallowRestart() : CodePush.allowRestart() this.setState({ restartAllowed: !this.state.restartAllowed }) } getUpdateMetadata() { CodePush.getUpdateMetadata(CodePush.UpdateState.RUNNING).then( metadata => { this.setState({ syncMessage: metadata ? JSON.stringify(metadata) : 'Running binary version', progress: false }) }, error => { this.setState({ syncMessage: 'Error: ' + error, progress: false }) } ) } /** Update is downloaded silently, and applied on restart (recommended) */ sync() { CodePush.sync({}, this.codePushStatusDidChange.bind(this), this.codePushDownloadDidProgress.bind(this)) } /** Update pops a confirmation dialog, and then immediately reboots the app */ syncImmediate() { CodePush.sync( { installMode: CodePush.InstallMode.IMMEDIATE, updateDialog: true }, this.codePushStatusDidChange.bind(this), this.codePushDownloadDidProgress.bind(this) ) } restartApp() { CodePush.restartApp() } render() { let progressView if (this.state.progress) { progressView = ( <Text style={styles.messages}> {this.state.progress.receivedBytes} of {this.state.progress.totalBytes} bytes received </Text> ) } return ( <SafeAreaView> <ScrollView> <View style={styles.container}> <Text style={styles.welcome}>Welcome to CodePush!</Text> <Text style={styles.welcome}>Demo bundle</Text> <TouchableOpacity onPress={this.restartApp.bind(this)}> <Text style={styles.syncButton}>Press to restart</Text> </TouchableOpacity> <TouchableOpacity onPress={this.sync.bind(this)}> <Text style={styles.syncButton}>Press for background sync</Text> </TouchableOpacity> <TouchableOpacity onPress={this.syncImmediate.bind(this)}> <Text style={styles.syncButton}>Press for dialog-driven sync</Text> </TouchableOpacity> {progressView} <TouchableOpacity onPress={this.toggleAllowRestart.bind(this)}> <Text style={styles.restartToggleButton}> Restart {this.state.restartAllowed ? 'allowed' : 'forbidden'} </Text> </TouchableOpacity> <TouchableOpacity onPress={this.getUpdateMetadata.bind(this)}> <Text style={styles.syncButton}>Press for Update Metadata</Text> </TouchableOpacity> <Text style={styles.messages}>{this.state.syncMessage || ''}</Text> </View> </ScrollView> </SafeAreaView> ) } } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', backgroundColor: '#F5FCFF', paddingTop: 50 }, image: { margin: 30, width: Dimensions.get('window').width - 100, height: (365 * (Dimensions.get('window').width - 100)) / 651 }, messages: { marginTop: 30, textAlign: 'center' }, restartToggleButton: { color: 'blue', fontSize: 17 }, syncButton: { color: 'green', fontSize: 17 }, welcome: { fontSize: 20, textAlign: 'center', margin: 20 } }) /** * Configured with a MANUAL check frequency for easy testing. For production apps, it is recommended to configure a * different check frequency, such as ON_APP_START, for a 'hands-off' approach where CodePush.sync() does not * need to be explicitly called. All options of CodePush.sync() are also available in this decorator. */ let codePushOptions = { checkFrequency: CodePush.CheckFrequency.MANUAL } UpdatePage = CodePush(codePushOptions)(UpdatePage) export default UpdatePage
参考:React Native Client SDK Plugin Usage
四、发布更新:
一般为了方便操作,通常使用 appcenter codepush release-react
命令来发布更新。
appcenter codepush release-react
[--use-hermes]
[--extra-hermes-flag <arg>]
[--extra-bundler-option <arg>]
[-t|--target-binary-version <arg>]
[-o|--output-dir <arg>]
[--sourcemap-output-dir <arg>]
[-s|--sourcemap-output <arg>]
[-xt|--xcode-target-name <arg>]
[-c|--build-configuration-name <arg>]
[--plist-file-prefix <arg>]
[-xp|--xcode-project-file <arg>]
[-p|--plist-file <arg>]
[--pod-file <arg>]
[-g|--gradle-file <arg>]
[-e|--entry-file <arg>]
[--development]
[-b|--bundle-name <arg>]
[-r|--rollout <arg>]
[--disable-duplicate-release-error]
[-k|--private-key-path <arg>]
[-m|--mandatory]
[-x|--disabled]
[--description <arg>]
[-d|--deployment-name <arg>]
[-a|--app <arg>]
其中参数:
-a|--app <arg>:格式为<ownerName>/<appName>;
-b|--bundle-name <arg>:生成的JS包文件的名称。如果未指定,则将使用标准bundle名称:"main.jsbundle" (iOS)、 "index.android.bundle" (Android) 、"index.windows.bundle" (Windows) ;
-d|--deployment-name <arg>:将更新发布到的部署,默认Staging;
--description <arg>:描述在此版本中对应用程序所做的更改;
--development:指定是否生成 dev 或 release 版本;
-e|--entry-file <arg> :应用程序入口JavaScript文件的路径。如果省略, "index.<platform>.js"、 "index.js"将被使用;
-m|--mandatory:是否强制更新;
-r|--rollout <arg>:能收到此版本的用户百分比;-x|--disabled:此版本是否立即可下载;
-t|--target-binary-version <arg>:指定此版本的二进制应用程序版本的Semver表达式(例如1.1.0,~1.2.3);
-xt|--xcode-target-name <arg> :目标名称(PBXNativeTarget),仅限iOS;
如:
appcenter codepush release-react -a org/projectName-android -d Staging -m -t 1.0.0 --description '大家好,为了更好的服务您,我们需要升级服务'
说明:以下等两条命令是等效
appcenter codepush release-react -a <ownerName>/MyApp-iOS
等同于
mkdir ./CodePush
react-native bundle --platform ios \
--entry-file index.ios.js \
--bundle-output ./CodePush/main.jsbundle \
--assets-dest ./CodePush \
--dev false
appcenter codepush release -a <ownerName>/MyApp-iOS -c ./CodePush -t 1.0.0
五、封装提示
import CodePush from 'react-native-code-push'
export const update = component =>
CodePush({
updateDialog: {
appendReleaseDescription: true,
descriptionPrefix: '更新内容:',
mandatoryContinueButtonLabel: '立即更新',
mandatoryUpdateMessage: '',
optionalIgnoreButtonLabel: '稍后',
optionalInstallButtonLabel: '后台更新',
optionalUpdateMessage: '',
title: '更新提示'
}
})(component)
export default update
网友评论