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不仅能节约开发成本,还能做原生开发不能 ...
随机推荐
- Android 如何有效的解决内存泄漏的问题
前言:最近在研究Handler的知识,其中涉及到一个问题,如何避免Handler带来的内存溢出问题.在网上找了很多资料,有很多都是互相抄的,没有实际的作用. 本文的内存泄漏检测工具是:LeakCana ...
- iOS 10 开发适配系列 之 权限Crash问题
升级 iOS 10 之后目测坑还是挺多的,记录一下吧,看看到时候会不会成为一个系列. 直入正题吧 今天用一个项目小小练下手,发现调用相机,崩了.试试看调用相册,又特么崩了.然后看到控制台输出了以下信息 ...
- React Native 之生命周期
前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...
- React Native FlexBox
FlexBox 是React Native布局的一种算法,目的是为了适配不同尺寸的屏幕而设计的. 使用时最关键的就是flex关键字的用法. flex用于修饰当前View在父视图中的占比. 占比如何计算 ...
- swift学习笔记3——类、结构体、枚举
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- Android自定义ViewGroup
视图分类就两类,View和ViewGroup.ViewGroup是View的子类,ViewGroup可以包含所有的View(包括ViewGroup),View只能自我描绘,不能包含其他View. 然而 ...
- uboot的配置流程分析
简单介绍一下uboot的基本配置流程.和绝大多数源码编译安装一样,uboot在执行make之前需要执行make XXXconfig来配置相关信息,而且uboot本身是针对多种平台的bootloader ...
- [收集]MVC3 HTML辅助方法集录
1.跳转链接 @Html.ActionLink("linkText","actionName",routeValues,htmlAttributes) e.g& ...
- win10+vs2013+cuda8.0+caffe
1,首先说下环境和配置 配置: 环境:windows10,vs2013 community,cuda8.0,caffe,cudnn4 注意:先要安装好显卡驱动(我的显卡是1070),这里的例子只开通了 ...
- JavaScript的two-sum问题解法
一个很常见的问题,找出一个数组中和为给定值的两个数的下标.为了简单一般会注明解只有一个之类的. 最容易想到的方法是循环遍历,这里就不说了. 在JS中比较优雅的方式是利用JS的对象作为hash的方式: ...