返回顶部
首页 > 资讯 > 前端开发 > JavaScript >简析React Native startReactApplication 方法
  • 218
分享到

简析React Native startReactApplication 方法

2024-04-02 19:04:59 218人浏览 泡泡鱼
摘要

在 React Native 启动流程简析 这篇文章里,我们梳理了 RN 的启动流程,最后的 startReactApplication 由于相对复杂且涉及到最终执行前端 js 的流

React Native 启动流程简析 这篇文章里,我们梳理了 RN 的启动流程,最后的 startReactApplication 由于相对复杂且涉及到最终执行前端 js 的流程,我们单独将其提取出来,独立成文加以分析。

首先来看 startReactApplication 的调用之处:


mReactRootView.startReactApplication(
    getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);

可以看到是在 rootView 上调用 startReactApplication,入参为 instanceManager、appKey、mLaunchOptions

顺着 startReactApplication 扒出其调用链:

mReactInstanceManager.createReactContextInBackground() -> recreateReactContextInBackgroundInner() -> recreateReactContextInBackgroundFromBundleLoader() -> recreateReactContextInBackground() -> runCreateReactContextOnNewThread()

recreateReactContextInBackgroundReactInstanceManager 中的方法,做了两件事:

1.创建 ReactContextInitParams 实例 initParams,如下,其入参 jsExecutorFactory 为创建 ReactInstanceManager 时传入。


final ReactContextInitParams initParams =
    new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);

2.调用 runCreateReactContextOnNewThread

runCreateReactContextOnNewThreadReactInstanceManager 中的方法,主要做了两件事:

  1. 创建一个新的线程,并在新线程中通过 createReactContext 创建 ReactContext 上下文;
  2. 通过 setupReactContext 来设置上下文环境,并最终调用到 AppReGIStry.js 启动App。

createReactContext

先看其调用的地方:


final ReactApplicationContext reactApplicationContext =
    createReactContext(
        initParams.getJsExecutorFactory().create(),
        initParams.getJsBundleLoader());

其两个入参分别为 JsExecutorFactory 创建的 javascriptExecutor 实例,和 JsBundleLoader 实例。

JavaScriptExecutor

startReactApplication 第一个入参为 getReactNativeHost().getReactInstanceManager() 获取 ReactInstanceManager 实例。ReactInstanceManager 实例在 RN 应用中只有一个,先前在创建 MainActivity 时已创建。

回顾 React Native 启动流程简析,在创建过程中实际上是调用下面的方法:


ReactInstanceManager reactInstanceManager = builder.build()

builderReactInstanceManagerBuilder,我们来到该类的 build 方法,发现其最终是执行 return new ReactInstanceManager(...),在构造参数中第 4 个参数即为:getDefaultJSExecutorFactory,来到其定义处:


 private JavaScriptExecutorFactory getDefaultJSExecutorFactory(
      String appName, String deviceName, Context applicationContext) {
    try {
      // If JSC is included, use it as nORMal
      initializeSoLoaderIfNecessary(applicationContext);
      SoLoader.loadLibrary("jscexecutor");
      return new JSCExecutorFactory(appName, deviceName);
    } catch (UnsatisfiedLinkError jscE) {  }
}

也就是说在创建 ReactInstanceManagerBuilder 时我们就创建了 JSCExecutorFactory,并在随后调用其 create 方法创建 JSCExecutorJSCExecutorFactory 实现了 JavaScriptExecutorFactory 接口,其 create 方法如下,返回了 JSCExecutor 实例:


 @Override
  public JavaScriptExecutor create() throws Exception {
    WritableNativeMap jscConfig = new WritableNativeMap();
    jscConfig.putString("OwnerIdentity", "ReactNative");
    jscConfig.putString("AppIdentity", mAppName);
    jscConfig.putString("DeviceIdentity", mDeviceName);
    return new JSCExecutor(jscConfig);
  }

再往下看 JSCExecutor 的定义,其继承自 JavaScriptExecutor 类:


@DoNotStrip
 class JSCExecutor extends JavaScriptExecutor {
  static {
    SoLoader.loadLibrary("jscexecutor");
  }
   JSCExecutor(ReadableNativeMap jscConfig) {
    super(initHybrid(jscConfig));
  }
  @Override
  public String getName() {
    return "JSCExecutor";
  }
  private static native HybridData initHybrid(ReadableNativeMap jscConfig);
}

于是就很清楚了,createReactContext 第一个参数为 JSCExecutor 实例,是通过 SoLoader 加载的 c++ 模块。

JsBundleLoader

同样的,在 return new ReactInstanceManager(...),其构造参数中第 5 个参数为:JSBundleLoader.createAssetLoader(mApplication, mJSBundleAssetUrl, false)

来到其定义之处,发现其返回了 JSBundleLoader 实例,并重写了其 loadScript 方法。


public static JSBundleLoader createAssetLoader(
    final Context context, final String assetUrl, final boolean loadSynchronously) {
  return new JSBundleLoader() {
    @Override
    public String loadScript(JSBundleLoaderDelegate delegate) {
      delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
      return assetUrl;
    }
  };
}

