React-Native 告別CodePush,自建熱更新版本升級環境

來源:互聯網
上載者:User

標籤:

微軟的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)[0],@"main.jsbundle"];  //assets檔案夾地址  NSString *assetsCachePath = [NSString stringWithFormat:@"%@/\%@",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0],@"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(1,data);      }else{        finish(0,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:1];  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 == 1){      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 == 1){      //更新    [[MXFileHelper shared] downloadFileWithURLString:_versionDic[@"fileurl"] finish:^(NSInteger status, id data) {      if(status == 1){        NSLog(@"下載完成");        NSError *error;        NSString *filePath = (NSString *)data;        NSString *desPath = [NSString stringWithFormat:@"%@",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]];        [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

 

React-Native 告別CodePush,自建熱更新版本升級環境

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.