什么是热更新
简单说就是不需要去应用市场重新下载,直接打开app就会下载更新的内容然后进入app,类似于经常玩游戏,游戏里需要更新,然后就有个进度条在读取。总结就是可以不通过应用市场来进行升级,极大的提升了app修bug和赋予新功能的能力
RN热更新的原理是什么
一个完整的RN-app程序通常包含以下几个部分:
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
// ... 其它代码 #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,}) }); } //热更新函数 doUpdate = info => { //做点什么,让你的UI显示出来,提供个假性的进度条什么的 downloadUpdate(info).then(hash => { //下载完版本返回一个hash字符串,是当前笨笨的唯一标示,然后切换版本 switchVersion(hash); }).catch(err => { this.setState({ progressState:false,}) }); };
就理论而言,热更新操作到此结束,但是实际使用过程中,5000个用户大概会有100个丢掉的可能性。不是特别的准,也存在少量用户回滚版本的行为。听说公司其他部门的团队做的app用的是codePush,后期也可以多研究一下。