在创建完 JSCExecutor 实例和 JSBundleLoader 实例后,正式进入到 createReactContext 方法。

createReactContext


private ReactApplicationContext createReactContext(
  final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);

  CatalystInstanceImpl.Builder catalystInstanceBuilder = 

  try {
    catalystInstance = catalystInstanceBuilder.build();
  } finally {  }

  reactContext.initializeWithInstance(catalystInstance);

  TurboModuleManager turboModuleManager =
    new TurboModuleManager(  )

  catalystInstance.setTurboModuleManager(turboModuleManager);

  if (mJSIModulePackage != null) {
    catalystInstance.addJSIModules(  );
  }

  catalystInstance.runJSBundle();
  return reactContext;

在这里面,首先创建了 reactContext,并通过 catalystInstanceBuilder 创建了 catalystInstance。接着通过 initializeWithInstance 方法将 reactContextcatalystInstance 关联起来,并进行了一系列的为 catalystInstance 初始化的工作。最后进入到方法 catalystInstance.runJSBundle() 中。

initializeWithInstance

通过调用 getUIQueueThreadgetNativeModulesQueueThreadgetJSQueueThread创建了3个线程队列,分别是 UI线程、NativeModules 线程,和 JS 线程。

runJSBundle


public void runJSBundle() {
  mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
  synchronized (mJSCallsPendingInitLock) {
    MacceptCalls = true;
    for (PendingJSCall function : mJSCallsPendingInit) {
      function.call(this);
    }
    mJSCallsPendingInit.clear();
    mJSBundleHasLoaded = true;
  }
  Systrace.registerListener(mTraceListener);
}

通过先前返回的 mJSBundleLoader 执行其 loadScript 方法:


public String loadScript(JSBundleLoaderDelegate delegate) {
  delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
  return assetUrl;
}

loadScriptFromAssets 方法在 CatalystInstanceImpl 中:


public void loadScriptFromAssets(
    AssetManager assetManager, String assetURL, boolean loadSynchronously) {
  mSourceURL = assetURL;
  jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
}

这里的 assetURL 是在 createAssetLoader 创建 mJSBundleLoader 时传入,其赋值时机是在 reactInstanceManagerBuilder 实例中,由 reactNativeHost 实例的 createReactInstanceManager 方法。若 开发者在 MainApplication.java 中通过重写 getJSBundleFile 方法自定义了 assetURL 则使用该 url,否则使用系统默认,如:file://sdcard/myapp_cache/index.Android.bundle

jniLoadScriptFromAssets 方法为 C++ 侧定义的方法,用于读取 js 文件。为什么 Java 代码中可以直接调用 C++ 方法,这里还要打个问号,后续在分析 Java 与 C++ 通信及 Java 与 JS 通信时阐释。

通过 createReactContext 创建了 reactContext,创建了 catalystInstance 实例,并将上述两者关联,接着通过 catalystInstance 读入 js 文件。接下来就进入到 setupReactContext 的环节。

setupReactContext


private void setupReactContext(final ReactApplicationContext reactContext) {
    synchronized (mAttachedReactRoots) {
      catalystInstance.initialize();
      for (ReactRoot reactRoot : mAttachedReactRoots) {
        if (reactRoot.getState().compareAndSet(ReactRoot.STATE_STOPPED, ReactRoot.STATE_STARTED)) {
          attachRootViewToInstance(reactRoot);
        }
      }
    }
    UiThreadUtil.runOnUiThread(
      public void run() {
        listener.onReactContextInitialized(reactContext);
      }
    )
    reactContext.runOnJSQueueThread(
      public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
      }
    )
    reactContext.runOnNativeModulesQueueThread(
      public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
      }
    )
}

这里面做的事情如下:

  • catalystInstance.initialize(): 所有原生模块的初始化
  • attachRootViewToInstance(reactRoot): 绘制所有的 RootView 并添加到相应实例并设置相应的监听事件
  • 创建 UI 模块、JS 模块和原生模块线程,并设置 JS 模块和原生模块所在线程的优先级

总结本文

从 createReactContext 和 setupReactContext 两个方法的源码出发,分析了 RN startReactApplication 方法的执行过程,其中:

createReactContext 的主要作用是:创建 reactContext、创建 catalystInstance 实例,并将上述两者关联,接着通过 catalystInstance 读入 js 文件。

setupReactContext的主要作用是:初始化所有原生模块,绘制所有 rootview,创建 UI 模块、JS 模块和原生模块线程,并设置优先级。

到此这篇关于React Native startReactApplication 方法简析的文章就介绍到这了,更多相关React Native startReactApplication内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 简析React Native startReactApplication 方法

