微软的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,自建热更新版本升级环境的更多相关文章

  1. ReactNative 使用微软的CodePush进行热更新,继续填坑

    1.别被开发环境骗了 在我们开发react native的时候,一键运行工程,js改了,只要cmd+R就可以刷新了.然后会轻易以为真正app上线的时候也是一样,只要app一打开就是最新的. 其实!这是 ...

  2. 在React Native中集成热更新

    最近,在项目DYTT集成了热更新,简单来说,就是不用重新下载安装包即可达到更新应用的目的,也不算教程吧,这里记录一下. 1.热更新方案 目前网上大概有两个比较广泛的方式,分别是 react-nativ ...

  3. react-native热更新之CodePush详细介绍及使用方法

    react-native热更新之CodePush详细介绍及使用方法 2018年03月04日 17:03:21 clf_programing 阅读数:7979 标签: react native热更新co ...

  4. React Native之code-push的热更新(ios android)

    React Native之code-push的热更新(ios android) React Native支持大家用React Native技术开发APP,并打包生成一个APP.在动态更新方面React ...

  5. CodePush热更新组件详细接入教程

    CodePush热更新组件详细接入教程 什么是CodePush CodePush是一个微软开发的云服务器.通过它,开发者可以直接在用户的设备上部署手机应用更新.CodePush相当于一个中心仓库,开发 ...

  6. 深度使用react-native的热更新能力,必须知道的一个shell命令

    开篇之前,先讲一个自己开发中的一个小插曲: 今天周日,iOS版 App 周一提交,周三审核通过上架,很给力.不过,中午11:30的时候,运营就反应某个页面有一个很明显的问题,页面没法拉到底部,部分信息 ...

  7. ReactNative学习笔记(四)热更新和增量更新

    概括 关于RN的热更新,网上有很多现成方案,但是一般都依赖第三方服务,我所希望的是能够自己管控所有一切,所以只能自己折腾. 热更新的思路 热更新一般都是更新JS和图片,也就是在不重新安装apk的情况下 ...

  8. react-native热更新从零到成功中的各种坑

    https://github.com/reactnativecn/react-native-pushy/blob/master/docs/guide.md Android NDK暂时没有安装 在你的项 ...

  9. 用CodePush在React Native App中做热更新

    最近在学React Native,学到了CodePush热更新. 老师讲了两种实现的方法,现将其记录一下. 相比较原生开发,使用React Native开发App不仅能节约开发成本,还能做原生开发不能 ...

随机推荐

  1. Android 如何有效的解决内存泄漏的问题

    前言:最近在研究Handler的知识,其中涉及到一个问题,如何避免Handler带来的内存溢出问题.在网上找了很多资料,有很多都是互相抄的,没有实际的作用. 本文的内存泄漏检测工具是:LeakCana ...

  2. iOS 10 开发适配系列 之 权限Crash问题

    升级 iOS 10 之后目测坑还是挺多的,记录一下吧,看看到时候会不会成为一个系列. 直入正题吧 今天用一个项目小小练下手,发现调用相机,崩了.试试看调用相册,又特么崩了.然后看到控制台输出了以下信息 ...

  3. React Native 之生命周期

    前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...

  4. React Native FlexBox

    FlexBox 是React Native布局的一种算法,目的是为了适配不同尺寸的屏幕而设计的. 使用时最关键的就是flex关键字的用法. flex用于修饰当前View在父视图中的占比. 占比如何计算 ...

  5. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  6. Android自定义ViewGroup

    视图分类就两类,View和ViewGroup.ViewGroup是View的子类,ViewGroup可以包含所有的View(包括ViewGroup),View只能自我描绘,不能包含其他View. 然而 ...

  7. uboot的配置流程分析

    简单介绍一下uboot的基本配置流程.和绝大多数源码编译安装一样,uboot在执行make之前需要执行make XXXconfig来配置相关信息,而且uboot本身是针对多种平台的bootloader ...

  8. [收集]MVC3 HTML辅助方法集录

    1.跳转链接 @Html.ActionLink("linkText","actionName",routeValues,htmlAttributes) e.g& ...

  9. win10+vs2013+cuda8.0+caffe

    1,首先说下环境和配置 配置: 环境:windows10,vs2013 community,cuda8.0,caffe,cudnn4 注意:先要安装好显卡驱动(我的显卡是1070),这里的例子只开通了 ...

  10. JavaScript的two-sum问题解法

    一个很常见的问题,找出一个数组中和为给定值的两个数的下标.为了简单一般会注明解只有一个之类的. 最容易想到的方法是循环遍历,这里就不说了. 在JS中比较优雅的方式是利用JS的对象作为hash的方式: ...