React Native热更新部署-CodePush(适配Android)
CodePush简介
CodePush是微软提供的一套用于热更新 React Native 和 Cordova 应用的服务。CodePush 是提供给 React Native 和 Cordova 开发者直接部署移动应用更新给用户设备的云服务。CodePush 作为一个中央仓库,开发者可以推送更新 (JS, HTML, CSS and images),应用可以从客户端 SDK 里面查询更新。CodePush 可以让应用有更多的可确定性,也可以让你直接接触用户群。在修复一些小问题和添加新特性的时候,不需要经过二进制打包,可以直接推送代码进行实时更新。
官方文档:http://microsoft.github.io/code-push/docs/
安装CodePush客户端与注册账号
- 安装客户端
npm install -g code-push-cli
- 查看版本
code-push -v
- 注册账号
code-push register
授权登陆并得到 access key
- 登陆
code-push login
- 查看当前登录用户
code-push whoami
- 注销
code-push logout
- 列出当前登陆会话
code-push session ls
- 删除登录会话
code-push session rm <machineName>
访问密钥
- 假如您不想通过 Github 或者 Microsoft 第三方授权获取 access key,那么可以通过命令方式生成,默认有效期为60天
code-push access-key add "VSTS Integration"
- 通过 access key 登录
code-push login --accessKey <accessKey>
- 设置用户名及有效期
code-push access-key patch <accessKeyName> --name "new name" --ttl 10d
CodePush服务器APP管理
- 添加APP
code-push app add <appName>
- 分平台添加APP
code-push app add MyApp-Android
code-push app add MyApp-iOS
- 重命名APP
code-push app rename <appName> <newAppName>
- 删除APP
code-push app rm <appName>
- 查看当前账号下APP列表
code-push app ls
部署管理
一个APP名字默认对应两个部署环境:生产环境Production、模拟或演示环境Staging
- 添加部署环境
code-push deployment add <appName> <deploymentName>
- 删除及重命名部署环境
code-push deployment rm <appName> <deploymentName>
code-push deployment rename <appName> <deploymentName> <newDeploymentName>
- 查看指定APP的部署环境
code-push deployment ls <appName> [--displayKeys|-k]
-k 表示显示 Deployment Key
Android集成CodePush、打包、发布更新
参考:https://github.com/Microsoft/react-native-code-push
安装组件
npm install --save react-native-code-push@latest
链接组件
// React Native v0.27+
react-native link react-native-code-push
// React Native v0.27-
rnpm link react-native-code-push
过程需要输入部署环境 key
使用CodePush更新策略
使用 CodePush 包裹根组件
//ES6
import codePush from "react-native-code-push";
class MyApp extends Component {
}
MyApp = codePush(MyApp);
//ES7
import codePush from "react-native-code-push";
@codePush
class MyApp extends Component {
}
- 使用更新选项
let codePushOptions = { checkFrequency: codePush.CheckFrequency.ON_APP_RESUME };
class MyApp extends Component {
}
MyApp = codePush(CodePushOptions)(MyApp);
- 手动更新选项
let codePushOptions = { checkFrequency: codePush.CheckFrequency.MANUAL };
class MyApp extends Component {
onButtonPress() {
codePush.sync({
updateDialog: true,
installMode: codePush.installMode.IMMEDIATE
});
}
render() {
<View>
<TouchableOpacity onPress={this.onButtonPress}>
<Text>Check for updates</Text>
</TouchableOpacity>
</View>
}
}
MyApp = codePush(CodePushOptions)(MyApp);
Redux Saga for CodePush:react-native-code-push-saga
发布更新
code-push release-react <appName> <platform>
code-push release-react MyApp ios
code-push release-react MyApp-Android android
自动打包js和资源文件成bundle并且上传发布到CodePush的服务器。
也可以自己打包:
react-native bundle --platform 平台 --entry-file 启动文件 --bundle-output 打包js输出文件 --assets-dest 资源输出目录 --dev 是否调试
react-native bundle --platform android --entry-file index.android.js --bundle-output ./bundles/index.android.bundle --dev false
然后手动上传:
code-push release <应用名称> <Bundles所在目录> <对应的应用版本> --deploymentName 更新环境 --description 更新描述 --mandatory 是否强制更新
code-push release CodePushDemo ./bundles/index.android.bundle 1.2.0 --deploymentName Staging --description "支持文章缓存" --mandatory true
多环境部署测试的步骤
客户端的回滚机制可以导致服务器端的回滚:code-push rollback
- 发布更新到Staging环境:
code-push release-react <appName> <platform>
- 运行Staging版APP,同步更新,验证其是否正常工作
- 从演示环境推进到生产环境:code-push promote
- 运行Production版APP,同步更新,验证其是否正常工作
我们注意到第2步与第4步,需要生成两种APP,其实可以整合,但是却是分平台的,这里以Android为例。
配置 Debug 和 Release 模式分别对应 Staging 和 Production 部署环境
(1)使用 Android Studio 打开修改 app/build.gradle,配置 debug下 Staging部署环境的 key和 release下 Production部署环境的 key,然后同步
buildTypes {
debug {
...
buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_STAGING_KEY>"'
...
}
release {
...
buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_PRODUCTION_KEY>"'
...
}
}
(2)修改 MainApplication
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
//new CodePush(getResources().getString(R.string.reactNativeCodePush_androidDeploymentKey), getApplicationContext(), BuildConfig.DEBUG)
new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG)
);
}
配置之后,当你调试的时候更新用到的是Staging的key,当签名发布正式包的时候用的就是Production的Key
默认情况下, 用到的是Debug,对应 Staging环境
react-native run android
如果你想测试正式的版本包,即 Production环境,则运行:
react-native run-android --variant release
CodePush 插件的使用场景
CodePush 插件是由两部分组成:
- 1、js模块
- 2、原生API
CodePush 使用场景
下面列出CodePush一些常用的用法,你可以选择一个或者组合使用:
Silent sync on app start
// Fully silent update which keeps the app in sync with the server, without ever interrupting the end user
class MyApp extends Component {
}
MyApp = codePush(MyApp);
Silent sync everytime the app resumes
// 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);
Interactive
// 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);
Log/display progress
// 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);
CodePush 属性及回调方法
CodePushOptions 选项对象
CodePushOptions 选项对象可以自定义,其参数包括:
(1) checkFrequency (codePush.CheckFrequency)
检查频率,其值包括:
- codePush.CheckFrequency.ON_APP_START (0)(默认)
- codePush.CheckFrequency.ON_APP_RESUME (1)
- codePush.CheckFrequency.MANUAL (2)
(2) deploymentKey (String)
部署环境 key
(3) installMode (codePush.InstallMode)
可选的安装模式,其值包括:
- codePush.InstallMode.IMMEDIATE (0)(默认)
- codePush.InstallMode.ON_NEXT_RESTART (1)
- codePush.InstallMode.ON_NEXT_RESUME (2)
(4) mandatoryInstallMode (codePush.InstallMode)
强制性的安装模式,其值包括:
- codePush.InstallMode.IMMEDIATE (0)(默认)
- codePush.InstallMode.ON_NEXT_RESTART (1)
- codePush.InstallMode.ON_NEXT_RESUME (2)
(5) minimumBackgroundDuration (Number)
只在 InstallMode.ON_NEXT_RESUME 安装模式下有效,设置更新生效的时间间隔,单位为秒
(6) updateDialog (UpdateDialogOptions)
更新弹窗,包含选项:
- appendReleaseDescription (Boolean) - false
- descriptionPrefix (String) - " Description: "
- mandatoryContinueButtonLabel (String) - "Continue"
- mandatoryUpdateMessage (String) - "An update is available that must be installed."
- optionalIgnoreButtonLabel (String) - "Ignore"
- optionalInstallButtonLabel (String) - "Install"
- optionalUpdateMessage (String) - "An update is available. Would you like to install it?"
- title (String) - "Update available"
(7) codePushStatusDidChange
codePushStatusDidChange (event hook)
status code 产生变化的回调,SyncStatus 所有值:
- codePush.SyncStatus.CHECKING_FOR_UPDATE (0)
- codePush.SyncStatus.AWAITING_USER_ACTION (1)
- codePush.SyncStatus.DOWNLOADING_PACKAGE (2)
- codePush.SyncStatus.INSTALLING_UPDATE (3)
- codePush.SyncStatus.UP_TO_DATE (4)
- codePush.SyncStatus.UPDATE_IGNORED (5)
- codePush.SyncStatus.UPDATE_INSTALLED (6)
- codePush.SyncStatus.SYNC_IN_PROGRESS (7)
- codePush.SyncStatus.UNKNOWN_ERROR (-1)
(8) codePushDownloadDidProgress
codePushDownloadDidProgress (event hook)
更新下载过程回调,包含参数:
- totalBytes (Number)
- receivedBytes (Number)
实验调试
效果:程序员视角、终端用户视角
报错:The uploaded package is identical to the contents of the specified deployment's current release 表示:已经存在与这次上传完全一样的bundle(对应一个版本有两个bundle的md5完全一样),那么CodePush会拒绝此次更新。
index.android.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Alert,
Text,
Image,
View
} from 'react-native';
import codePush from "react-native-code-push";
class CodePushDemo 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.");
}
componentDidMount() {
console.log('组件加载后执行');
//访问慢,不稳定
codePush.checkForUpdate().then((update) => {
if (!update) {
Alert.alert("提示", "已是最新版本", [ {
text: "Ok", onPress: () => {
console.log("最新版本确定");
}
}]);
} else {
codePush.sync({ updateDialog: true, installMode: codePush.InstallMode.IMMEDIATE });
}
});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Double tap R on your keyboard to reload,{'\n'}
Shake or press menu button for dev menu
</Text>
<Image
style={styles.img}
resizeMode="contain"
source={require('./rnapp.png')}
/>
<Text style={styles.author}>Powered by RNAPP.CC</Text>
</View>
);
}
}
CodePushDemo = codePush(CodePushDemo);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
img: {
height: 60,
width: 332,
marginTop: 20,
},
author: {
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 10,
marginTop: 50,
textAlign: 'center',
fontSize: 16,
color: '#3BC1FF',
},
});
AppRegistry.registerComponent('CodePushDemo', () => CodePushDemo);
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/25/react-native-hot-update-deployment-codepush-android-compatible/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论