React Native 启动流程详细解析

 更新时间:2021年08月17日 11:55:48   作者:大闲人三石兄  
这篇文章主要介绍了React Native 启动流程简析,文以 react-native-cli 创建的示例工程(安卓部分)为例,给大家分析 React Native 的启动流程,需要的朋友可以参考下

导读:本文以 react-native-cli 创建的示例工程(安卓部分)为例,分析 React Native 的启动流程。

工程创建步骤可以参考官网。本文所分析 React Native 版本为 v0.64.2

我们知道上述工程是一个安卓应用,打开 android/ 目录下源码文件,首先发现它创建了两个 java 文件:MainApplication.javaMainActivity.java,分别做了应用以及主 Activity 的定义。

安卓应用的启动流程是:在启动第一个 activity 之前会创建一个全局唯一的 Application 对象。故在此我们先分析 MainApplication

MainApplication

public class MainApplication extends Application implements ReactApplication {
  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }
        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // 其它对 packages 的操作
          return packages;
        }
        @Override
        protected String getJSMainModuleName() {
          return "index";
        }
  }
  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }
  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }

MainApplication 继承自 Application 类,并且实现了 ReactApplication 接口。在其中做的事情有:

1.创建成员变量 ReactNativeHost 的实例,并在创建过程中通过重写 ReactNativeHost 类方法的方式,注入一些配置,包括:

  1. getUseDeveloperSupport: 配置是否开启调试
  2. getPackages: 配置要加载的模块
  3. getJSMainModuleName: 配置 js 模块的入口文件名

2.在 onCreate 中:

  1. 调用 Soloader 库。Soloader 是 facebook 推出的一个 so 文件加载库,它能够处理 so 文件的依赖在 react-native 中,所有框架相关的 so 文件都是通过SoLoader完成加载的
  2. 通过 ReactInstanceManager 初始化 Flipper。Flipper 是 facebook 推出的用于 debug ios、Android、React Native 应用的工具。

在这里简要介绍下 ReactNativeHostReactInstanceManager

ReactNativeHost

ReactNativeHost 是个抽象类,开发者可以重写其中的方法,其主要的作用是:在 application 中指定一些赋值操作,进而获取 ReactInstanceManager 的实例。所以可以把 ReactNativeHost 作为将用户自定义的参数赋值到 ReactInstanceManager 实例的中转站。核心方法是: getReactInstanceManager,详细分析见下文。

ReactInstanceManager

该类为核心类,主要负责管理 JS 的加载、维护生命周期、管理 JS 与 C++ 的交互等等。可以把 ReactInstanceManager 理解成 JS 与 C++ 的中转桥梁。

MainActivity

接着看 MainActivity.java

public class MainActivity extends ReactActivity {
  @Override
  protected String getMainComponentName() {
    return "myProject";
  }
}

MainActivity 类中仅重写了 getMainComponentName 方法。该类继承自 ReactActivity,我们再来看其 ReactActivity

public abstract class ReactActivity extends AppCompatActivity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
  private final ReactActivityDelegate mDelegate;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mDelegate.onCreate(savedInstanceState);
  }

ReactActivity 全权委托给 ReactActivityDelegate 来处理 onCreate 生命周期。来看 ReactActivityDelegateonCreate

protected void onCreate(Bundle savedInstanceState) {
  String mainComponentName = getMainComponentName();
  mReactDelegate =
      new ReactDelegate(
          getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions()) {
        @Override
        protected ReactRootView createRootView() {
          return ReactActivityDelegate.this.createRootView();
        }
      };
    if (mMainComponentName != null) {
      loadApp(mainComponentName);
    }
  }

这里首先创建了 ReactDelegate 实例。接着来看 loadApp 方法:

protected void loadApp(String appKey) {
  mReactDelegate.loadApp(appKey);
  getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}

由此走到 ReactDelegate 实例的 loadApp 方法:

