React Native 源码分析——启动流程
Posted 薛瑄
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Native 源码分析——启动流程相关的知识,希望对你有一定的参考价值。
本系列文章,是分析android 的 React Native 的源码,主要包括以下文章,和以往的源码系列一样,分析主流程的代码,不会细致到每一行(但相比上一篇的Gradle源码分析,要细致很多),会涉及到java、C++、js等源码。 RN版本是0.64.0
1、React Native 源码分析(一)—— 启动流程
2、React Native 源码分析(二)—— 通信机制
3、React Native 源码分析(三)—— UI渲染流程
4、React Native 源码分析(四)—— 任务调度
5、React Native 源码分析(五)—— 事件分发
在使用RN的时候,Activity需要继承ReactActivity, ReactActivity 的操作都是交给ReactActivityDelegate 来处理的,所以下面我们从ReactActivityDelegate的onCreate来开始
一、RN框架初始化
1.1、ReactActivityDelegate # onCreate
protected void onCreate(Bundle savedInstanceState)
//该函数在自己activity 重写
//后续进入React,会通过该名称,在js中寻找注册的同名组件,进行启动。
//js中 这样注册 AppRegistry.registerComponent(appName, () => Root);
String mainComponentName = getMainComponentName();
//创建ReactDelegate,
//参数getPlainActivity() 是当前的activity
//参数getReactNativeHost() 返回一个ReactNativeHost对象,是在Application中实现
mReactDelegate =
new ReactDelegate(
getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions())
//复写函数 创建RootView,后续RN的界面,都在这个View中承载
@Override
protected ReactRootView createRootView()
return ReactActivityDelegate.this.createRootView();
;
if (mMainComponentName != null)
// 加载javaModule、jsModule、创建UI线程、Native线程、js线程等等
loadApp(mainComponentName);
protected void loadApp(String appKey)
//代码1.2 分析
mReactDelegate.loadApp(appKey);
getPlainActivity().setContentView(mReactDelegate.getReactRootView());
1.2、ReactDelegate#loadApp
接着代码1.1 的 mReactDelegate.loadApp(appKey);
继续分析
public void loadApp(String appKey)
...
//会调用到代码1.1
mReactRootView = createRootView();
//该函数经过几次调用会到代码4
mReactRootView.startReactApplication(
//ReactNativeHost 实例是application中创建的,调用getReactInstanceManager,会先去创建ReactInstanceManager
//具体创建ReactInstanceManager的时机,由业务代码确定,也可能还没执行loadApp,ReactInstanceManager已经创建了
getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
在getReactInstanceManager()
获取实例时,如果为空,会先去创建,下面就看看是如何创建的
1.3、 ReactNativeHost # createReactInstanceManager
ReactNativeHost 是一个抽象类,可覆盖 protected、abstract函数,来实现自定义,下面代码中getxxxx()函数都是可以在创建 ReactNativeHost对象时,进行重写
protected ReactInstanceManager createReactInstanceManager()
ReactInstanceManagerBuilder builder =
ReactInstanceManager.builder()
.setApplication(mApplication)
.setJSMainModulePath(getJSMainModuleName()) //dev有效,JS主module名称,默认index.android,会从metro拉取js bundle
.setUseDeveloperSupport(getUseDeveloperSupport()) //是否debug,在ReactNativeHost 的抽象函数去获取
.setRedBoxHandler(getRedBoxHandler()) //红盒处理器,就是在调试时,出现错误异常,弹窗的红色报错页面
//自定义生产JS处理器的工厂类,例如:HermesExecutorFactory 、默认JSCExecutorFactory、
.setjavascriptExecutorFactory(getJavaScriptExecutorFactory())
//RN对UI处理,是通过java的UIManagerModule,该module可让js来操作native view,具体的实现在UIImplementation。
//UIImplementation 如何被提供,可通过次 自定义,默认UIImplementationProvider
.setUIImplementationProvider(getUIImplementationProvider())
.setJSIModulesPackage(getJSIModulePackage()) //可自定义添加JS module
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
//获取自定义添加的java module
for (ReactPackage reactPackage : getPackages())
builder.addPackage(reactPackage);
//获取js bundle文件
String jsBundleFile = getJSBundleFile();
if (jsBundleFile != null)
builder.setJSBundleFile(jsBundleFile);
else
//如果没有指定js bundle的路径,那么就指定使用asset中的js bundle文件。默认index.android.bundle
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
//创建ReactInstanceManager,把设置的值,赋值到成员变量,增加CoreModulesPackage到java module中 等
ReactInstanceManager reactInstanceManager = builder.build();
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
return reactInstanceManager;
下面接着代码2的startReactApplication
往下分析,经过几次调用到mReactInstanceManager.createReactContextInBackground()
1.4、ReactInstanceManager#recreateReactContextInBackgroundInner
@ThreadConfined(UI)
private void recreateReactContextInBackgroundInner()
...
// 这两个变量在代码3中设置,分别表示:是否是开发者模式、是否有JSMainModuleName
if (mUseDeveloperSupport && mJSMainModulePath != null)
final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();
if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS))
//如果js bundle 路径是assets,则mBundleLoader = JSBundleLoader.createAssetLoader
//否则 mBundleLoader = JSBundleLoader.createFileLoader
//都是异步加载
if (mBundleLoader == null)
mDevSupportManager.handleReloadJS();
else
//通过访问 http://localhost:8081/status 判断packager(e.g. metro)是否在运行,也只有开发的是会,才会出现这样的环境
mDevSupportManager.isPackagerRunning(
new PackagerStatusCallback()
@Override
public void onPackagerStatusFetched(final boolean packagerIsRunning)
//在UI线程中运行,把下面的任务加入loop的队列
//在实际的调试中,发现执行下面的代码之前,会执行代码1 的setContentView。
UiThreadUtil.runOnUiThread(
new Runnable()
@Override
public void run()
if (packagerIsRunning)
mDevSupportManager.handleReloadJS();
else if (mDevSupportManager.hasUpToDateJSBundleInCache()
&& !devSettings.isRemoteJSDebugEnabled())
//hasUpToDateJSBundleInCache 是比较 Context.getFilesDir()下的文件修改事件和当前app的最后更新时间
// If there is a up-to-date bundle downloaded from server,
// with remote JS debugging disabled, always use that.
onJSBundleLoadedFromServer();
else
// If dev server is down, disable the remote JS debugging.
devSettings.setRemoteJSDebugEnabled(false);
recreateReactContextInBackgroundFromBundleLoader();
);
);
return;
//生产环境,会运行这里
recreateReactContextInBackgroundFromBundleLoader();
onJSBundleLoadedFromServer
、recreateReactContextInBackgroundFromBundleLoader
最终都会调用到recreateReactContextInBackground
,只是参数JSBundleLoader 有差异 (前者是JSBundleLoader.createCachedBundleFromNetworkLoader, 后者是 mBundleLoader),这两个参数最终会传到ReactContextInitParams 中,如下:
@ThreadConfined(UI)
private void recreateReactContextInBackground(
...
UiThreadUtil.assertOnUiThread();
final ReactContextInitParams initParams =
new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
//这是一个volatile 变量,因为调用该函数前,会判断它是否为空,为空才会继续执行到这里。
if (mCreateReactContextThread == null)
//在下面的代码分析
runCreateReactContextOnNewThread(initParams);
else
//如果mCreateReactContextThread 在创建的过程,此时又需要创建,就把参数放置在该变量中,
//在当前正在运行的mCreateReactContextThread中,进行判断,如果不为空,就重新创建
mPendingReactContextInitParams = initParams;
在实际调试中发现,runCreateReactContextOnNewThread 是在线程mCreateReactContextThread中执行,此处可能会先执行代码1 的setContentView。
@ThreadConfined(UI)
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams)
...
//在activity destroy() 和 它自身线程执行 会置空
mCreateReactContextThread =
new Thread(
null,
new Runnable()
@Override
public void run()
ReactMarker.logMarker(REACT_CONTEXT_THREAD_END);
synchronized (ReactInstanceManager.this.mHasStartedDestroying)
while (ReactInstanceManager.this.mHasStartedDestroying)
try
ReactInstanceManager.this.mHasStartedDestroying.wait();
catch (InterruptedException e)
continue;
// As destroy() may have run and set this to false, ensure that it is true before we
// create
mHasStartedCreatingInitialContext = true;
try
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
//创建ReactContext,代码1.5 分析
final ReactApplicationContext reactApplicationContext =
createReactContext(
//这里create 并不是正常 创建JsExecutor,只是创建了C++层JavaScriptExecutorHolder父类的对应java类对象
//把该对象传递到c++,代码2.3的 *jseh
initParams.getJsExecutorFactory().create(),
initParams.getJsBundleLoader());
mCreateReactContextThread = null;
final Runnable maybeRecreateReactContextRunnable =
new Runnable()
@Override
public void run()
//该值是在上方代码段中设置的
if (mPendingReactContextInitParams != null)
runCreateReactContextOnNewThread(mPendingReactContextInitParams);
mPendingReactContextInitParams = null;
;
Runnable setupReactContextRunnable =
new Runnable()
@Override
public void run()
try
//代码1.8 分析
setupReactContext(reactApplicationContext);
...
;
reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
catch (Exception e)
mDevSupportManager.handleException(e);
,
"create_react_context");
ReactMarker.logMarker(REACT_CONTEXT_THREAD_START);
mCreateReactContextThread.start();
假如initParams.getJsExecutorFactory().create()
创建的为 HermesExecutor,来看下它对应c++的类HermesExecutorHolder,路径
ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/OnLoad.cpp ,它的父类JavaScriptExecutorHolder,路径ReactAndroid/src/main/jni/react/jni/JavaScriptExecutorHolder.h。调用函数getExecutorFactory,获取工厂类,继而创建JsExecutor
1.5、ReactInstanceManager# createReactContext
private ReactApplicationContext createReactContext(
JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader)
...
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
//异常处理器,也是在ReactInstanceManagerBuilder中可配置
NativeModuleCallExceptionHandler exceptionHandler =
mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
reactContext.setNativeModuleCallExceptionHandler(exceptionHandler);
//代码1.6 分析该函数
//函数就是把各个ReactPackage的所有NativeModule提取出来,
//以 Map<String, ModuleHolder> 的形式保存,再封装成NativeModuleRegistry。
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
CatalystInstanceImpl.Builder catalystInstanceBuilder =
new CatalystInstanceImpl.Builder()
//设置创建线程的配置项,第二章节会分析线程的创建流程
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
//js 执行器,代码三中设置
.setJSExecutor(jsExecutor)
.setRegistry(nativeModuleRegistry)
//代码四分析,三种JSBundleLoader
.setJSBundleLoader(jsBundleLoader)
.setNativeModuleCallExceptionHandler(exceptionHandler);
...
final CatalystInstance catalystInstance;
try
//代码1.7分析
catalystInstance = catalystInstanceBuilder.build();
...
//设置catalystInstance、三大线程到 ReactContext 的成员变量中
reactContext.initializeWithInstance(catalystInstance);
//这个参数是在ReactNativeHost setxxx 对应的函数设置的
if (mJSIModulePackage != null)
catalystInstance.addJSIModules(
mJSIModulePackage.getJSIModules(
reactContext, catalystInstance.getJavaScriptContextHolder()));
//turbo、jsi都是RN 新架构中用到的,不需要桥通信(也就是说可以实现同步调用),
//相关的module也需要改变,对应的就是turbo,有TurboCxxModule、JavaTurboModule。
//本系列文章的最后一篇再来讨论这些新特性
if (ReactFeatureFlags.useTurboModules)
JSIModule turboModuleManager =
catalystInstance.getJSIModule(JSIModuleType.TurboModuleManager);
catalystInstance.setTurboModuleManager(turboModuleManager);
TurboModuleRegistry registry = (TurboModuleRegistry) turboModuleManager;
// Eagerly initialize TurboModules
for (String moduleName : registry.getEagerInitModuleNames())
registry.getModule(moduleName);
if (ReactFeatureFlags.eagerInitializeFabric)
catalystInstance.getJSIModule(JSIModuleType.UIManager);
//添加 通信桥空闲时 的回调函数,这个在计算js帧率的时候,会用到
if (mBridgeIdleDebugListener != null)
catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
...
//在通信机制的文章 详细分析
catalystInstance.runJSBundle();
return reactContext;
1.6、processPackages
该函数就是把各个ReactPackage的所有NativeModule提取出来,以 Map<String, ModuleHolder> 的形式保存,再封装成NativeModuleRegistry。 其中ModuleHolder 包括NativeModule继承类的基本信息,class名称、module名称等
private NativeModuleRegistry processPackages(
ReactApplicationContext reactContext,
List<ReactPackage> packages,
boolean checkAndUpdatePackageMembership)
//最后是通过该变量来创建NativeModuleRegistry
NativeModuleRegistryBuilder nativeModuleRegistryBuilder =
new NativeModuleRegistryBuilder(reactContext, this);
...
synchronized (mPackages)
for (ReactPackage reactPackage : packages)
//该变量为true
if (checkAndUpdatePackageMembership && mPackages.contains(reactPackage))
//true 则终止本次循环
continue;
try
//true 则 把当前循环的 reactPackage 加入到mPackages。结合上方判断,意思是,只更新 新添加的reactPackage
if (checkAndUpdatePackageMembership)
mPackages.add(reactPackage);
//解析每个ReactPackage中的nativeModule
processPackage(reactPackage, nativeModuleRegistryBuilder);
...
...
NativeModuleRegistry nativeModuleRegistry;
try
//build,是把收集好的 Map<String, ModuleHolder> 作为参数,创建NativeModuleRegistry
nativeModuleRegistry = nativeModuleRegistryBuilder.build();
...
return nativeModuleRegistry;
private void processPackage(
ReactPackage reactPackage, NativeModuleRegistryBuilder nativeModuleRegistryBuilder)
...
nativeModuleRegistryBuilder.processPackage(reactPackage);
...
public void processPackage(ReactPackage reactPackage)
// We use an iterable instead of an iterator here to ensure thread safety, and that this list
// cannot be modified
Iterable<ModuleHolder> moduleHolders;
//根据不同的ReactPackage 类型来处理,原理都是先用reactPackage 的NativeModule 创建Iterable,然后就可以依次取出
if (reactPackage instanceof LazyReactPackage)
moduleHolders =
((LazyReactPackage) reactPackage).getNativeModuleIterator(mReactApplicationContext);
else if (reactPackage instanceof TurboReactPackage)
moduleHolders =
((TurboReactPackage) reactPackage).getNativeModuleIterator(mReactApplicationContext);
else
moduleHolders =
ReactPackageHelper.getNativeModuleIterator(
reactPackage, mReactApplicationContext, mReactInstanceManager);
for (ModuleHolder moduleHolder : moduleHolders)
String name = moduleHolder.getName();
if (mModules.containsKey(name))
ModuleHolder existingNativeModule = mModules.get(name);
...
mModules.remove(existingNativeModule);
mModules.put(name, moduleHolder);
代码1.5中 catalystInstanceBuilder.build();
会创建CatalystInstanceImpl,builder模式,就不进去看了,直接看CatalystInstanceImpl的构造函数
1.7、创建CatalystInstanceImpl
private CatalystInstanceImpl(
final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
final JavaScriptExecutor jsExecutor,
final NativeModuleRegistry nativeModuleRegistry,
final JSBundleLoader jsBundleLoader,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler)
mHybridData = initHybrid();
// 使用线程配置,具体创建线程,第二节会详细分析
mReactQueueConfiguration =
ReactQueueConfigurationImpl.create(
reactQueueConfigurationSpec, new NativeExceptionHandler());
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
mNativeModuleRegistry = nativeModuleRegistry;
mJSModuleRegistry = new JavaScriptModuleRegistry();
mJSBundleLoader = jsBundleLoader;
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
mTr以上是关于React Native 源码分析——启动流程的主要内容,如果未能解决你的问题,请参考以下文章
React Native 源码分析——Native View创建流程