background

Part of the company’s business uses the development of React-Native. Understanding the startup process in the source code is helpful for us to develop the product better. This paper uses [email protected] Android version for research

Project entry

Through Rn-CLI to create a project, we can see that there are two main files: MainActivity, MainApplication

MainApplication

For MainApplication. There are two main concerns

  1. OnCreate initializes the library for c++ layer load parsingSoLoader
  2. To obtain ReactNativeHost, see the following table

The main role is to save the current APP application instance, and from which to create a New reactInstanceManager, some initialization parameters passed in, can be understood as a transfer station

Check it out in the Builder file here

The default js excutor and jsbundleLoader are assigned and the default createAssetLoader is used

I’m not going to look at what’s going on in ReactInstanceManage. Because there’s no method call yet

At this point MainApplication is initialized

Next, go to MainActivity

MainActivity

MainActivity inherits from one of our key members, ReactActivity

Java layer key code

ReactActivity

The ReactActivity is really just a placeholder activity, in which all actions to an RN application are performed by calling the ReactActivityDelegate.

Now what does ReactActivityDelegate’s Create do

We initialize the reactDelegate instance, pass in the current activity and some initialization parameters, and call the reactDelegate loadApp method

As you can see, the loadApp method basically calls the other key member I just mentioned, ReactRootView

This should be the key startup process

To summarize the Delegate call, there are three main steps

  1. Create a reactRootView as the view hosting your RN application
  2. Call ReactRootView’s startRactApplication to start an RN application
  3. Set the created reactRootView into the activity

Now let’s look at ReactRootView

ReactRootVIew

ReactRootView There’s a comment that summarizes what ReactRootView does

Basically, the root of an RN application is trying to lay out elements while listening for native events to be handled by JS

Take a look at his startApplication method

Here, reactInstanceManager is called after ensuring that it is currently running in the UI thread

CreateReactContextInBackground method

ReactContext

Is actually a call to the recreateReactContextInBackground finally

RunCreateReactContextOnNewThread main logic is as follows

The main task is to initialize and set up the RN context.

Let’s look at the first step, createReactContext

Here comes another core member of the communication bridge just now, catalysInstanceImpl

There are a couple of things going on here

  1. Create the JavaModule registry
  2. To create a goodcatalysInstanceImplThe instance
  3. If a jsiModule exists, register it with it
  4. Start loading js bundle

Let’s take a look at the constructor of CatalysInstanceImpl

CatalysInstanceImpl

Looking at the constructor for CatalysInstanceImpl, there are two key points

  1. Methods to initialize c++
  2. Initializing the bridge is actually a method called native (explained in detail in the communication section below).

Let’s move on to the startup process and look at runJSBundle

The loadScript method of jsbundleLoader is actually called

Enter the jsbundleLoader

CreateAssetLoader (loadScript) createAssetLoader (loadScript

The loadScriptFromAssets method of CatalysInstanceImpl is actually called

This is actually calling a native c++ method,

To sum up, in this case the LoadJS method is actually called when catalysInstanceImpl is initialized

Start by drawing a current flow chart

Java layer summary

C++ layer initialization

Enter the CatalysInstaneImpl. CPP

See that a series of methods have been registered with the initializeBridge and jniLoadScriptFromAssets that were just called by the Java layer

Let’s look at loadScript processing first

Continue, eventually the instance by calling the link: : loadScriptFromString > loadBundle > nativeToJsBridge – JSIExcutor

Call to loadbundle

There are two steps. The first step is to execute the javascript script directly through JScore, which is the bundle entry file that we packaged

The second step is to execute bindBrdige, which we will also ignore for the moment, as we will discuss later in the Communications section, but remember the method name bindBridge

The first step is to execute the bundle entry file

Back to our familiar JS code, the entry file

Actually call appRegistry registerComponent

RegisterComponent actually just stores calls to the application’s rederApplication method in runnables indexed by appKey, so it looks like there still needs to be a place to call renderApplication

Moving on to the Java layer, we mentioned that setup happens after an RN context is created. What does setup do

Perform render

What does the ReactInstanceManager back to the Java layer execute next after js execution

In setupReactContext attachRootViewToInstance is called

Check it out here

This is where you find appRegistry and call its runApplication method

Let’s ignore getJSModuel, which is actually bridge calls as well.

When we get to Rn, we execute renderApplication by finding the corresponding comp in runnable

This is the end of the startup process

Next comes the js side, which evaluates the virtual DOM. Finally, the bridge is rendered to the native module

conclusion

The overall flow chart should look something like this

Summarize the overall process

  1. The ReactActivity holds the ReactInstanceManager and sets the ReactRootView
  2. The context of Rn is then created by calling Manager via ReactRootView
  3. The CatalysInstanceImpl is instantiated here, and the CatalysInstanceImpl registers the native modules that need to be exposed and the JS modules that need to be invoked
  4. The loadJs method and initialBridge are then called to initialize the bridge code in the native part
  5. Then you get into the C++ layer
  6. Load the bundle at the C++ layer and execute the bundle through the js engine
  7. The bundle that comes in is the entry file that we packaged
  8. In the bundle layer, we use appRegistry to register our Component and render methods
  9. Then, after loading JS, the Java layer calls renderApplication, finds the function in Runnable, executes it, and renders it. There is a bit of bridge communication involved here, as discussed later. (Stay tuned for the next post)

Reference Documents:

ReactNative source code: startup process