乐趣区

在React Native中集成热更新

最近,在项目 DYTT 集成了热更新,简单来说,就是不用重新下载安装包即可达到更新应用的目的,也不算教程吧,这里记录一下。

1. 热更新方案
目前网上大概有两个比较广泛的方式,分别是

react-native-pushy
react-native-code-push

前者是由 ReactNative 中文网推出的代码热更新服务,后者是由微软老大哥推出的,当然不仅仅是为 React Native,还包括其他原生方式。
综合考虑之下,选择了 react-native-code-push。
2. 安装 code-push
1. 安装 code-push
npm install -g code-push-cli
2. 注册登录账号
code-push register
这时候会自动启动浏览器打开网页并提供一个 codePush AccessKey,然后命令行里出现需要输入 access key
输入之后就登录成功了。
(貌似在本机上以后都不用登录了,暂不清楚保持登录持续多久)
3. 添加一个 CodePush 应用
code-push app add myProject android react-native
注意填写 app 的名称,OS(android/ios),平台 (react-native),并且 android 和 ios 需要创建两个应用
创建完成会出现两个 key

name
Deployment Key

Production
(一串 37 位的 key)

Staging
(一串 37 位的 key)

Production 是对应生产环境的,Staging 是对应开发环境的。
这个对于我们来说其实没什么区别,只是为了方便测试,所以搞了两个环境
3.react-native 应用接入 code-push
1. 安装 react-native-code-push
yarn add react-native-code-push

# link
react-native link react-native-code-push
2. 原生配置
目前只测试了 android,ios 有兴趣的可以自行测试
上面提到了两个 key 值,现在需要配置在原生目录里
1. 打开 android/app/build.gradle
android {

buildTypes {
debug {

// Note: CodePush updates should not be tested in Debug mode as they are overriden by the RN packager. However, because CodePush checks for updates in all modes, we must supply a key.
buildConfigField “String”, “CODEPUSH_KEY”, ‘””‘

}

releaseStaging {

buildConfigField “String”, “CODEPUSH_KEY”, ‘”<INSERT_STAGING_KEY>”‘// 注意这里的引号

}

release {

buildConfigField “String”, “CODEPUSH_KEY”, ‘”<INSERT_PRODUCTION_KEY>”‘

}
}

}
如果遇到打包错误,可加上 matchingFallbacks = [‘release’, ‘debug’],不知道是不是个别情况,如果没有的请忽略。
修改 versionName 为 3 位数的版本号(code-push 要求)
defaultConfig {
applicationId “com.dytt”
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2
versionName “2.1.0”// 默认为 2 位版本号
// ndk {
// abiFilters “armeabi-v7a”, “x86”
// }
}
release {
//…
matchingFallbacks = [‘release’, ‘debug’]// 加上这一句
buildConfigField “String”, “CODEPUSH_KEY”, ‘”<INSERT_PRODUCTION_KEY>”‘
//…
}
2. 打开 MainApplication.java
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(

new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG), // Add/change this line.

);
}
这样就实现了 key 的动态部署,即在什么环境下使用什么 key
以上文档参考自 https://github.com/Microsoft/react-native-code-push/blob/master/docs/multi-deployment-testing-android.md
4. 客户端更新策略
1. 导入 react-native-code-push
这里需要在应用的根组件上添加 CodePush 配置
import CodePush from “react-native-code-push”;
如果你的环境支持 Decorator(修饰符),可以这样
@codePush(options: CodePushOptions)
class MyApp extends Component<{}> {}
普通的写法
class MyApp extends Component<{}> {}
MyApp = codePush(codePushOptions)(MyApp);
export default MyApp;
这里的 codePushOptions 是更新的配置选项

checkFrequency (codePush.CheckFrequency) 指定您要检查更新的时间,默认为 codePush.CheckFrequency.ON_APP_START。

installMode(codePush.InstallMode)指定何时安装可选更新,默认为 codePush.InstallMode.ON_NEXT_RESTART。

