CodePush是什么?
CodePush是一个微软开发的云服务器。通过它,开发者可以直接在用户的设备上部署手机应用更新。CodePush相当于一个中心仓库,开发者可以推送当前的更新(包括JS/HTML/CSS/IMAGE等)到CoduPush,然后应用将会查询是否有更新,本篇主要介绍使用微软云服务器。
当然,我们也可以自己搭建code-push-server服务器,详情可以查看本地热更新服务器搭建。
实现环境
1.react-native:0.62.2
2.react-native-code-push:^6.2.0
首先介绍下Code Push相关命令
/**前言——code-pus相关指令**/
/**注册登录相关指令**/
code-push login /*进行身份验证以开始管理您的应用*/
code-push logout /*注销当前会话*/
code-push access-key /*查看和管理与您的帐户关联的访问密钥*/
code-push access-key ls /*列出登陆的token*/
code-push access-key rm 删除某个 access-key
/**管理App相关指令**/
code-push app /*查看和管理您的CodePush应用*/
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的所有权转移到另外一个账号
/**查看deployment key**/
code-push deployment /*查看和管理您的应用程序部署*/
code-push deployment ls Appname -k /*查看deployment key*/
/**其他**/
code-push collaborator /*查看和管理应用协作者*/
code-push debug /*查看正在运行的应用程序的CodePush调试日志*/
code-push link /*将其他身份验证提供程序(例如GitHub)链接到现有的Mobile Center帐户*/
code-push patch /*更新现有版本的元数据*/
code-push promote /*将最新版本从一种应用程序部署升级到另一种*/
code-push register /*注册一个新的Mobile Center帐户*/
code-push release /*发布更新到应用程序部署*/
code-push release-cordova /*将Cordova更新发布到应用程序部署*/
code-push release-react /*将React Native更新发布到应用程序部署*/
code-push rollback /*回滚最新版本的应用程序部署*/
接入流程
1.安装 CodePush CLI
2.注册 CodePush账号
3.在CodePush服务器注册App
4.React Native(JavaScript)端集成CodePush
5.原生应用中配置CodePush
6.发布更新的版本
react-native-code-push Demo示例:
首先新建一个React Native项目CodePushDemo
1.CodePush CLI
使用CodePush之前,需要先安装CodePush命令行工具,并注册CodePush账号和应用,安装命令如下:
注意:这个CodePush指令只需要全局安装一次即可,如果第一次安装成功了,那后面就不在需要安装。
npm install -g code-push-cli
安装完成后可以通过code-push -v命令进行验证
2.注册 CodePush账号
注册CodePush账号也很简单,同样是只需简单的执行下面的命令,同样这个注册操作也是全局只需要注册一次即可
code-push register
注意:当执行完上面的命令后,会自动打开一个授权网页,让你选择使用哪种方式进行授权登录,这里我们统一就选择使用GitHub即可
当注册登录成功后,CodePush会给我们一个key:
我们直接复制这个key,然后在终端中将这个key填写进去即可,填写key登录成功显示效果如下
3.在CodePush服务器注册App
为了使CodePush服务器有我们的App,我们需要CodePush注册App,输入下面命令即可完成注册:
注意:如果我们的应用分为iOS和Android两个平台,这时我们需要分别注册两套key:
code-push app add 应用平台命名 平台名称 使用的框架/语言
注册Android平台应用
code-push app add CodePushDemo-Android android react-native
注册iOS平台应用ios
code-push app add CodePushDemo-iOS ios react-native
应用添加成功后就会返回对应的 Production 和 Staging 两个key。
Production 代表生产版的热更新部署,
Staging 代表开发版的热更新部署,
在ios中将staging的部署key复制在info.plist的CodePushDeploymentKey值中,
在android中复制在Application的getPackages的CodePush中
我们可以输入如下命令来查看我们刚刚添加的App
code-push app list
4.React Native(JavaScript)端集成CodePush
安装组件
npm install react-native-code-push --save
添加原生依赖,这里添加依赖我们使用自动添加依赖的方式
react-native link react-native-code-push
JS逻辑代码实现
主页面(App.js)
/**
* 热更新主页面
* Created by 技术渣渣 on 2020/4/26
**/
import React, {Component} from 'react'
import {View, Text, StyleSheet, TouchableOpacity} from 'react-native'
import CodePush from 'react-native-code-push';
import ProgressBarModal from './ProgressBarModal';
class App extends Component{
constructor(props) {
super(props);
this.state={
progressModalVisible:false
}
}
componentDidMount() {
this.syncImmediate(); //开始检查更新
}
syncImmediate() {
CodePush.sync(
{
installMode: CodePush.InstallMode.IMMEDIATE,
updateDialog: {
appendReleaseDescription: true, //是否显示更新description,默认为false
descriptionPrefix: '更新内容:', //更新说明的前缀。 默认是” Description:
mandatoryContinueButtonLabel: '立即更新', //强制更新的按钮文字,默认为continue
mandatoryUpdateMessage: '', //- 强制更新时,更新通知. Defaults to “An update is available that must be installed.”.
optionalIgnoreButtonLabel: '稍后', //非强制更新时,取消按钮文字,默认是ignore
optionalInstallButtonLabel: '后台更新', //非强制更新时,确认文字. Defaults to “Install”
optionalUpdateMessage: '有新版本了,是否更新?', //非强制更新时,更新通知. Defaults to “An update is available. Would you like to install it?”.
title: '更新提示', //要显示的更新通知的标题. Defaults to “Update available”.
},
},
this.codePushStatusDidChange.bind(this),
this.codePushDownloadDidProgress.bind(this),
);
}
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.',progressModalVisible:true});
break;
case CodePush.SyncStatus.AWAITING_USER_ACTION:
this.setState({syncMessage: 'Awaiting user action.'});
break;
case CodePush.SyncStatus.INSTALLING_UPDATE:
this.setState({syncMessage: 'Installing update.',progressModalVisible:true});
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});
}
render(){
let progressView;
if (this.state.progress) {
let total = (this.state.progress.totalBytes/(1024*1024)).toFixed(2);
let received =(this.state.progress.receivedBytes/(1024*1024)).toFixed(2);
let progress = parseInt((received/total)*100);
progressView = (
);
}
return(
欢迎使用热更新!
版本1
Press for dialog-driven sync
{ progressView }
)
}
}
const styles = StyleSheet.create({
container:{
flex: 1,
alignItems: 'center',
backgroundColor: '#F5FCFF',
paddingTop: 50,
},
welcome:{
fontSize: 20,
textAlign: 'center',
margin: 20,
},
syncButton: {
color: 'green',
fontSize: 17,
},
})
let codePushOptions = {checkFrequency: CodePush.CheckFrequency.MANUAL};
App = CodePush(codePushOptions)(App);
export default App;
进度条页面1(ProgressBarModal.js)
import React, { PureComponent } from 'react';
import {
View,
Modal,
Text,
ImageBackground,
StyleSheet
} from 'react-native';
import Bar from './Bar';
import scale from './scale';
const propTypes = {
...Modal.propTypes,
};
const defaultProps = {
animationType: 'none',
transparent: true,
progressModalVisible: false,
onRequestClose: () => {},
};
/* 更新进度条Modal */
class ProgressBarModal extends PureComponent {
constructor(props) {
super(props);
this.state = {
title: '正在下载更新文件' // 更新提示标题
};
}
render() {
const {
animationType,
transparent,
onRequestClose,
progress,
progressModalVisible,
totalPackageSize,
receivedPackageSize,
} = this.props;
return (
{this.state.title}
{`${receivedPackageSize}M/${totalPackageSize}M`}
*温馨提示:下载完更新文件,应用会重启
);
}
}
ProgressBarModal.propTypes = propTypes;
ProgressBarModal.defaultProps = defaultProps;
export default ProgressBarModal;
const styles = StyleSheet.create({
imageBg: {
width: scale(600),
height: scale(100),
justifyContent: 'center',
alignItems: 'center',
backgroundColor:'#1083E6',
borderTopLeftRadius:scale(26),
borderTopRightRadius:scale(26),
},
progressBarView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.2)'
},
// 默认进度条背景底色
barBackgroundStyle: {
backgroundColor: '#e0e0e0'
},
subView: {
width: scale(600),
height: scale(296),
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
},
bottomContainer: {
width: scale(600),
height: scale(39),
borderBottomLeftRadius: scale(26),
borderBottomRightRadius: scale(26),
backgroundColor: '#FFF'
},
textPackageSize: {
fontSize: scale(40),
color: '#686868',
marginTop: scale(36)
},
title: {
color: '#FFF',
fontSize: scale(30)
}
})
进度条页面1(Bar.js)
import React, { PureComponent } from 'react';
import {
View,
Animated,
} from 'react-native';
import PropTypes from 'prop-types';
import scale from './scale';
const propTypes = {
progress: PropTypes.number.isRequired,
backgroundStyle: PropTypes.number.isRequired,
style: PropTypes.object.isRequired,
};
/* 进度条组件 */
class Bar extends PureComponent {
constructor(props) {
super(props);
this.progress = new Animated.Value(0);
this.update = this.update.bind(this);
}
componentWillReceiveProps(nextProps) {
if (this.props.progress >= 0 && this.props.progress !== nextProps.progress) {
this.update(nextProps.progress);
}
}
update(progress) {
Animated.spring(this.progress, {
toValue: progress
}).start();
}
render() {
return (
);
}
}
Bar.propTypes = propTypes;
export default Bar;
5.原生应用中配置CodePush
配置Android平台
1.编辑 android/app/build.gradle,新增依赖:
dependencies {
implementation project(':react-native-code-push')
}
2.编辑 android/app/build.gradle,修改buildTypes,输入对应的Key:
buildTypes {
debug {
signingConfig signingConfigs.debug
resValue "string", "CodePushDeploymentKey", ""
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://facebook.github.io/react-native/docs/signed-apk-android.
signingConfig signingConfigs.release
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
//这里的key为Productionde的key
resValue "string", "CodePushDeploymentKey", "9DSt0TxqNuDlsX1SneATSr8qrrkJ4ksvOXqog"
}
releaseStaging {
//这里的key为Staging的key
resValue "string", "CodePushDeploymentKey", "HmTsl4j3G7qlMtxmIG93beLpF6ns4ksvOXqog"
matchingFallbacks = ['release']
}
}
3.编辑 android/app/build.gradle,修改defaultConfig,将versionName 修改为三位(1.0.0):
defaultConfig {
applicationId "com.codepushdemo"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0.0"
}
6.发布更新的版本
使用前应考虑到应用检查更新的时机,是否要求强制更新,是否要求即时更新等问题。
常见的更新时机有两种
1.打开App就自动检查更新
可以在页面的componentDidMount生命周期方法里通过codePush.sync来触发检查更新,如果有更新包可供下载则会在重启后生效。
注意:这种下载和安装都是静默的,即用户不可见,本文额外增加了更新下载进度条的 modal
codePush.sync({
installMode: CodePush.InstallMode.IMMEDIATE,
updateDialog: {
appendReleaseDescription: true, //是否显示更新description,默认为false
descriptionPrefix: '更新内容:', //更新说明的前缀。 默认是” Description:
mandatoryContinueButtonLabel: '立即更新', //强制更新的按钮文字,默认为continue
mandatoryUpdateMessage: '', //- 强制更新时,更新通知. Defaults to “An update is available that must be installed.”.
optionalIgnoreButtonLabel: '稍后', //非强制更新时,取消按钮文字,默认是ignore
optionalInstallButtonLabel: '后台更新', //非强制更新时,确认文字. Defaults to “Install”
optionalUpdateMessage: '有新版本了,是否更新?', //非强制更新时,更新通知. Defaults to “An update is available. Would you like to install it?”.
title: '更新提示', //要显示的更新通知的标题. Defaults to “Update available”.
},
}),
2.用户点击检查更新并安装
在用户点击按钮触发事件时,在调用上面的codePush.sync方法,在有更新时弹出提示框让用户选择是否更新,如果用户点击立即更新按钮,则会进行安装包的下载,下载完成后会立即重启并生效。
常见的更新时机有两种
如果是强制更新需要在发布的时候指定,发布命令中配置--m true
更新是否要求即时
在更新配置中通过指定installMode来决定安装完成的重启时机,亦即更新生效时机
1.codePush.InstallMode.IMMEDIATE :安装完成立即重启更新
2.codePush.InstallMode.ON_NEXT_RESTART :安装完成后会在下次重启后进行更新
3.codePush.InstallMode.ON_NEXT_RESUME :安装完成后会在应用进入后台后重启更新
如何发布CodePush更新包
本文介绍楼主使用过的发布方式,通过以下指令发布更新包:
code-push release-react --t <本更新包面向的旧版本号> --dev false --d Production --des <本次更新说明> --m true
注意:CodePush默认是更新Staging 环境的,如果发布生产环境的更新包,需要指定--d参数:--d Production,如果发布的是强制更新包,需要加上 --m true强制更新