什么是热更新
简单说就是不需要去应用市场重新下载,直接打开app就会下载更新的内容然后进入app,类似于经常玩游戏,游戏里需要更新,然后就有个进度条在读取。总结就是可以不通过应用市场来进行升级,极大的提升了app修bug和赋予新功能的能力
RN热更新的原理是什么
一个完整的RN-app程序通常包含以下几个部分:
native代码部分
js代码部分-rn代码、依赖的第三方库、业务代码等
图片资源部分
native代码发生了变动
如果你的项目的native代码发生了变动,对不起,热更新不能满足你的需求,你只能硬更新,让用户重新下载新的来覆盖旧的app。截止的当前日期,RN的版本还只是0.32,距离1.0还很遥远。所以经常会有需要用到的功能,而RN原生没有封装,所以只能亲自来写,当然,如果我们有一个完整的无线团队,那么是极好的,直接去把无线团队里的类库中筛选个一些可能会用到的功能,先提前封装进来,尽量的减少热更新的次数。
图片资源或者是js发生变动
而如果我们是想修改图片资源或者是js的代码部分,好的,可以使用热更新,那么既然是热更新,我就置想去修改变动的内容,计算方法:新版本(V3.1) - 旧版本(v3.0) = 增量包
好的,以上都是理论原理内容,由于项目期只有2个人在做RN前端方面的开发,所以没有足够的时间去开发公司内部的热更新。所以使用了第三方的组件react-native-pushy
如何使用react-native-pushy
注册一个pushy账号
配置Bundle URL(iOS)
在工程target的Build Phases->Link Binary with Libraries中加入libz.tbd、libbz2.1.0.tbd
在你的AppDelegate.m文件中增加如下代码:
// ... 其它代码
#import "RCTHotUpdate.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#if DEBUG
// 原来的jsCodeLocation
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
#else
jsCodeLocation=[RCTHotUpdate bundleURL];
#endif
// ... 其它代码
}
配置Bundle URL(Android)
0.29及以后版本:在你的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);
}
// ... 其它代码
}
}
0.28及以前版本:在你的MainActivity中增加如下代码:
// ... 其它代码
import cn.reactnative.modules.update.UpdateContext;
public class MainActivity extends ReactActivity {
@Override
protected String getJSBundleFile() {
return UpdateContext.getBundleUrl(this);
}
// ... 其它代码
}
添加热更新功能
页面需要引用react-native-update模块
import {
isFirstTime,
isRolledBack,
packageVersion,
currentVersion,
checkUpdate,
downloadUpdate,
switchVersion,
switchVersionLater,
markSuccess,
} from 'react-native-update';
通常情况下,热更新的判断需要在app启动上来就要进行判断,那么大多数都会写在index.android.js中
componentWillMount(){
//去除debug时候的警告,测试的时候建议打开,hotloading的时候可以关掉
// console.disableYellowBox = true;
// 2s 后如果还没有响应 则提示并取消
let freshedFlag = false;
let timeout = setTimeout(() => {
timeout && clearTimeout(timeout);
if (freshedFlag) return;
freshedFlag = true;
console.log('超时');
//做些什么,比如setState让页面跳过
}, REQ_TIMEOUT);
//防止反触发,就是更新完了回滚
markSuccess();
//异步函数checkUpdate可以检查当前版本是否需要更新
checkUpdate(appKey).then(info => {
// freshedFlag 为 true 则说明超时
console.log('timeout'+freshedFlag);
if (freshedFlag) {
return;
} else {
freshedFlag = true;
}
//包过期,需要下载最新版的应用(非热更新)
if (info.expired) {
//进度条隐藏,新版本弹窗,提供下载地址
this.setState({
progressState:false,
showDialog:true,
downloadUrl:info.downloadUrl
})
}
//当前版本是最新版本,无需热更新
else if (info.upToDate) {
this.setState({
progressState:false,
progressNum: 100,
welcome:false,
update:false
})
} else {
//需要热更新了
this.doUpdate(info)
}
}).catch(err => {
this.setState({
progressState:false,
welcome:false,
})
});
}
//热更新函数
doUpdate = info => {
//做点什么,让你的UI显示出来,提供个假性的进度条什么的
downloadUpdate(info).then(hash => {
//下载完版本返回一个hash字符串,是当前笨笨的唯一标示,然后切换版本
switchVersion(hash);
}).catch(err => {
this.setState({
progressState:false,
welcome:false,
})
});
};
就理论而言,热更新操作到此结束,但是实际使用过程中,5000个用户大概会有100个丢掉的可能性。不是特别的准,也存在少量用户回滚版本的行为。听说公司其他部门的团队做的app用的是codePush,后期也可以多研究一下。