本文链接: https://lsjlt.com/news/134966.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 简析React Native startReactApplication 方法
    在 React Native 启动流程简析 这篇文章里,我们梳理了 RN 的启动流程,最后的 startReactApplication 由于相对复杂且涉及到最终执行前端 js 的流...
    99+
    2024-04-02
  • react-native弹窗封装的方法
    本文实例为大家分享了react-native弹窗封装的具体代码,供大家参考,具体内容如下 上图 仿苹果弹窗组件(android+ios均可用) 以上效果均基于本文的弹窗组件,后...
    99+
    2024-04-02
  • 框架分析(8)-React Native
    框架分析(8)-React Native 专栏介绍React Native特性和优势跨平台开发:热更新原生性能组件化开发第三方库支持社区支持 限制和挑战性能问题第三方库兼容性学习曲线 ...
    99+
    2023-09-05
    react native react.js javascript
  • React Native 加载H5页面的实现方法
    目录一、基本使用1.1 RN向H5发送数据1.2 H5向RN传递数据1.3 双向传值二、属性和方法2.1 属性2.2 方法三、使用示例3.1 加载外源网页信息3.2 登陆场景3.3 ...
    99+
    2024-04-02
  • React Native 启动流程详细解析
    导读:本文以 react-native-cli 创建的示例工程(安卓部分)为例,分析 React Native 的启动流程。 工程创建步骤可以参考官网。本文所分析 React Nat...
    99+
    2024-04-02
  • React Native项目中使用Lottie动画的方法
    Lottie是Airbnb开源的一个面向iOS、Android、React Native的动画库,能加载Adobe After Effects导出的动画,并且能让原生App像使用静态...
    99+
    2024-04-02
  • 在 React Native 中使用 CSS Modules的配置方法
    目录安装依赖和配置使用示例有些前端工程师希望也能像开发 web 应用那样,使用 CSS Modules 来开发 React Native。本文将介绍如何在 React Native ...
    99+
    2022-11-13
    React Native使用 CSS Modules React  CSS Modules
  • Android React-Native通信数据模型分析
    无论是计算机领域还是日常生活中,我们所言的通信,其核心都是数据信息的交换,而数据模型的优劣对通信效率有着决定性的作用。 在React-Native项目中,Javascript语...
    99+
    2022-06-06
    数据模型 数据 模型 native React Android
  • react-native之ART绘图的示例分析
    小编给大家分享一下react-native之ART绘图的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!背景在移动应用的开...
    99+
    2024-04-02
  • react-native只保留3x图原理解析
    目录引言1. 输出构建产物2. RN如何决定加载哪张scale图片?3. repo中是否可以只保留3x图?3.1 资源上传3.2 资源下载4. 结论引言 我们的react-nati...
    99+
    2023-01-13
    react-native保留3x图 react-native
  • React Native集成支付宝支付的实现方法
    在RN应用开发过程中,集成支付宝和微信支付除了直接使用第三方的插件之,比如:react-native-yunpeng-alipay,我们还可以借助RN提供的NativeModules...
    99+
    2024-04-02
  • react-native消息推送实现方式
    目录react-native极光推送一、安装插件二、配置安卓配置IOS配置三、使用解决ios角标无法清除总结react-native极光推送 先去官网注册:https://www.j...
    99+
    2023-02-18
    react-native消息推送 react-native 消息推送
  • 用React Native制作一个简单的游戏引擎
    目录简介开始吧对React Native游戏引擎的简单介绍让我们在React Native中建立一个蛇形游戏创建游戏实体游戏逻辑移动蛇头"游戏结束!"条件食用食物控制蛇尾巴功能结语简...
    99+
    2024-04-02
  • React-Native左右联动List的示例分析
    这篇文章将为大家详细讲解有关React-Native左右联动List的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一:左右联动List,在工作中很常见。今天分享...
    99+
    2024-04-02
  • React Native自定义标题栏组件的实现方法
    大家好,今天讲一下如何实现自定义标题栏组件,我们都知道RN有一个优点就是可以组件化,在需要使用该组件的地方直接引用并传递一些参数就可以了,这种方式确实提高了开发效率。标题栏是大多数应用界面必不可少的一部分,将标题栏剥离出来做成一个组件很有必...
    99+
    2023-05-31
    react native 标题栏
  • 在 React Native 中给第三方库打补丁的过程解析
    目录安装使用示例有时使用了某个React Native 第三方库,可是它有些问题,我们不得不修改它的源码。本文介绍如何修改源码又不会意外丢失修改结果的方法。 我们可能不方便给原作者提...
    99+
    2022-11-13
    React Native第三方库打补丁 React Native第三方库
  • React Native与web的基本交互方式
    本篇内容介绍了“React Native与web的基本交互方式”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成...
    99+
    2024-04-02
  • React Native图片查看组件的示例分析
    这篇文章将为大家详细讲解有关React Native图片查看组件的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。React Native 图片查看组件:react...
    99+
    2024-04-02
  • 响应式React Native Echarts组件的示例分析
    小编给大家分享一下响应式React Native Echarts组件的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前言...
    99+
    2024-04-02
  • react native原生模块桥接的示例分析
    这篇文章主要介绍react native原生模块桥接的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Android创建原生模块包通过继承 ReactPackage 为你的原生...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作