React Native菜鸟入门RN iOS开发相关Hybrid开发

React-Native做本地服务器热更新/热部署(IOS)

2018-02-28  本文已影响1164人  币乎iOS

前言

        某个公司考虑使用React-Native的理由有很多,热更新/热部署可能是一个很大的原因。如果公司认为热更新/热部署是主要原因的话,那么这应该是一个很错误的决定。因为APP的质量和具有前瞻性的规划才是您真正需要考虑的事情,而不是热更新的补救。当然不可否认的是热更新/热部署很符合敏捷开发这个思维.......

进入正题

        现在热更新的第三方服务很多:微软的CodePushRN中文网的Pushy......国内还是推荐使用国内的服务吧。

        既然有这么多第三方服务为何还要自己开发热更新/热部署功能呢?

        1、安全性

        2、可控性

        3、实现简单的业务逻辑开发起来其实很简单

        4、之前使用的微软CodePush的服务下载时出现很多问题,于是决定自己开发。

开发思路

开发思路

开发步骤

1、编译项目

ios打包编译:CD到项目根目录运行命令

react-native bundle --entry-file index.ios.js --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle

安卓打包请移步到打包APK

ios打包完成后在项目中的ios目录中多出了bundle文件夹,这里就是我们打包出来的RN运行文件,实际上RN运行的就是这里的.jsbundle文件。

编译项目目录

2、压缩编译文件

把bundle文件夹压缩为ZIP包

3、把压缩的bundle的ZIP包上传到后端

4、更新后台相关的配置文件,比如:RN包的版本号、更新日志、是否强制更新、是否静默更新、是否回滚......具体有多少功能是你们的自己的事


5、下载最新的包,这里开始是写代码的时候了

5.1首先网络请求服务的RN配置内容

5.2对比本地RN的版本号

5.3弹出更新

5.4下载解压最新的包

下载和解压文件的代码:下载使用的是AFN、解压使用的是SSZipArchive

AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];

    //下载地址

    NSURL*mgrurl = [NSURLURLWithString:self.updateUrl];

    NSURLRequest*request = [NSURLRequestrequestWithURL:mgrurl];

    NSURLSessionDownloadTask*download = [mgrdownloadTaskWithRequest:requestprogress:^(NSProgress*_NonnulldownloadProgress) {

      //在主线程中调用

      [[NSOperationQueue mainQueue]addOperationWithBlock:^{

        NSLog(@"进度%f",1.0*downloadProgress.completedUnitCount/ downloadProgress.totalUnitCount);

        CGFloatjsw =1.0* downloadProgress.completedUnitCount/ downloadProgress.totalUnitCount* (PW-40);

        self.jdView.frame=CGRectMake(0,0, jsw,5);

        self.jdText.text= [NSStringstringWithFormat:@"更新进度(%.0f/100)",100.0*downloadProgress.completedUnitCount/ downloadProgress.totalUnitCount];

        self.suduText.text= [NSStringstringWithFormat:@"%lldkb/s",[MLRNSingtongetInterfaceBytes]/1024/1024];

      }];

    }destination:^NSURL*_Nonnull(NSURL*_NonnulltargetPath,NSURLResponse*_Nonnullresponse) {

      NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];

      NSLog(@"targetPath:%@",targetPath);

      NSLog(@"fullPath:%@",fullPath);

      return[NSURLfileURLWithPath:fullPath];

    }completionHandler:^(NSURLResponse*_Nonnullresponse,NSURL*_NullablefilePath,NSError*_Nullableerror) {

      //下载完成,解压

      //Caches路径

      NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];

      NSString *xxxx = [[filePath absoluteString] substringFromIndex:7];

      [SSZipArchive unzipFileAtPath: xxxx toDestination:cachesPath];

      [[NSOperationQueue mainQueue]addOperationWithBlock:^{

        [MBProgressHUD hideHUD];

        UIStoryboard*storayobard = [UIStoryboardstoryboardWithName:@"main"bundle:nil];

        self.view.window.rootViewController = storayobard.instantiateInitialViewController;

      }];

    }];

    [downloadresume];

下载和解压和重启app

5.5运行本地的RN文件

在使用调用RN的地方(一般在AppDelegate中)

修改RCTRootView初始化方法为

RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:[[RCTBridge alloc] initWithDelegate:self launchOptions:nil] moduleName:@""name"" initialProperties:nil];

修改RCTRootView初始化方法

添加代理RCTBridgeDelegate

添加代理

实现RCTBridgeDelegate中的sourceURLForBridge方法

- (NSURL*)sourceURLForBridge:(RCTBridge*)bridge {

  <#code#>

}

sourceURLForBridge方法

在sourceURLForBridge方法中确定您是要使用最新那个URL中的包

我这里的逻辑是

判断沙盒是否存在.jsbundle文件 --->  有则使用沙盒中的.jsbundle

                                                            没有则使用本地打包的文件

- (NSURL*)sourceURLForBridge:(RCTBridge*)bridge{

  NSURL*jsCodeLocation;

  // 取得沙盒目录

  NSString *localPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

  // 要检查的文件目录

  NSString*filePath = [localPath  stringByAppendingPathComponent:@"bundle/index.ios.jsbundle"];

  NSFileManager *fileManager = [NSFileManager defaultManager];

  if([fileManagerfileExistsAtPath:filePath]) {

    NSString*newUrl = [NSStringstringWithFormat:@"file://%@",filePath];

    jsCodeLocation = [NSURLURLWithString:newUrl];

    NSLog(@"文件存在");

    returnjsCodeLocation;

  }else{

#if DEBUG

    // 原来的jsCodeLocation

    jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];

#else

    jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"bundle/index.ios"withExtension:@"jsbundle"];

#endif

    NSLog(@"文件不存在");

    returnjsCodeLocation;

  }

}

判断代码

大功告成运行项目。

到这里最基础的热更新/热部署服务就搭建完成。如果想要更加完善还是需要花点功夫的,毕竟师傅领进门修行靠个人。

上一篇下一篇

猜你喜欢

热点阅读