React-Native开发iOS篇-热更新的代码实现

前端之家收集整理的这篇文章主要介绍了React-Native开发iOS篇-热更新的代码实现前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

转载:http://www.jianshu.com/p/dc527de06b5e

但是这位博主,源代码没有完全开放,我只是按照他的思路将代码补全,并将源代码开放

需求

1.在打开APP的时候进行网络请求,检查是否有网络更新。

2.如果有网络更新,下载新的版本,再次打开APP的时候,就直接连接到新的内容

具体功能的实现:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [[UpdateDataLoader sharedInstance] createPath];
  [[UpdateDataLoader sharedInstance] getAppVersion];
   [self testCopy];
  //检查更新并下载,有更新则直接下载,无则保持默认配置
  //定义加载bundle的URL
  NSURL *jsCodeLocation;
  NSString* iOSBundlePath = [[UpdateDataLoader sharedInstance] iOSFileBundlePath];
  if ([[NSFileManager defaultManager] fileExistsAtPath:iOSBundlePath]) {
    jsCodeLocation = [NSURL URLWithString:[iOSBundlePath stringByAppendingString:@"/index.ios.jsbundle"]];
     
  }else{
    jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
  }
    NSLog(@"jsCodeLocation%@",jsCodeLocation);
  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"CMEngineRoom"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];
  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
  [DownLoadTool defaultDownLoadTool].view = rootView;
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  return YES;
}


上述代码是在Appdelegate中的实现,关键点有两个:
1.实现对版本号的数据持久化存储。
2.如何加载沙盒路径下的js.bundle文件


实现数据持久化的方法

在三种数据持久化得方式中,我选择了plist文件去存储版本号和下载路径。


实现从本地文件夹中获取bundle并加载

在这里,有以下几个问题需要去解决

