美文网首页Hybrid开发
RN拆包解决方案(二) bundle加载

RN拆包解决方案(二) bundle加载

作者: gy先生 | 来源:发表于2019-12-29 13:51 被阅读0次

    前言

    本文跟随上一篇RN拆包解决方案(一) bundle拆分,已打出common.bundle和patch.bundle文件为前提,引入工程项目中

    iOS原生加载流程

    RCTBridge开放私有方法

    @interface RCTBridge (ReactExecuteScript)
    
    - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync;
    
    @end
    

    预先加载common包

    在App项目完全启动完成后,可预先加载通用包,缓存到内存中

    jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"common" withExtension:@"jsbundle"];
    bridge = [[RCTBridge alloc] initWithBundleURL:jsCodeLocation
                                 moduleProvider:nil
                                  launchOptions:launchOptions];
    

    加载业务包

    当用户跳转路由到某个RN页面时加载patch部分

    NSURL *jsCodeLocationBiz = [[NSBundle mainBundle] URLForResource:@"patch" withExtension:@"jsbundle"];
    NSError *error = nil;
    NSData *sourceBuz = [NSData dataWithContentsOfFile:jsCodeLocationBiz.path
                                             options:NSDataReadingMappedIfSafe
                                               error:&error];
    [bridge.batchedBridge executeSourceCode:sourceBuz sync:NO];
    

    需要注意的是,加载业务包的流程必须在common完全加载完毕后执行,否则会出现加载异常;由于没有提供加载完成的回调,只能通过侦听isLoading状态变化来处理

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
      //加载common
      
      while (bridge.isLoading) {//侦听common加载完成
      }
      
      //...
      //加载业务包
    });
    

    绑定到视图RCTRootView

    RCTRootView *view = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:nil];
    

    由此可见,加载common和patch都在同一个RCTBridge容器中执行,最终绑定到RCTRootView展示

    Android原生加载流程

    使用ReactInstanceManager加载基础包

    首先需要初始化RN的运行环境。加载common使公共的模块代码优先执行,不会涉及视图的绑定渲染

    jsbundleFile = "assets://common.bundle";
    final ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
                    .setApplication(application)
                    .addPackage(new MainReactPackage())
                    .setJSBundleFile(jsbundleFile);
    ReactInstanceManager manager = builder.build();
    

    按需加载业务包

    通过ReactInstanceManager获取CatalystInstance实例,此实例负责继续加载业务包

    ReactContext context = manager.getCurrentReactContext();
    CatalystInstance instance = context.getCatalystInstance();
    
    String source = "assets://patch.bundle";
    ((CatalystInstanceImpl)instance).loadScriptFromAssets(context.getAssets(), source,loadSynchronously);
    

    同理,加载业务包需要在common加载完成后执行

    //加载common包
    //...
    if (!manager.hasStartedCreatingInitialContext()) {
        manager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
            @Override
            public void onReactContextInitialized(ReactContext context) {
                manager.removeReactInstanceEventListener(this);
                //...
                //加载业务包
            }
        });
        manager.createReactContextInBackground();
    }
    

    绑定到视图

    当用户进入RN页面时在activity层创建并显示

    reactRootView = new ReactRootView(this);
    reactRootView.startReactApplication(manager, moduleName, null);
    setContentView(reactRootView);
    

    总结

    RN拆包流程,最终还是要归功于 RN 基于 javascript 设计的灵活性。分步的执行方式能够让我们轻松的将 Bundle 的加载、视图的渲染分步进行,互不影响;

    相关文章

      网友评论

        本文标题:RN拆包解决方案(二) bundle加载

        本文链接:https://www.haomeiwen.com/subject/luuyoctx.html