public void loadApp(String appKey) {
  if (mReactRootView != null) {
    throw new IllegalStateException("Cannot loadApp while app is already running.");
  }
  mReactRootView = createRootView();
  mReactRootView.startReactApplication(
      getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
}

在这里做了三件事:创建 rootView (createRootView)、创建 ReactInstanceManager (getReactInstanceManager)、创建 ReactApplication (startReactApplication)。

createRootView

首先看下什么是 rootView。

public class ReactRootView extends FrameLayout implements RootView, ReactRoot { /* ... */}

ReactRootView 继承自 FrameLayout,并且实现了 RootViewReactRoot 两个接口。FrameLayout 是安卓几大布局中较为简单的一个,整个界面被当成一块空白备用区域,所有元素以左上角对齐堆叠。ReactRootView 继承自 FrameLayout,表明其也是作为简单布局而存在,UI 的绘制渲染都发生在上面。

getReactInstanceManager

ReactInstanceManager 是一个核心类,管理着 JS 的加载、C++ 和 JS 的交互、初始化参数等。最终调用来到 ReactNativeHost 类中的 createReactInstanceManager 方法:

protected ReactInstanceManager createReactInstanceManager() {
  ReactInstanceManagerBuilder builder = /* ... */

  for (ReactPackage reactPackage : getPackages()) {
    builder.addPackage(reactPackage);
  }

  String jsBundleFile = getJSBundleFile();
  if (jsBundleFile != null) {
    builder.setJSBundleFile(jsBundleFile);
  } else {
    builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
  }
  
  ReactInstanceManager reactInstanceManager = builder.build();
  return reactInstanceManager;
}

此处做的事情如下:

  • 创建 ReactInstanceManagerBuilder 实例。这里采用建造者模式来构造 ReactInstanceManager 实例,故在此先传入参数设定构造者;
  • 把在 ReactNativeHost 中注册的 packages 都添加到 ReactInstanceManagerBuilder 实例中;
  • 如果 getJSBundleFile 不为空,则加载对应的文件,否则加载默认的 jsBundleFile
  • 调用 builder.build 方法。通过建造者真正构造 ReactInstanceManager 实例

startReactApplication

  public void startReactApplication(/* */) {
    // ...
    try {
      // ...
      mReactInstanceManager.createReactContextInBackground();
    } finally {
      // ...
    }
  }

最终执行到 ReactInstanceManagercreateReactContextInBackground 方法中。最后经过调用链:recreateReactContextInBackgroundInner() -> recreateReactContextInBackgroundFromBundleLoader() -> recreateReactContextInBackground() -> runCreateReactContextOnNewThread()

runCreateReactContextOnNewThread 主要做了两件事:

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

详细分析我们放到另一篇文章:React Native startReactApplication 流程梳理

总结

总结本文,通过 react-native-cli 创建的示例工程(安卓部分)为例,顺着两个类 MainApplicationMainActivity 的执行流程,抓住主干逻辑,最终梳理出了 React Native 从开始启动至执行用户 js 文件的过程。可以看到:

MainApplication 的作用主要是传入用户的配置,并做 so 库以及应用 debug 工具的初始化工作;

MainActivity 的作用主要是:

  1. 为应用创建 rootView 布局容器;
  2. 创建 ReactInstanceManager 核心类,用于后续管理 JS 的加载、C++ 和 JS 的交互、初始化参数等;
  3. 通过 startReactApplication 来创建 ReactContext 上下文,并最终调用到 AppRegistry.js 启动App。

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

相关文章

  • react嵌套路由实现TabBar的实现

    react嵌套路由实现TabBar的实现

    本文主要介绍了react嵌套路由实现TabBar的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • React Native性能优化指南及问题小结

    React Native性能优化指南及问题小结

    本文将介绍在React Native开发中常见的性能优化问题和解决方案,包括ScrollView内无法滑动、热更新导致的文件引用问题、高度获取、强制横屏UI适配、低版本RN适配iOS14、缓存清理、navigation参数取值等,感兴趣的朋友一起看看吧
    2024-01-01
  • React中的权限组件设计问题小结

    React中的权限组件设计问题小结

    这篇文章主要介绍了React中的权限组件设计,整个过程也是遇到了很多问题,本文主要来做一下此次改造工作的总结,对React权限组件相关知识感兴趣的朋友一起看看吧
    2022-07-07
  • 基于PixiJS实现react图标旋转动效

    基于PixiJS实现react图标旋转动效

    PixiJS是一个开源的基于web的渲染系统,为游戏、数据可视化和其他图形密集型项目提供了极快的性能,这篇文章主要介绍了用PixiJS实现react图标旋转动效,需要的朋友可以参考下
    2022-05-05
  • React Streaming SSR原理示例深入解析

    React Streaming SSR原理示例深入解析

    这篇文章主要为大家介绍了React Streaming SSR原理示例深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 一文详解React Redux使用方法

    一文详解React Redux使用方法

    这篇文章主要介绍了一文详解React Redux使用方法,文章围绕主题展开详细的内容戒杀,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • React Hook Form 优雅处理表单使用指南

    React Hook Form 优雅处理表单使用指南

    这篇文章主要为大家介绍了React Hook Form 优雅处理表单使用指南,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Vite + React从零开始搭建一个开源组件库

    Vite + React从零开始搭建一个开源组件库

    这篇文章主要介绍了Vite + React 如何从0到1搭建一个开源组件库,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • ES6 class类链式继承,实例化及react super(props)原理详解

    ES6 class类链式继承,实例化及react super(props)原理详解

    这篇文章主要介绍了ES6 class类链式继承,实例化及react super(props)原理,结合实例形式详细分析了ES6 中class类链式继承,实例化及react super(props)原理相关概念、原理、定义与使用技巧,需要的朋友可以参考下
    2020-02-02
  • React中遍历数组生成标签问题

    React中遍历数组生成标签问题

    这篇文章主要介绍了React中遍历数组生成标签问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01

最新评论