@H_502_36@
  • 如何下载?
  • 下载完毕后如何解压?
  • 解压完成后如何配置文件
  • 首先解决如何下载的问题,在这里我选择了第三方AFNetworking 3.0来实现对文件的下载。

    使得下载主动进行。

    在下载完毕之后的block回调中,是在主线程中进行的,在这里就可以进行一些UI的更新。

    注意在完成之后返回的文件路径filePath为:
    file:///*********
    直接进行使用发现,获取不到文件
    必须将file:///去掉才能解决问题。
    利用nsstring提供的方法来实现。

    在这里需要注意的是每个下载的设置默认是被挂起的,所以在设置完毕之后,需要调用

    [downloadTask resume]
    使得下载主动进行。



    OK解决的下载问题,现在来解决解压问题,解压方式我选择了第三方提供的SSZipArchive.


    最后,来解决一下如何配置的问题:
    在各种文档里都没有找到说明如何加载一个现有的js.bundle文件
    经过我个人的几番尝试,我找到了如下方法

     NSURL *jsCodeLocation;
    jsCodeLocation = [NSURL URLWithString:iOSBundlePath];
    
    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                          moduleName:@"Dingla"
                                                   initialProperties:nil
                                                       launchOptions:launchOptions];


    iOSBUndlepath为沙盒内的文件路径。

    至此,iOS的热更新就实现了。


    源码实现

    DownloadTool.h

    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    @interface DownLoadTool : NSObject
    
    @property (nonatomic,strong) NSString *zipPath;
    
    @property (nonatomic,strong) UIView*  view;
    
    + (DownLoadTool *) defaultDownLoadTool;
    
    //根据url下载相关文件
    -(void)downLoadWithUrl:(NSString*)url;
    //解压压缩包
    -(BOOL)unZip;
    //删除压缩包
    -(void)deleteZip;
    
    @end
    

    DownloadTool.m
    #import "DownLoadTool.h"
    #import "SSZipArchive.h"
    #import "AFURLSessionManager.h"
    #import "UpdateDataLoader.h"
    
    @implementation DownLoadTool
    + (DownLoadTool *) defaultDownLoadTool{
      static DownLoadTool *sharedInstance = nil;
      static dispatch_once_t onceToken;
      
      dispatch_once(&onceToken,^{
        sharedInstance = [[DownLoadTool alloc] init];
      });
      
      return sharedInstance;
    }
    
    //下载了一个dmg文件
    //https://www.baidu.com/link?url=AH4YJUtQK3tB6D6BARqSkZzQsax38iBawDvAXK1wVGVplkkmuhf7mkpc6barjlavO6ysikDjimVG7d0l8KAFvorDmM3K_T5aIES89-JdQEG&wd=&eqid=e165a7c1000050c3000000035993b22c
    
    -(void)downLoadWithUrl:(NSString*)url{
      //根据url下载相关文件
      NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
      AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
      NSURL *URL = [NSURL URLWithString:url];
      NSURLRequest *request = [NSURLRequest requestWithURL:URL];
      NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        //获取下载进度
             NSLog(@"Progress is %f",downloadProgress.fractionCompleted);
      } destination:^NSURL *(NSURL *targetPath,NSURLResponse *response) {
        //有返回值的block,返回文件存储路径
        NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
        NSURL* targetPathUrl = [documentsDirectoryURL URLByAppendingPathComponent:@"kiOSFileName"];
        return [targetPathUrl URLByAppendingPathComponent:[response suggestedFilename]];
        
      } completionHandler:^(NSURLResponse *response,NSURL *filePath,NSError *error) {
        if(error){
          //下载出现错误
          NSLog(@"%@",error);
          
        }else{
          // [self showPromptWithStr:@"更新完毕。请重新启动******!"];
          //下载成功
          NSLog(@"File downloaded to: %@",filePath);
          self.zipPath = [[filePath absoluteString] substringFromIndex:7];
          //下载成功后更新本地存储信息
            NSDictionary*infoDic=@{@"bundleVersion":@3,@"downloadUrl":url};
            [UpdateDataLoader sharedInstance].versionInfo=infoDic;
            
         [[UpdateDataLoader sharedInstance] writeAppVersionInfoWithDictiony:[UpdateDataLoader sharedInstance].versionInfo];
            
          //解压并删除压缩包
          if ([self unZip]) {
            [self deleteZip];
          };
          
        }
      }];
      [downloadTask resume];
    }
    
    //解压压缩包
    -(BOOL)unZip{
      if (self.zipPath == nil) {
        return NO;
      }
      //检查Document里有没有bundle文件夹
      NSString* path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0];
      NSString* bundlePath = [path stringByAppendingPathComponent:@"kiOSfileSetName"];
      BOOL isDir;
      //如果有,则删除后解压,如果没有则直接解压
      if ([[NSFileManager defaultManager] fileExistsAtPath:bundlePath isDirectory:&isDir]&&isDir) {
        [[NSFileManager defaultManager] removeItemAtPath:bundlePath error:nil];
      }
      NSString *zipPath = self.zipPath;
      NSString *destinationPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES) objectAtIndex:0]stringByAppendingString:@"/IOSBundle"];
      BOOL success = [SSZipArchive unzipFileAtPath:zipPath
                                     toDestination:destinationPath];
      return success;
    }
    
    //删除压缩包
    -(void)deleteZip{
      NSError* error = nil;
      [[NSFileManager defaultManager] removeItemAtPath:self.zipPath error:&error];
    }
    
    @end
    

    UpdateDataLoader.h


    #import <Foundation/Foundation.h>
    
    @interface UpdateDataLoader : NSObject
    
    @property (nonatomic,strong) NSDictionary* versionInfo;
    + (UpdateDataLoader *) sharedInstance;
    
    
    
    //创建bundle路径
    -(void)createPath;
    //获取版本信息
    -(void)getAppVersion;
    
    -(void)writeAppVersionInfoWithDictiony:(NSDictionary*)info;
    
    -(NSString*)iOSFileBundlePath;
    
    @end

    UpdateDataLoader.m
    #import "UpdateDataLoader.h"
    #import "DownLoadTool.h"
    
    @implementation UpdateDataLoader
    + (UpdateDataLoader *) sharedInstance
    {
        static UpdateDataLoader *sharedInstance = nil;
        static dispatch_once_t onceToken;
      
         dispatch_once(&onceToken,^{
          sharedInstance = [[UpdateDataLoader alloc] init];
         });
      
        return sharedInstance;
    }
    //创建bundle路径
    -(void)createPath{
      
        if([self getVersionPlistPath]){
            return;
        }
      NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES);
      NSString *path = [paths lastObject];
      
      NSFileManager *fileManager = [NSFileManager defaultManager];
      NSString *directryPath = [path stringByAppendingPathComponent:@"IOSBundle"];
      [fileManager createDirectoryAtPath:directryPath withIntermediateDirectories:YES attributes:nil error:nil];
      NSString *filePath = [directryPath stringByAppendingPathComponent:@"Version.plist"];
      [fileManager createFileAtPath:filePath contents:nil attributes:nil];
    }
    //获取版本信息
    -(void)getAppVersion{
      
      //从服务器上获取版本信息,与本地plist存储的版本进行比较
      //假定返回的结果集
       /*{
        bundleVersion = 2;
        downloadUrl = "www.baidu.com";
       }*/
      
      //1.获取本地plist文件的版本号 假定为2
      NSString* plistPath=[self getVersionPlistPath];
      NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
        
        
      NSInteger localV=[data[@"bundleVersion"]integerValue];
      
      localV=2;
      
      
      //2  服务器版本 假定为3
      NSInteger serviceV=3 ;
      
      if(serviceV>localV){
        //下载bundle文件 存储在 Doucuments/IOSBundle/下
          
           NSString*url=@"https://www.baidu.com/link?url=AH4YJUtQK3tB6D6BARqSkZzQsax38iBawDvAXK1wVGVplkkmuhf7mkpc6barjlavO6ysikDjimVG7d0l8KAFvorDmM3K_T5aIES89-JdQEG&wd=&eqid=e165a7c1000050c3000000035993b22c";
        
        [[DownLoadTool defaultDownLoadTool] downLoadWithUrl:url];
      
      }else{
      
      }
    }
    
    //获取Bundle 路径
    -(NSString*)iOSFileBundlePath{
        //获取沙盒路径
        NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES);
        NSString* path = [paths objectAtIndex:0];
        NSLog(@"the save version file's path is :%@",path);
        //填写文件名
        NSString* filePath = [path stringByAppendingPathComponent:@"/IOSBundle"];
        return  filePath;
    }
    
    //获取版本信息储存的文件路径
    -(NSString*)getVersionPlistPath{
      
      //获取沙盒路径
      NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,YES);
      NSString* path = [paths objectAtIndex:0];
      NSLog(@"the save version file's path is :%@",path);
      //填写文件名
      NSString* filePath = [path stringByAppendingPathComponent:@"/IOSBundle/Version.plist"];
      NSLog(@"文件路径为:%@",filePath);
      return filePath;
    }
    
    //创建或修改版本信息
    -(void)writeAppVersionInfoWithDictiony:(NSDictionary*)dictionary{
        
      NSString* filePath  = [self getVersionPlistPath];
      [dictionary writeToFile:filePath atomically:YES];
    }
    

    猜你在找的React相关文章