首页 > 代码库 > react native ios版本热更新

react native ios版本热更新

react native 热更新的好处

js脚本代码改变了,比如对ui进行了一些修改,客户端要是想更新的话,如果直接下载apk 或者ipa,一个是浪费流量,还有比较麻烦

热更新只要下载打包好的bundle 文件,然后进行替换就可以了

思路比较简单,客户端跟服务端都维持 一个bundle版本信息,如果服务端的版本比客户端的 版本新就下载,然后替换掉 重新渲染就OK了

具体实现,如果没有 热更新,载入bundle的代码是这样的

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

如果加入热更新,是这样的

NSURL *jsCodeLocation=nil;

  jsCodeLocation=[self getBundle];
  
  if(jsCodeLocation==nil)
  {
    jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
  }
getBundle 函数就包含加载 服务端获取到的bundle 的逻辑

-(NSURL *) getBundle
{
  NSString* ss=@"#####";//服务端bundle版本号的地址
  NSString* str = [self httpGet:ss];
  NSString *pathDocuments=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
  
  NSString *createPath=[NSString stringWithFormat:@"%@/%@",pathDocuments,@"version.txt"];//用文件名补全路径
  Boolean bb=false;
  NSFileManager *defaultManager;
  defaultManager = [NSFileManager defaultManager];
  NSURL *nsurl=nil;
  if ([[NSFileManager defaultManager] fileExistsAtPath:createPath])//判断文件是否已存在
  {
     NSString* fileContents = [NSString stringWithContentsOfFile:createPath encoding:NSUTF8StringEncoding error:nil];
    int a=[str intValue];//服务端bundle版本号
    int b=[fileContents intValue];//客户端bundle版本信息
    if(a>b)//如果服务端的bundle版本比加大,就删除客户端的bundle,然后更新成服务端的
    {
      if ([[NSFileManager defaultManager] fileExistsAtPath:createPath])//判断文件是否已存在
      {
        [defaultManager removeItemAtPath:createPath error:NULL];
      }
      [self storeFile:@"version.txt" content:str];
      bb=true;
    }
    else//如果发现下载的bundle文件不存在,也要下载更新
    {
      createPath=[NSString stringWithFormat:@"%@/%@",pathDocuments,@"main.jsbundle"];
      if (![[NSFileManager defaultManager] fileExistsAtPath:createPath])//判断文件是否已存在
      {
        bb=true;
      }
    }
  }
  else//如果客户端的bundle是空,也要下载
  {
   [self storeFile:@"version.txt" content:str];
    bb=true;
  }
  if (bb==true) {
    createPath=[NSString stringWithFormat:@"%@/%@",pathDocuments,@"main.jsbundle"];
   if ([[NSFileManager defaultManager] fileExistsAtPath:createPath])//判断文件是否已存在
    {
      [defaultManager removeItemAtPath:createPath error:NULL];
    }
    ss=@"####";//服务端bundle文件的地址
    str = [self httpGet:ss];
    
    NSString *fileName=[self storeFile:@"main.jsbundle" content:str];
    nsurl=[NSURL fileURLWithPath:fileName];//这是bundle 文件的路径
    
  }
  else{
    createPath=[NSString stringWithFormat:@"%@/%@",pathDocuments,@"main.jsbundle"];
    nsurl=[NSURL fileURLWithPath:createPath];//这是bundle 文件的路径
  }
  return nsurl;
  
}
-(NSString *) httpGet:(NSString *)ss
{
  //第一步,创建URL
  NSURL *url = [NSURL URLWithString:ss];
  
  //第二步,通过URL创建网络请求
  NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
  //NSURLRequest初始化方法第一个参数:请求访问路径,第二个参数:缓存协议,第三个参数:网络请求超时时间(秒)
  /*其中缓存协议是个枚举类型包含:
   NSURLRequestUseProtocolCachePolicy(基础策略)
   NSURLRequestReloadIgnoringLocalCacheData(忽略本地缓存)
   NSURLRequestReturnCacheDataElseLoad(首先使用缓存,如果没有本地缓存,才从原地址下载)
   NSURLRequestReturnCacheDataDontLoad(使用本地缓存,从不下载,如果本地没有缓存,则请求失败,此策略多用于离线操作)
   NSURLRequestReloadIgnoringLocalAndRemoteCacheData(无视任何缓存策略,无论是本地的还是远程的,总是从原地址重新下载)
   NSURLRequestReloadRevalidatingCacheData(如果本地缓存是有效的则不下载,其他任何情况都从原地址重新下载)*/
  //第三步,连接服务器
  NSData *received = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
  
  NSString *str = [[NSString alloc]initWithData:received encoding:NSUTF8StringEncoding];
  return str;
}
//存储文件
-(NSString *)storeFile:(NSString *)fileName content:(NSString *)writeContent
{
  NSString *pathDocuments=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
  
  NSString *createPath=[NSString stringWithFormat:@"%@/%@",pathDocuments,fileName];//用文件名补全路径
  NSError *ReadFileError;
  NSString *readContent ;
  NSData *data ;
  if ([[NSFileManager defaultManager] fileExistsAtPath:createPath])//判断文件是否已存在
  {
    if (nil == writeContent) {
      readContent = [NSString stringWithContentsOfFile:createPath encoding:NSUTF8StringEncoding error:&ReadFileError];
    }else{
      data = [writeContent dataUsingEncoding:NSUTF8StringEncoding];//新文件的初始数据
      [[NSFileManager defaultManager] createFileAtPath:createPath contents:data attributes:nil];//创建文件
      readContent = [NSString stringWithContentsOfFile:createPath encoding:NSUTF8StringEncoding error:&ReadFileError];
    }
  }
  else
  {
    if (nil == writeContent) {
      return nil;
    }else{
      data = [writeContent dataUsingEncoding:NSUTF8StringEncoding];//新文件的初始数据
      [[NSFileManager defaultManager] createFileAtPath:createPath contents:data attributes:nil];//创建文件
      readContent = [NSString stringWithContentsOfFile:createPath encoding:NSUTF8StringEncoding error:&ReadFileError];
    }
  }
  return createPath;
}

以上就是主要代码,有注释说明意思

ios bundle打包脚本如下

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

 

 

 

 

react native ios版本热更新