react native 实现自定义热更新(android+ios)

react native 已经集成好的热更新方案:codePush

自定义热更新实现逻辑:其实就是修改bundlejs

Android 具体实现:

1.在rn目录下运行命令,打包 bundlejs 和静态文件,打包之后需要将文件进行压缩上传。

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

注意, ./bundle/android 这个文件是自定义的,你想保存到那里就去修改。(注意:需要先创建文件夹,不然会报错)

2.在 android 文件夹中,找到 MainApplication.java 这个文件,在 ReactNativeHostWrapper 中添加入这段代码,像相当于重写了 getJSBundleFile 这个方法。(这一步相当于替换运行的bundlejs)

@Override        
protected String getJSBundleFile() {
          // 检查本地bundle文件是否存在
          String localBundlePath = new File(getFilesDir(), "android/index.android.bundle").getAbsolutePath();
          File bundleFile = new File(localBundlePath);
          // 如果本地bundle文件存在,则使用它
          if (bundleFile.exists()) {
            return bundleFile.getAbsolutePath();
          } else {
            // 如果本地bundle不存在,则使用默认bundle
            return super.getJSBundleFile();
          }
        }

3.在rn代码中找到合适的位置下载并且替换bundlejs文件,代码大概如下(这一步是下载并且解压代码)

//下载并替换bundle
export const downloadAndReplaceBundle = async (updateInfo) => {
    const libraryPath = `${IS_ANDROID ? RNFetchBlob.fs.dirs.DocumentDir : RNFetchBlob.fs.dirs.LibraryDir}`;
    const dirName = `${IS_ANDROID ? 'android' : 'ios'}`;
    try {
        const path = `${libraryPath}`;
        const zipPath = `${path}/bundlezip`;
        let zipRes;
        zipRes = await RNFetchBlob.config({
            path: zipPath, // 指定保存路径
            fileCache: true, // 启用文件缓存
            timeout: 120000, // 设置超时时间
        }).fetch('GET', getFileUrl(updateInfo?.hotUrl)); // 使用 GET 请求下载文件
        //解压
        await unzip(zipRes.path(), path);
        // 重启
        setTimeout(() => {
            RNRestart.Restart();
        }, 1000);
    } catch (error) {

    }
};

 这里我用到了

rn-fetch-blob    react-native-zip-archive   react-native-restart 

这三个包,分别是下载,解压,重启应用的功能。

解压到你能找的目录就行,然后在原生的android代码中也要读取这个目录下的bundlejs。

然后 android 的热更新就大功告成了。

Ios具体实现

其实rn的代码都是这样做,不通过的地方就是需要在 ios 原生代码中读取相应的 bundlejs

首先是打包 ios的bundlejs

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

同样的,打包后的文件的位置是自定义的。

然后就是原生iOS代码中替换bundlejs

在 ios 文件夹中找到 AppDelegate.m 或者 AppDelegate.mm 这文件,然后找到这段代码

#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

直接把 else 后面的代码去掉,修改成

#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
  // 检查本地bundle文件是否存在
  NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"main" ofType:@"jsbundle"];
  NSFileManager *fileManager = [NSFileManager defaultManager];

  // // 获取Library目录下的bundle文件路径
  NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
  NSString *localBundlePath = [libraryPath stringByAppendingPathComponent:@"ios/main.jsbundle"];


  // 如果本地bundle存在,使用本地bundle
  if ([fileManager fileExistsAtPath:localBundlePath]) {
    NSLog(@"存在本地bundle,使用本地bundle");
    return [NSURL fileURLWithPath:localBundlePath];
  }

  NSLog(@"不存在本地bundle,使用默认bundle");

  // 否则使用默认bundle
  return [NSURL fileURLWithPath:bundlePath];
#endif

然后就大功告成了。


总结:整体流程就是 下载-解压-替换,就完成热更新了。


ps:这个只是简易的实现,后续可能还要考虑到,热更完成之后,出现错误需要回滚等等等等的事情。这个我会在下一篇文章中说一下我目前这个项目的处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值