ReactNative 启动应用
简述
本节我们来看一下ReactNative在Android上启动Activity的流程,ReactNative在Android上也是一个Apk,它的实现全部都在应用层,所以它肯定也是符合我们Android应用的启动流程的,UI页面的载体也是一个Activity,然后启动JS引擎来加载index.js,执行javascript的代码,然后javascript通过Fabric渲染器和TurboModule执行到java代码,调用到最终的Native实现,本节我们就来看一下启动的这个过程。
Application启动
1.1 MainApplication.init
ReactNative的能力被包装为Package,Package里面包含一些Module,每个Module是一个子能力,后续介绍TurboModule的时候会介绍包加载的流程。
class MainApplication : Application(), ReactApplication {
// 主要就是构建了DefaultReactNativeHost和ReactHost
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
// 这里加载了所有包
PackageList(this).packages.apply {
// Packages that cannot be autolinked yet can be added manually here, for example:
// add(MyReactNativePackage())
}
override fun getJSMainModuleName(): String = "index"
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}
// 详见1.2
override val reactHost: ReactHost
get() = getDefaultReactHost(applicationContext, reactNativeHost)
override fun onCreate() {
super.onCreate()
SoLoader.init(this, false)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
load()
}
}
}
1.2 getDefaultReactHost
调用ReactNativeHost.toReactHost构造ReactHost。
@OptIn(UnstableReactNativeAPI::class)
@JvmStatic
public fun getDefaultReactHost(
context: Context,
reactNativeHost: ReactNativeHost,
): ReactHost {
require(reactNativeHost is DefaultReactNativeHost) {
"You can call getDefaultReactHost only with instances of DefaultReactNativeHost"
}
//详见1.3
return reactNativeHost.toReactHost(context)
}
1.3 toReactHost
调用了getDefaultReactHost
@UnstableReactNativeAPI
internal fun toReactHost(context: Context): ReactHost =
// 详见1.4
DefaultReactHost.getDefaultReactHost(
context,
packages,
jsMainModuleName,
bundleAssetName ?: "index",
isHermesEnabled ?: true,
useDeveloperSupport,
)
1.4 getDefaultReactHost
初始化了JS引擎,加载了js代码,还构建了DefaultReactHostDelegate,最终会把这些信息封装到一个ReactHostImpl中,ReactHost建立了React和Activity一些交互的接口。
@OptIn(UnstableReactNativeAPI::class)
@JvmStatic
public fun getDefaultReactHost(
context: Context,
packageList: List<ReactPackage>,
jsMainModulePath: String = "index",
jsBundleAssetPath: String = "index",
isHermesEnabled: Boolean = true,
useDevSupport: Boolean = ReactBuildConfig.DEBUG,
cxxReactPackageProviders: List<(ReactContext) -> CxxReactPackage> = emptyList(),
): ReactHost {
// 构建ReactHostImpl
if (reactHost == null) {
// 创建jsBundleLoader,这个是用来执行JS代码的
val jsBundleLoader =
JSBundleLoader.createAssetLoader(context, "assets://$jsBundleAssetPath", true)
// 创建JS引擎
val jsRuntimeFactory = if (isHermesEnabled) HermesInstance() else JSCInstance()
val defaultTmmDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder()
cxxReactPackageProviders.forEach { defaultTmmDelegateBuilder.addCxxReactPackage(it) }
// 构建DefaultReactHostDelegate
val defaultReactHostDelegate =
DefaultReactHostDelegate(
jsMainModulePath = jsMainModulePath,
jsBundleLoader = jsBundleLoader,
reactPackages = packageList,
jsRuntimeFactory = jsRuntimeFactory,
turboModuleManagerDelegateBuilder = defaultTmmDelegateBuilder)
val componentFactory = ComponentFactory()
DefaultComponentsRegistry.register(componentFactory)
// 创建ReactHostImpl,详见1.5
reactHost =
ReactHostImpl(
context,
defaultReactHostDelegate,
componentFactory,
true /* allowPackagerServerAccess */,
useDevSupport,
)
.apply {
jsEngineResolutionAlgorithm =
if (isHermesEnabled) {
JSEngineResolutionAlgorithm.HERMES
} else {
JSEngineResolutionAlgorithm.JSC
}
}
}
return reactHost as ReactHost
}
1.5 ReactHostImpl
构建了一个DevSupportManager。
public ReactHostImpl(
Context context,
ReactHostDelegate delegate,
ComponentFactory componentFactory,
Executor bgExecutor,
Executor uiExecutor,
boolean allowPackagerServerAccess,
boolean useDevSupport) {
mContext = context;
mReactHostDelegate = delegate;
mComponentFactory = componentFactory;
mBGExecutor = bgExecutor;
mUIExecutor = uiExecutor;
mQueueThreadExceptionHandler = ReactHostImpl.this::handleHostException;
mMemoryPressureRouter = new MemoryPressureRouter(context);
mAllowPackagerServerAccess = allowPackagerServerAccess;
mUseDevSupport = useDevSupport;
// debug版本和release版本,分别构建不同的SupportManager
if (mUseDevSupport) {
mDevSupportManager =
new BridgelessDevSupportManager(
ReactHostImpl.this, mContext, mReactHostDelegate.getJsMainModulePath());
} else {
mDevSupportManager = new ReleaseDevSupportManager();
}
}
Application中主要是初始化了一些React的对象,主要就是一个ReactHostImpl,ReactHostImpl里面持有了JS代码和引擎,以及要加载的包信息等等。
Activity启动
2.1 ReactActivity.onCreate
调了ReactActivityDelegate的onCreate
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 详见2.2
mDelegate.onCreate(savedInstanceState);
}
2.2 ReactActivityDelegate.onCreate
构建ReactDelegate,会根据flag构建ReactDelegate传入不同的参数,我们跟新架构的路径。
ReactDelegate会持有ReactHost或者ReactNativeHost,新架构是前者,老架构师后者。
public void onCreate(Bundle savedInstanceState) {
String mainComponentName = getMainComponentName();
final Bundle launchOptions = composeLaunchOptions();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isWideColorGamutEnabled()) {
mActivity.getWindow().setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
}
if (ReactFeatureFlags.enableBridgelessArchitecture) {
// 详见2.3
mReactDelegate =
new ReactDelegate(getPlainActivity(), getReactHost(), mainComponentName, launchOptions);
} else {
mReactDelegate =
new ReactDelegate(
getPlainActivity(),
getReactNativeHost(),
mainComponentName,
launchOptions,
isFabricEnabled()) {
@Override
protected ReactRootView createRootView() {
ReactRootView rootView = ReactActivityDelegate.this.createRootView();
if (rootView == null) {
rootView = super.createRootView();
}
return rootView;
}
};
}
if (mainComponentName != null) {
// 详见2.3
loadApp(mainComponentName);
}
}
2.3 ReactActivityDelegate.loadApp
构建根View,配置给Activity。
protected void loadApp(String appKey) {
// 详见2.4
mReactDelegate.loadApp(appKey);
getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}
2.4 ReactDelegate.loadApp
这里一样有两套逻辑,新架构一套老架构一套,我们还是看新架构的流程。
这里构建了一个ReactSurfaceImpl,ReactSurfaceImpl里面会持有一个ReactSurfaceView,ReactSurfaceView是一个FrameLayout的子类,作为根View。
然后调用了mReactSurface.start来初始化。
public void loadApp(String appKey) {
// With Bridgeless enabled, create and start the surface
if (ReactFeatureFlags.enableBridgelessArchitecture) {
if (mReactSurface == null) {
// 构建了一个ReactSurfaceImpl和ReactSurfaceView,ReactSurfaceImpl持有ReactSurfaceView
// ReactSurfaceView本质就是一个FrameLayout
mReactSurface = mReactHost.createSurface(mActivity, appKey, mLaunchOptions);
mActivity.setContentView(mReactSurface.getView());
}
// 启动ReactSurfaceImpl,详见2.5
mReactSurface.start();
} else {
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.");
}
mReactRootView = createRootView();
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
}
}
2.5 ReactSurfaceImpl.start
这里的Task是ReactNative自己写的一套逻辑,封装了异步调用的能力,功能类似于RXJava,就不详细看了,只要知道这是干啥用的就可以。
大致就是在mBGExecutor线程池里面调用getOrCreateStartTask返回的Task,然后等任务完成后回调getResult。
逻辑在getOrCreateStartTask里。
public TaskInterface<Void> start() {
// 详见2.6
return Task.call(this::getOrCreateStartTask, mBGExecutor).continueWithTask(Task::getResult);
}
2.6 ReactSurfaceImpl.getOrCreateStartTask
主要就是通过waitThenCallGetOrCreateReactInstanceTask来构建ReactInstance的Task
private Task<Void> getOrCreateStartTask() {
final String method = "getOrCreateStartTask()";
if (mStartTask == null) {
log(method, "Schedule");
mStartTask =
// 调用waitThenCallGetOrCreateReactInstanceTask来构建ReactInstance,首次就会构建,后续使用缓存,详见2.7
waitThenCallGetOrCreateReactInstanceTask()
.continueWithTask(
(task) -> {
if (task.isFaulted()) {
mReactHostDelegate.handleInstanceException(task.getError());
// 如果出现异常则调用DestoryTask。
return getOrCreateDestroyTask(
"getOrCreateStartTask() failure: " + task.getError().getMessage(),
task.getError())
.continueWithTask(destroyTask -> Task.forError(task.getError()))
.makeVoid();
}
return task.makeVoid();
},
mBGExecutor);
}
return mStartTask;
}
2.7 ReactSurfaceImpl.waitThenCallGetOrCreateReactInstanceTaskWithRetries
直接调用了waitThenCallGetOrCreateReactInstanceTaskWithRetries重载函数
@ThreadConfined("ReactHost")
private Task<ReactInstance> waitThenCallGetOrCreateReactInstanceTask() {
// 调用重载函数,传入参数为重试次数,详见2.8
return waitThenCallGetOrCreateReactInstanceTaskWithRetries(0, 4);
}
2.8 ReactSurfaceImpl.waitThenCallGetOrCreateReactInstanceTaskWithRetries
这里最终调用了getOrCreateReactInstanceTask来创建 创建ReactInstance的Task,也就是说其实最终是通过getOrCreateReactInstanceTask返回的Task里面的任务来创建ReactTask,其他的代码都是负责处理辅助逻辑,如失败重试,失败销毁,切换线程执行等。
@ThreadConfined("ReactHost")
private Task<ReactInstance> waitThenCallGetOrCreateReactInstanceTaskWithRetries(
int tryNum, int maxTries) {
final String method = "waitThenCallGetOrCreateReactInstanceTaskWithRetries";
if (mReloadTask != null) {
log(method, "React Native is reloading. Return reload task.");
return mReloadTask;
}
if (mDestroyTask != null) {
// 如果失败后重试次数没到最大重试次数,还可以重试
boolean shouldTryAgain = tryNum < maxTries;
if (shouldTryAgain) {
log(
method,
"React Native is tearing down."
+ "Wait for teardown to finish, before trying again (try count = "
+ tryNum
+ ").");
return mDestroyTask.onSuccessTask(
(task) -> waitThenCallGetOrCreateReactInstanceTaskWithRetries(tryNum + 1, maxTries),
mBGExecutor);
}
raiseSoftException(
method,
"React Native is tearing down. Not wait for teardown to finish: reached max retries.");
}
// 调用getOrCreateReactInstanceTask来创建ReactInstance,详见2.9
return getOrCreateReactInstanceTask();
}
2.9 ReactSurfaceImpl.getOrCreateReactInstanceTask
ReactInstance代表着React的一个实例,里面持有了FabricUIManager,TurboModuleManager等,且提供了loadJSBundle执行JS代码,是React在Java侧最重要的管理类了。
这里最终调用了instance.loadJSBundle来执行JS代码。
@ThreadConfined("ReactHost")
private Task<ReactInstance> getOrCreateReactInstanceTask() {
final String method = "getOrCreateReactInstanceTask()";
log(method);
return mCreateReactInstanceTaskRef.getOrCreate(
() -> {
log(method, "Start");
ReactMarker.logMarker(
ReactMarkerConstants.REACT_BRIDGELESS_LOADING_START, BRIDGELESS_MARKER_INSTANCE_KEY);
// 获取JsBundleLoder,最终是通过这个来执行JS代码的,这个JsBundleLoader就是我们在Application初始化ReactHost的时候创建的那个。
return getJsBundleLoader()
.onSuccess(
task -> {
// 前面Task完成后会进onSuccess,task.getResult可以拿到前面方法的返回值,就是JsBundleLoader
final JSBundleLoader bundleLoader = task.getResult();
final BridgelessReactContext reactContext = getOrCreateReactContext();
final DevSupportManager devSupportManager = getDevSupportManager();
reactContext.setJSExceptionHandler(devSupportManager);
log(method, "Creating ReactInstance");
// 构建ReactInstance,这里初始化了很多内容,比较重要的有FabricUIManager,TurboModuleManager
final ReactInstance instance =
new ReactInstance(
reactContext,
mReactHostDelegate,
mComponentFactory,
devSupportManager,
mQueueThreadExceptionHandler,
mUseDevSupport,
getOrCreateReactHostInspectorTarget());
mReactInstance = instance;
instance.initializeEagerTurboModules();
MemoryPressureListener memoryPressureListener =
createMemoryPressureListener(instance);
mMemoryPressureListener = memoryPressureListener;
mMemoryPressureRouter.addMemoryPressureListener(memoryPressureListener);
log(method, "Loading JS Bundle");
// 执行JS代码,详见2.10
instance.loadJSBundle(bundleLoader);
// ...
return new Result();
},
mBGExecutor)
.onSuccess(
task -> {
// ...流转生命周期
return reactInstance;
},
mUIExecutor);
});
}
2.10 ReactInstance.loadJSBundle
这里逻辑挺绕的,这里会调用JSBundleLoader的loadScript,JSBundleLoader是在1.4通过createAssetLoader创建的,是一个匿名内部类,里面就是调用了JSBundleLoaderDelegate.loadScriptFromAssets,JSBundleLoaderDelegate是loadscript的一个入参,是这里的匿名内部类,随意就是执行了这里的loadScriptFromAssets。
public void loadJSBundle(JSBundleLoader bundleLoader) {
// Load the JS bundle
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstance.loadJSBundle");
bundleLoader.loadScript(
new JSBundleLoaderDelegate() {
@Override
public void loadScriptFromFile(
String fileName, String sourceURL, boolean loadSynchronously) {
mBridgelessReactContext.setSourceURL(sourceURL);
loadJSBundleFromFile(fileName, sourceURL);
}
@Override
public void loadSplitBundleFromFile(String fileName, String sourceURL) {
loadJSBundleFromFile(fileName, sourceURL);
}
@Override
public void loadScriptFromAssets(
//执行的是这,我们在编译后会将js打包到assets目录下,这里就是执行入口。
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
mBridgelessReactContext.setSourceURL(assetURL);
// 详见2.11
loadJSBundleFromAssets(assetManager, assetURL);
}
@Override
public void setSourceURLs(String deviceURL, String remoteURL) {
mBridgelessReactContext.setSourceURL(deviceURL);
}
});
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
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;
}
};
}
2.11 ReactInstance.loadJSBundleFromAssets
这个是native方法,映射到C++层是JReactInstance::loadJSBundleFromAssets。
void JReactInstance::loadJSBundleFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL) {
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
auto manager = extractAssetManager(assetManager);
// 加载asset内的文件,将结果存在script
auto script = loadScriptFromAssets(manager, sourceURL);
// 最终调用的C++层的ReactInstance::loadScript
instance_->loadScript(std::move(script), sourceURL);
}
2.12 ReactInstance::loadScript
这里调用了JSCRuntime.evaluateJavaScript,这里就到了JSI到逻辑了,JSI是使用JS引擎提供的api封装的轻量级框架,用于提供Ojbect-C和JS或者C++和JS通信,我们这里就不继续深入了,后面会有专门一节介绍JSI。
这里调用JSI接口执行JS代码,就到了index.js了,后续index.js代码是怎么最终通知Native构建View以及显示的逻辑我们在Fabric渲染器章节再来介绍。
void ReactInstance::loadScript(
std::unique_ptr<const JSBigString> script,
const std::string& sourceURL) {
auto buffer = std::make_shared<BigStringBuffer>(std::move(script));
std::string scriptName = simpleBasename(sourceURL);
runtimeScheduler_->scheduleWork(
[this,
scriptName,
sourceURL,
buffer = std::move(buffer),
weakBufferedRuntimeExecuter = std::weak_ptr<BufferedRuntimeExecutor>(
bufferedRuntimeExecutor_)](jsi::Runtime& runtime) {
try {
SystraceSection s("ReactInstance::loadScript");
bool hasLogger(ReactMarker::logTaggedMarkerBridgelessImpl);
if (hasLogger) {
ReactMarker::logTaggedMarkerBridgeless(
ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());
}
// 调用JSCRuntime.evaluateJavaScript,这就到了JSI层了,我们这里暂时不继续看了,后面会有一节专门讲JSI
runtime.evaluateJavaScript(buffer, sourceURL);
if (hasLogger) {
ReactMarker::logTaggedMarkerBridgeless(
ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
ReactMarker::logMarkerBridgeless(
ReactMarker::INIT_REACT_RUNTIME_STOP);
ReactMarker::logMarkerBridgeless(ReactMarker::APP_STARTUP_STOP);
}
if (auto strongBufferedRuntimeExecuter =
weakBufferedRuntimeExecuter.lock()) {
strongBufferedRuntimeExecuter->flush();
}
} catch (jsi::JSError& error) {
jsErrorHandler_->handleFatalError(error);
}
});
}
小结
通过上面的介绍,我们知道了ReactNative的Android app是怎么启动并且最终执行到JS到index.js代码,中间我们跳过了一些逻辑,比如加载TruboModule包,且后面index.js执行后又是怎么通知到Native侧,让应用更新对应的View布局,以及JSI是怎么通过JS引擎提供的接口实现JS和C++层通信,这些我们会在后面的章节来介绍。