详细的配置可参考 https://github.com/Microsoft/react-native-code-push/blob/master/docs/api-js.md
2. 更新策略
默认情况下,CodePush 会在 app 每次启动的时候去检测是否有更新,如果有,app 会自动下载并在下次打开 app 时安装
这种更新方式是静默的,用户根本察觉不到。
如果我们需要给一点更新提示,可以使用默认的弹出框,也就是 react-native 自带的 Alert,点击后立即安装
class MyApp extends Component {}
MyApp = codePush({
updateDialog: true,
installMode: codePush.InstallMode.IMMEDIATE
})(MyApp);
当然,你可以对弹出框做少量的自定义,比如标题,按钮的文字等
updateDialog: {
optionalIgnoreButtonLabel: ‘ 稍后 ’,
optionalInstallButtonLabel: ‘ 立即更新 ’,
optionalUpdateMessage: ‘ 有新版本了,是否更新?’,
title: ‘ 更新提示 ’
},

这些是默认的更新方式,那么如何自定义呢。
我们可以用到 CodePush.checkForUpdate 来手动检查更新,然后弹出一个自定义窗口
const RemotePackage = await CodePush.checkForUpdate(deploymentKey);
if(RemotePackage){
this.modal.init(RemotePackage);// 打开弹窗
}
这里需要注意的是,在 checkForUpdate(或其他需要填写 deploymentKey 的地方) 的时候,如果在 debug 模式下,如果不填写 deploymentKey,会提示缺少 deploymentKey,我们可以临时写一个固定的方便测试。在正式环境下,这里是不需要填写,它会根据系统自动获取我们在之前配置的那些 deploymentKey 值
然后可以通过 RemotePackage.download 和 LocalPackage.install 来完成下载和安装
install = async () => {
LayoutAnimation.easeInEaseOut();
this.setState({status:1})//download
const LocalPackage = await this.RemotePackage.download((progress)=>{
this.setState({
receivedBytes:progress.receivedBytes
})
Animated.timing(
this.width,
{
toValue: parseFloat(progress.receivedBytes / progress.totalBytes).toFixed(2),
duration: 150
}
).start();
})
this.setState({status:2})//downloadComplete
await LocalPackage.install(LocalPackage.isMandatory?CodePush.InstallMode.IMMEDIATE:CodePush.InstallMode.ON_NEXT_RESUME);
if(!LocalPackage.isMandatory){
this.setState({status:3})
this.setVisible(false);
}else{
ToastAndroid && ToastAndroid.show(‘ 下次启动完成更新 ’, ToastAndroid.SHORT);
}
}
具体实现可以参考项目 DYTT
3. 打包 Release
cd android

# 生成 Release(Production)包
gradlew assembleRelease

# 生成 Release(Staging)包
gradlew assembleReleaseStaging
其实都一样,只是环境区别
5. 发布 code-push 更新
这一步很简单,集成了打包和发布
code-push release-react dyttAndroid android –t 2.1.0 –dev false –d Production –des “1. 修复了已知 BUG\n 2. 测试 code push” –m true
这里注意 –t 2.1.0,有以下几种规则
1.2.3 仅仅只有 1.2.3 的版本

* 所有版本

1.2.x 主要版本 1,次要版本 2 的任何修补程序版本

1.2.3 – 1.2.7 1.2.3 版本到 1.2.7 版本

>=1.2.3 <1.2.7 大于等于 1.2.3 版本小于 1.2.7 的版本

~1.2.3 大于等于 1.2.3 版本小于 1.3.0 的版本

^1.2.3 大于等于 1.2.3 版本小于 2.0.0 的版本
–d 表示开发版本,可选择 Production 和 Staging
–m 表示是否强制更新
当然还有很多操作,比如删除某些更新,回滚等,可以参考官方文档 https://github.com/Microsoft/react-native-code-push
小节
总的来说,这次热更新集成还是挺容易,里面碰到的几个误区在上面也已经提到过,欢迎大家多多关注我的项目 DYTT^^

退出移动版