ReactNative 告别CodePush,自建热更新版本升级环境
微软的CodePush热更新非常难用大家都知道,速度跟被墙了没什么区别。
另外一方面,我们不希望把代码放到别人的服务器。自己写接口更新总归感觉安全一点。
so,就来自己搞个React-Native APP的热更新管理工具吧。暂且命名为hotdog。
/**************************************************/
首先我们要弄清react-native启动的原理,是直接调用jslocation的jsbundle文件和assets资源文件。
由此,我们可以自己通过的服务器接口去判断版本,并下载最新的然后替换相应的文件,然后从这个文件调用启动APP。这就像之前的一些H5APP一样做版本的管理。
以iOS为例,我们需要分以下几步去搭建这个自己的RN升级插件:
一、设置默认jsbundle地址(比如document文件夹):
1.首先打包的时候把jsbundle和assets放入copy bundle resource,每次启动后,检测document文件夹是否存在,不存在则拷贝到document文件夹,然后给RN框架读取启动。
我们建立如下的bundle文件管理类:
MXBundleHelper.h
#import <Foundation/Foundation.h> @interface MXBundleHelper : NSObject +(NSURL *)getBundlePath; @end
MXBundleHelper.m
#import "MXBundleHelper.h"
#import "RCTBundleURLProvider.h"
@implementation MXBundleHelper
+(NSURL *)getBundlePath{
#ifdef DEBUG
NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
return jsCodeLocation;
#else
//需要存放和读取的document路径
//jsbundle地址
NSString *jsCachePath = [NSString stringWithFormat:@"%@/\%@",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[],@"main.jsbundle"];
//assets文件夹地址
NSString *assetsCachePath = [NSString stringWithFormat:@"%@/\%@",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[],@"assets"]; //判断JSBundle是否存在
BOOL jsExist = [[NSFileManager defaultManager] fileExistsAtPath:jsCachePath];
//如果已存在
if(jsExist){
NSLog(@"js已存在: %@",jsCachePath);
//如果不存在
}else{
NSString *jsBundlePath = [[NSBundle mainBundle] pathForResource:@"main" ofType:@"jsbundle"];
[[NSFileManager defaultManager] copyItemAtPath:jsBundlePath toPath:jsCachePath error:nil];
NSLog(@"js已拷贝至Document: %@",jsCachePath);
} //判断assets是否存在
BOOL assetsExist = [[NSFileManager defaultManager] fileExistsAtPath:assetsCachePath];
//如果已存在
if(assetsExist){
NSLog(@"assets已存在: %@",assetsCachePath);
//如果不存在
}else{
NSString *assetsBundlePath = [[NSBundle mainBundle] pathForResource:@"assets" ofType:nil];
[[NSFileManager defaultManager] copyItemAtPath:assetsBundlePath toPath:assetsCachePath error:nil];
NSLog(@"assets已拷贝至Document: %@",assetsCachePath);
}
return [NSURL URLWithString:jsCachePath];
#endif
}
二、做升级检测,有更新则下载,然后对本地文件进行替换:
假如我们不立即做更新,可以更新后替换,然后不会影响本次APP的使用,下次使用就会默认是最新的了。
如果立即更新的话,需要使用到RCTBridge类里的reload函数进行重启。
这里通过NSURLSession进行下载,然后zip解压缩等方法来实现文件的替换。
MXUpdateHelper.h
#import <Foundation/Foundation.h>
typedef void(^FinishBlock) (NSInteger status,id data); @interface MXUpdateHelper : NSObject
+(void)checkUpdate:(FinishBlock)finish;
@end
MXUpdateHelper.m
#import "MXUpdateHelper.h" @implementation MXUpdateHelper
+(void)checkUpdate:(FinishBlock)finish{
NSString *url = @"http://www.xxx.com/xxxxxxx";
NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[newRequest setHTTPMethod:@"GET"];
[NSURLConnection sendAsynchronousRequest:newRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * response, NSData * data, NSError * connectionError) {
if(connectionError == nil){
//请求自己服务器的API,判断当前的JS版本是否最新
/*
{
"version":"1.0.5",
"fileUrl":"http://www.xxxx.com/xxx.zip",
"message":"有新版本,请更新到我们最新的版本",
"forceUpdate:"NO"
}
*/
//假如需要更新
NSString *curVersion = @"1.0.0";
NSString *newVersion = @"2.0.0";
//一般情况下不一样,就是旧版本了
if(![curVersion isEqualToString:newVersion]){
finish(,data);
}else{
finish(,nil);
}
}
}];
}
@end
三、APPdelegate中的定制,弹框,直接强制更新等
如果需要强制刷新reload,我们新建RCTView的方式也需要稍微改下,通过新建一个RCTBridge的对象。
因为RCTBridge中有reload的接口可以使用。
#import "AppDelegate.h"
#import "RCTBundleURLProvider.h"
#import "RCTRootView.h"
#import "MXBundleHelper.h"
#import "MXUpdateHelper.h"
#import "MXFileHelper.h"
#import "SSZipArchive.h"
@interface AppDelegate()<UIAlertViewDelegate>
@property (nonatomic,strong) RCTBridge *bridge;
@property (nonatomic,strong) NSDictionary *versionDic;
@end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ NSURL *jsCodeLocation;
jsCodeLocation = [MXBundleHelper getBundlePath]; _bridge = [[RCTBridge alloc] initWithBundleURL:jsCodeLocation
moduleProvider:nil
launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:_bridge moduleName:@"MXVersionManager" initialProperties:nil]; rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; __weak AppDelegate *weakself = self;
//更新检测
[MXUpdateHelper checkUpdate:^(NSInteger status, id data) {
if(status == ){
weakself.versionDic = data;
/*
这里具体关乎用户体验的方式就多种多样了,比如自动立即更新,弹框立即更新,自动下载下次打开再更新等。
*/
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:data[@"message"] delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"现在更新", nil];
[alert show];
//进行下载,并更新
//下载完,覆盖JS和assets,并reload界面
// [weakself.bridge reload];
}
}];
return YES;
} - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex == ){
//更新
[[MXFileHelper shared] downloadFileWithURLString:_versionDic[@"fileurl"] finish:^(NSInteger status, id data) {
if(status == ){
NSLog(@"下载完成");
NSError *error;
NSString *filePath = (NSString *)data;
NSString *desPath = [NSString stringWithFormat:@"%@",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[]];
[SSZipArchive unzipFileAtPath:filePath toDestination:desPath overwrite:YES password:nil error:&error];
if(!error){
NSLog(@"解压成功");
[_bridge reload];
}else{
NSLog(@"解压失败");
}
}
}];
}
}
流程简单,通过接口请求版本,然后下载到document去访问。 其中需要做版本缓存,Zip的解压缩,以及文件拷贝等。
运行iOS工程可以看到效果。 初始为1.0.0版本,然后更新后升级到1.0.1版本。
demo: https://github.com/rayshen/MXHotdog
ReactNative 告别CodePush,自建热更新版本升级环境的更多相关文章
- ReactNative 使用微软的CodePush进行热更新,继续填坑
1.别被开发环境骗了 在我们开发react native的时候,一键运行工程,js改了,只要cmd+R就可以刷新了.然后会轻易以为真正app上线的时候也是一样,只要app一打开就是最新的. 其实!这是 ...
- 在React Native中集成热更新
最近,在项目DYTT集成了热更新,简单来说,就是不用重新下载安装包即可达到更新应用的目的,也不算教程吧,这里记录一下. 1.热更新方案 目前网上大概有两个比较广泛的方式,分别是 react-nativ ...
- react-native热更新之CodePush详细介绍及使用方法
react-native热更新之CodePush详细介绍及使用方法 2018年03月04日 17:03:21 clf_programing 阅读数:7979 标签: react native热更新co ...
- React Native之code-push的热更新(ios android)
React Native之code-push的热更新(ios android) React Native支持大家用React Native技术开发APP,并打包生成一个APP.在动态更新方面React ...
- CodePush热更新组件详细接入教程
CodePush热更新组件详细接入教程 什么是CodePush CodePush是一个微软开发的云服务器.通过它,开发者可以直接在用户的设备上部署手机应用更新.CodePush相当于一个中心仓库,开发 ...
- 深度使用react-native的热更新能力,必须知道的一个shell命令
开篇之前,先讲一个自己开发中的一个小插曲: 今天周日,iOS版 App 周一提交,周三审核通过上架,很给力.不过,中午11:30的时候,运营就反应某个页面有一个很明显的问题,页面没法拉到底部,部分信息 ...
- ReactNative学习笔记(四)热更新和增量更新
概括 关于RN的热更新,网上有很多现成方案,但是一般都依赖第三方服务,我所希望的是能够自己管控所有一切,所以只能自己折腾. 热更新的思路 热更新一般都是更新JS和图片,也就是在不重新安装apk的情况下 ...
- react-native热更新从零到成功中的各种坑
https://github.com/reactnativecn/react-native-pushy/blob/master/docs/guide.md Android NDK暂时没有安装 在你的项 ...
- 用CodePush在React Native App中做热更新
最近在学React Native,学到了CodePush热更新. 老师讲了两种实现的方法,现将其记录一下. 相比较原生开发,使用React Native开发App不仅能节约开发成本,还能做原生开发不能 ...
随机推荐
- javascript 类型转换。
学校js感觉好漫长,断断续续,要坚持每天都能学到点,总结了下数据类型的转换. Javascript的变量是松散类型的,它可以存储Javascript支持的任何数据类型,其变量的类型可以在运行时被动态改 ...
- 深入理解javascript选择器API系列第二篇——getElementsByClassName
× 目录 [1]使用 [2]classList [3]扩展 前面的话 既然有getElementById()和getElementsByTagName()方法,为什么没有getElementsByCl ...
- iOS---The maximum number of apps for free development profiles has been reached.
真机调试免费App ID出现的问题The maximum number of apps for free development profiles has been reached.免费应用程序调试最 ...
- 【代码笔记】iOS-页面之间的跳转效果
一,工程图. 二,代码. RootViewController.m -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { ...
- 【原】HTTP in iOS你看我就够
声明:本文是本人 编程小翁 原创,转载请注明. 本文同步发布在简书中,强烈建议移步简书查看,编程小翁 HTTP属于老话题了,在项目中我们经常需要往服务端发POST或者GET请求,但是对于HTTP的了解 ...
- Learning the standard of C++11
It's a very useful website of en.cppreference.com. It lists a huge number of information about the l ...
- [Erlang 0127] Term sharing in Erlang/OTP 上篇
之前,在 [Erlang 0126] 我们读过的Erlang论文 提到过下面这篇论文: On Preserving Term Sharing in the Erlang Virtual Machine ...
- monkey命令选项参考
基本参数: --help 打印帮助消息 -v 可以在命令行中出现多次,每次一个-V选项都会增加monkey向命令行打印输出的详细级别.默认的级别0只会打印启动信息. ...
- 编译protobuf的jar文件
1.准备工作 需要到github上下载相应的文件,地址https://github.com/google/protobuf/releases protobuf有很多不同语言的版本,因为我们需要的是ja ...
- JAVA NIO Scatter/Gather(矢量IO)
矢量IO=Scatter/Gather: 在多个缓冲区上实现一个简单的IO操作.减少或避免了缓冲区拷贝和系统调用(IO) write:Gather 数据从几个缓冲区顺序抽取并沿着通道发送,就好 ...