Learning CodePush
热更新方案中,比较常用的有微软的 CodePush,ReactNative中文网的pushy,本篇将用pushy配置完整的RN热更新。
镜像更改
cnpm的命令可以去淘宝镜像下载依赖包,但是cnpm本身存在一些问题,项目开发时总会有各种奇怪的问题,因此建议还是用npm来安装依赖包。但是npm原本的镜像下载包的速度很慢且不稳定,为了更快安装包我们可以把npm原本镜像的地址改为淘宝的镜像地址,这样既可以用npm指令安装包,又可以加快速度。
查看镜像地址
npm get registry
#https://registry.npmjs.org/
设成淘宝的镜像
npm config set registry http://registry.npm.taobao.org/
恢复
npm config set registry https://registry.npmjs.org/
安装配置
在你的项目根目录下运行以下命令:
# 全局安装命令行工具,每台电脑只用装一次
yarn global add react-native-update-cli
# 在项目中安装热更新模块
yarn add react-native-update --save
在MainApplication中增加如下代码:
import cn. reactnative. modules. update. UpdateContext;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost ( this ) {
@Override
protected String getJSBundleFile ( ) {
return UpdateContext. getBundleUrl ( MainApplication. this ) ;
}
}
}
登录与创建应用
在 https://update.reactnative.cn 注册帐号,然后在你的项目根目录下运行以下命令:
$ pushy login
email: < 输入你的注册邮箱>
password: < 输入你的密码>
这会在项目文件夹下创建一个.update文件,注意不要把这个文件上传到Git等CVS系统上。你可以在.gitignore末尾增加一行.update来忽略这个文件。
登录之后可以创建应用。注意iOS平台和安卓平台需要分别创建:
$ pushy createApp -- platform ios
App Name: < 输入应用名字>
$ pushy createApp -- platform android
App Name: < 输入应用名字>
两次输入的名字可以相同,这没有关系。
如果你已经在网页端或者其它地方创建过应用,也可以直接选择应用:
#例如:
$ pushy selectApp -- platform ios
1 ) 鱼多多 ( ios)
2 ) 招财旺 ( ios)
Total 2 ios apps
Enter appId: < 输入应用前面的编号>
选择或者创建过应用后,你将可以在文件夹下看到update.json文件,其内容类似如下形式:
{
"ios" : {
"appId" : 1 ,
"appKey" : "<一串随机字符串>"
} ,
"android" : {
"appId" : 2 ,
"appKey" : "<一串随机字符串>"
}
}
代码集成
import React, {
Component,
} from 'react' ;
import {
StyleSheet,
Platform,
Text,
View,
Alert,
TouchableOpacity,
Linking,
} from 'react-native' ;
import {
isFirstTime,
isRolledBack,
packageVersion,
currentVersion,
checkUpdate,
downloadUpdate,
switchVersion,
switchVersionLater,
markSuccess,
} from 'react-native-update' ;
import _updateConfig from './update.json' ;
const { appKey} = _updateConfig[ Platform. OS ] ;
export default class MyProject extends Component {
componentDidMount ( ) {
if ( isFirstTime) {
Alert. alert ( '提示' , '这是当前版本第一次启动,是否要模拟启动失败?失败将回滚到上一版本' , [
{ text: '是' , onPress: ( ) => { throw new Error ( '模拟启动失败,请重启应用' ) } } ,
{ text: '否' , onPress: ( ) => { markSuccess ( ) } } ,
] ) ;
} else if ( isRolledBack) {
Alert. alert ( '提示' , '刚刚更新失败了,版本被回滚.' ) ;
}
}
doUpdate = async ( info) => {
try {
const hash = await downloadUpdate ( info) ;
Alert. alert ( '提示' , '下载完毕,是否重启应用?' , [
{ text: '是' , onPress: ( ) => { switchVersion ( hash) ; } } ,
{ text: '否' , } ,
{ text: '下次启动时' , onPress: ( ) => { switchVersionLater ( hash) ; } } ,
] ) ;
} catch ( err) {
Alert. alert ( '提示' , '更新失败.' ) ;
}
} ;
checkUpdate = async ( ) => {
if ( __DEV__) {
return ;
}
let info;
try {
info = await checkUpdate ( appKey) ;
} catch ( err ) {
console. warn ( err) ;
return ;
}
if ( info. expired) {
Alert. alert ( '提示' , '您的应用版本已更新,请前往应用商店下载新的版本' , [
{ text: '确定' , onPress: ( ) => { info. downloadUrl && Linking. openURL ( info. downloadUrl) } } ,
] ) ;
} else if ( info. upToDate) {
Alert. alert ( '提示' , '您的应用版本已是最新.' ) ;
} else {
Alert. alert ( '提示' , '检查到新的版本' + info. name+ ',是否下载?\n' + info. description, [
{ text: '是' , onPress: ( ) => { this . doUpdate ( info) } } ,
{ text: '否' , } ,
] ) ;
}
} ;
render ( ) {
return (
< View style= { styles. container} >
< Text style= { styles. welcome} >
欢迎使用热更新服务
< / Text>
< Text style= { styles. instructions} >
这是版本一 { '\n' }
当前原生包版本号: { packageVersion} { '\n' }
当前热更新版本Hash: { currentVersion|| '(空)' } { '\n' }
< / Text>
< TouchableOpacity onPress= { this . checkUpdate} >
< Text style= { styles. instructions} >
点击这里检查更新
< / Text>
< / TouchableOpacity>
< / View>
) ;
}
}
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 ,
} ,
} ) ;
发布应用
参考文档-生成已签名的APK
#在android文件夹下运行
. / gradlew assembleRelease
#找到你的应用包
android/ app/ build/ outputs/ apk/ release/ app- release. apk
#运行如下命令
$ pushy uploadApk android/ app/ build/ outputs/ apk/ release/ app- release. apk
#即可上传apk以供后续版本比对之用。此apk的versionName字段 ( 位于android/ build. gralde中) 会被记录为原生版本号packageVersion。
发布新的热更新版本
你可以尝试修改一行代码(譬如将版本一修改为版本二),然后生成新的热更新版本
$ pushy bundle -- platform < ios| android>
Bundling with React Native version: 0.22 .2
< 各种进度输出>
Bundled saved to: build/ output/ android. 1459850548545. ppk
Would you like to publish it? ( Y / N )
如果想要立即发布,此时输入Y。当然,你也可以在将来使用pushy publish --platform <ios|android> 来发布版本。
Uploading [ === === === === === === === === === === === === === === === === === === == ] 100 % 0.0 s
Enter version name: < 输入热更新版本名字,如1.0 .0 - rc>
Enter description: < 输入热更新版本描述>
Enter meta info: { "ok" : 1 }
Ok.
Would you like to bind packages to this version? ( Y / N )
此时版本已经提交到update服务,但用户暂时看不到此更新,你需要先将特定的原生包版本绑定到此热更新版本上。
此时输入Y立即绑定,你也可以在将来使用pushy update --platform <ios|android>来使得对应原生包版本的用户更新。 除此以外,你还可以在网页端操作,简单的将对应的原生包版本拖到此热更新版本下即可。
Offset 0
1 ) FvXnROJ1 1.0 .1 ( no package )
2 ) FiWYm9lB 1.0 [ 1.0 ]
Enter versionId or page Up/ page Down/ Begin ( U / D / B ) < 输入序号, U / D 翻页, B 回到开始,序号就是上面列表中) 前面的数字>
1 ) 1.0 ( normal) - 3 FiWYm9lB ( 未命名)
Total 1 packages.
Enter packageId: < 输入原生包版本序号,序号就是上面列表中) 前面的数字>
版本绑定完毕后,客户端就应当可以检查到更新并进行更新了...