接触RN开发也快两年的时间了,期间也开发了5、6个APP了,ReactNative的版本也在快速的迭代着,今天重新出发,从源码解析一下App的启动流程,此次解析基于RN 0.60.5版本。
开始之前
开始分析之前,新建一个名为RnDemo的空项目,RN版本选择0.60.5,通过查看项目的目录结构中Android部分会自动为我们生成MainActivity.java和MainApplication.java文件,我们的分析就从这两个文件入手。
Java部分,开始上传
1.首先看一下MainApplication文件,继承Application并实现了ReactApplication接口,主要做一写RN的初始化操作。
public class MainApplication extends Application implements ReactApplication {
// 实现ReactApplication接口,创建ReactNativeHost成员变量,持有ReactInstanceManager实例,做一些初始化操作。
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
// 是否开启dev调试,及一些调试工具,比如redbox(红盒),有时我们看到的报错
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
// 返回app需要的ReactPackage,添加需要加载的模块,这个地方就是我们在项目中添加依赖包时需要添加第三方package的地方
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
//SoLoader:加载C++底层库,准备解析JS。
SoLoader.init(this, /* native exopackage */ false);
}
}
2.接下来看一下MainActivity文件,继承自ReactActivity,ReactActivity作为JS页面的真正容器
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
// 返回组件名,和js入口注册名字一致
return "RnDemo";
}
}
对应的js模块注册名字中:
AppRegistry.registerComponent("RnDemo", () => App);
3.继续,来看一下ReactActivity来,
public abstract class ReactActivity extends AppCompatActivity
implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
private final ReactActivityDelegate mDelegate;
protected ReactActivity() {
mDelegate = createReactActivityDelegate();
}
/**
* Called at construction time, override if you have a custom delegate implementation.
*/
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName());
}
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate(savedInstanceState);
}
protected final ReactNativeHost getReactNativeHost() {
return mDelegate.getReactNativeHost();
}
protected final ReactInstanceManager getReactInstanceManager() {
return mDelegate.getReactInstanceManager();
}
protected final void loadApp(String appKey) {
mDelegate.loadApp(appKey);
}
}
从以上代码可以看到,真正实现是在ReactActivityDelegate类中进行的。
4.继续,我们重点看一下ReactActivityDelegate中的内容
public class ReactActivityDelegate {
protected void onCreate(Bundle savedInstanceState) {
//mMainComponentName就是上面ReactActivity.getMainComponentName()返回的组件名
String mainComponentName = getMainComponentName();
if (mainComponentName != null) {
// 加载app页面
loadApp(mainComponentName);
}
// 双击判断工具类
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
}
protected void loadApp(String appKey) {
// 非空判断
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.");
}
//创建ReactRootView作为根视图,它本质上是一个FrameLayout
mReactRootView = createRootView();
// 启动RN应用,并完成一些初始化设置
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(),
appKey,
getLaunchOptions());
// 将ReactRootView作为Activity的显示view
getPlainActivity().setContentView(mReactRootView);
}
看看ReactActivityDelegate做了那些工作:
1.创建ReactRootView作为根视图
2.startReactApplication启动RN流程
3.将ReactRootView作为ReactActivity的内容显示view
由此看来ReactRootView是个关键,进入ReactRootView类继续看一下启动RN的startReactApplication方法,它接受三个参数:ReactInstanceManager,appName,启动的设置参数launchOptions,
/**
* Schedule rendering of the react component rendered by the JS application from the given JS
* module (@{param moduleName}) using provided {@param reactInstanceManager} to attach to the
* JS context of that manager. Extra parameter {@param launchOptions} can be used to pass initial
* properties for the react component.
*/
public void startReactApplication(
ReactInstanceManager reactInstanceManager,
String moduleName,
@Nullable Bundle initialProperties,
@Nullable String initialUITemplate) {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication");
try {
UiThreadUtil.assertOnUiThread();
// TODO(6788889): Use POJO instead of bundle here, apparently we can't just use WritableMap
// here as it may be deallocated in native after passing via JNI bridge, but we want to reuse
// it in the case of re-creating the catalyst instance
Assertions.assertCondition(
mReactInstanceManager == null,
"This root view has already been attached to a catalyst instance manager");
// reactInstanceManage实例,管理React实例
mReactInstanceManager = reactInstanceManager;
// js注册的name,同ReactActivity.getMainComponentName()与AppRegistry.registerComponent()放回一致
mJSModuleName = moduleName;
// 是Native向JS传递的数据,以后可能由POJO代替,默认是null,需要的话要重写createReactActivityDelegate ,并重写其中getLaunchOptions方法
mAppProperties = initialProperties;
mInitialUITemplate = initialUITemplate;
if (mUseSurface) {
// TODO initialize surface here
}
// 创建RN的上下文ReactContext
if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
mReactInstanceManager.createReactContextInBackground();
}
//宽高计算完成后添加布局监听
attachToReactInstanceManager();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
接下来,进入ReactInstanceManger类看一下createReactContextInBackground方法,
/**
* Trigger react context initialization asynchronously in a background async task. This enables
* applications to pre-load the application JS, and execute global code before
* {@link ReactRootView} is available and measured. This should only be called the first time the
* application is set up, which is enforced to keep developers from accidentally creating their
* application multiple times without realizing it.
*
* Called from UI thread.
*/
@ThreadConfined(UI)
public void createReactContextInBackground() {
Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContextInBackground()");
Assertions.assertCondition(
!mHasStartedCreatingInitialContext,
"createReactContextInBackground should only be called when creating the react " +
"application for the first time. When reloading JS, e.g. from a new file, explicitly" +
"use recreateReactContextInBackground");
// 仅在应用首次启动是调用,防止开发人员意外的创建其他应用
mHasStartedCreatingInitialContext = true;
recreateReactContextInBackgroundInner();
}
createReactContextInBackground方法仅会在首次启动时调用,重新加载(reloaded)app时,会调用recreateReactContextInBackground(),两个方法都会调用recreateReactContextInBackgroundInner(),
@ThreadConfined(UI)
private void recreateReactContextInBackgroundInner() {
Log.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackgroundInner()");
PrinterHolder.getPrinter()
.logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: recreateReactContextInBackground");
//UI线程
UiThreadUtil.assertOnUiThread();
//开发模式,实现在线更新Bundle,晃动弹出调试菜单等功能,这一部分属于调试功能流程。
if (mUseDeveloperSupport && mJSMainModulePath != null) {
final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();
// If remote JS debugging is enabled, load from dev server.
if (mDevSupportManager.hasUpToDateJSBundleInCache() &&
!devSettings.isRemoteJSDebugEnabled()) {
// If there is a up-to-date bundle downloaded from server,
// with remote JS debugging disabled, always use that.
// 调试模式,从服务器加载jsBundle
onJSBundleLoadedFromServer(null);
return;
}
if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
// 加载服务bundle
if (mBundleLoader == null) {
mDevSupportManager.handleReloadJS();
} else {
mDevSupportManager.isPackagerRunning(
new PackagerStatusCallback() {
@Override
public void onPackagerStatusFetched(final boolean packagerIsRunning) {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (packagerIsRunning) {
mDevSupportManager.handleReloadJS();
} else {
// If dev server is down, disable the remote JS debugging.
devSettings.setRemoteJSDebugEnabled(false);
recreateReactContextInBackgroundFromBundleLoader();
}
}
});
}
});
}
return;
}
}
// 加载本地bundle
recreateReactContextInBackgroundFromBundleLoader();
}
recreateReactContextInBackgroundFromBundleLoader方法向下调用recreateReactContextInBackground方法
@ThreadConfined(UI)
private void recreateReactContextInBackground(
//C++和JS双向通信的中转站
JavaScriptExecutorFactory jsExecutorFactory,
// bundle加载器,根据ReactNativeHost中的配置决定从哪里加载bundle文件
JSBundleLoader jsBundleLoader) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackground()");
UiThreadUtil.assertOnUiThread();
//创建ReactContextInitParams对象
final ReactContextInitParams initParams = new ReactContextInitParams(
jsExecutorFactory,
jsBundleLoader);
if (mCreateReactContextThread == null) {
// 在newThread实例化ReactContext
runCreateReactContextOnNewThread(initParams);
} else {
mPendingReactContextInitParams = initParams;
}
}
//runCreateReactContextOnNewThread()方法中内容
final ReactApplicationContext reactApplicationContext =
createReactContext(
initParams.getJsExecutorFactory().create(),
initParams.getJsBundleLoader());
在runCreateReactContextOnNewThread方法中,我们看到是ReactInstanceManager.createReactContext方法最终创建了ReactApplicationContext,我们继续看createReactContext()方法,有关此方法的2个参数:
JSCJavaScriptExecutor jsExecutor:JSCJavaScriptExecutor继承于JavaScriptExecutor,当该类被加载时,它会自动去加载"reactnativejnifb.so"库,并会调用Native方
法initHybrid()初始化C++层RN与JSC通信的框架。
JSBundleLoader jsBundleLoader:缓存了JSBundle的信息,封装了上层加载JSBundle的相关接口,CatalystInstance通过其简介调用ReactBridge去加载JS文件,不同的场景会创建
不同的加载器,具体可以查看类JSBundleLoader。
private ReactApplicationContext createReactContext(
JavaScriptExecutor jsExecutor,
JSBundleLoader jsBundleLoader) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()");
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START, jsExecutor.getName());
// ReactApplicationContext 是reactContext的包装类
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
reactContext.setNativeModuleCallExceptionHandler(exceptionHandler);
//创建JavaModule注册表Builder,用来创建JavaModule注册表,JavaModule注册表将所有的JavaModule注册到CatalystInstance中。
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
//jsExecutor、nativeModuleRegistry、nativeModuleRegistry等各种参数处理好之后,开始构建CatalystInstanceImpl实例。
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
.setJSExecutor(jsExecutor)// js执行通信类
.setRegistry(nativeModuleRegistry)//java模块注册表
.setJSBundleLoader(jsBundleLoader)// bundle加载器
.setNativeModuleCallExceptionHandler(exceptionHandler); // 异常处理器
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
// CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
final CatalystInstance catalystInstance;
try {
catalystInstance = catalystInstanceBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
}
if (mJSIModulePackage != null) {
catalystInstance.addJSIModules(mJSIModulePackage
.getJSIModules(reactContext, catalystInstance.getJavaScriptContextHolder()));
}
if (mBridgeIdleDebugListener != null) {
catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
}
if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
//调用CatalystInstanceImpl的Native方法把Java Registry转换为Json,再由C++层传送到JS层。
catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
}
ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START);
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle");
//通过CatalystInstance开始加载JS Bundle
catalystInstance.runJSBundle();
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
//关联ReacContext与CatalystInstance
reactContext.initializeWithInstance(catalystInstance);
return reactContext;
}
createReactContext方法中用catalystInstance.runJSBundle() 来加载 JS bundle
@Override
public void runJSBundle() {
...省略代码
mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
}
查看loadScript方法,参数JSBundleLoaderDelegate接口的实现类CatalystInstanceImpl,我们假设调用了loadScriptFromAssets方法,
@Override
public void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
}
private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
CatalystInstanceImpl.java最终还是调用C++层的CatalystInstanceImpl.cpp去加载JS Bundle。
接下来看一下CatalystInstance的实现类CatalystInstanceImpl的构造方法:
private CatalystInstanceImpl(
final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
final JavaScriptExecutor jsExecutor,
final NativeModuleRegistry nativeModuleRegistry,
final JSBundleLoader jsBundleLoader,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstanceImpl");
//Native方法,用来创建JNI相关状态,并返回mHybridData
mHybridData = initHybrid();
//RN中的三个线程:Native Modules Thread、JS Thread、UI Thread,都是通过Handler来管理的。
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
reactQueueConfigurationSpec,
new NativeExceptionHandler());
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
mNativeModuleRegistry = nativeModuleRegistry;
mJSModuleRegistry = new JavaScriptModuleRegistry();
mJSBundleLoader = jsBundleLoader;
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
mTraceListener = new JSProfilerTraceListener(this);
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "initializeCxxBridge");
//Native方法,调用initializeBridge()方法,并创建BridgeCallback实例,初始化Bridge。
initializeBridge(
new BridgeCallback(this),
jsExecutor,
mReactQueueConfiguration.getJSQueueThread(),
mNativeModulesQueueThread,
mNativeModuleRegistry.getJavaModules(this),
mNativeModuleRegistry.getCxxModules());
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());
}
//在C++层初始化通信桥ReactBridge
private native void initializeBridge(
ReactCallback callback,
JavaScriptExecutor jsExecutor,
MessageQueueThread jsQueue,
MessageQueueThread moduleQueue,
Collection<JavaModuleWrapper> javaModules,
Collection<ModuleHolder> cxxModules);
参数解读:
- ReactCallback:CatalystInstanceImpl的静态内部类ReactCallback,负责接口回调
- JavaScriptExecutor: js执行器,将js的调用传给c++层
- MessageQueueThread jsQueue:js线程
- MessageQueueThread moduleQueue: java线程
- javaModules: java module
- cxxModules: c++ module
好累,😀,继续,我们去c++层看一下,在项目的node_modules/react-native/ReactAndroid/src/main/jni/react/jni可以找到CatalystInstanceImpl.cpp
看一下CatalystInstanceImpl::jniLoadScriptFromAssets
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
//获取source js Bundle的路径名,这里默认的就是index.android.bundle
auto sourceURL = assetURL.substr(kAssetsLength);
//assetManager是Java层传递过来的AssetManager,调用JSLoade.cpo里的extractAssetManager()方法,extractAssetManager()再
//调用android/asset_manager_jni.h里的AssetManager_fromJava()方法获取AssetManager对象。
auto manager = extractAssetManager(assetManager);
// 调用JSloader.cpp的loadScriptFromAssets方法,读取js Bundle里面的内容
auto script = loadScriptFromAssets(manager, sourceURL);
// unbundle命令打包判断,build.gradle默认里是bundle打包方式。
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
instance_->loadRAMBundle(
std::move(registry),
std::move(script),
sourceURL,
loadSynchronously);
return;
} else if (Instance::isIndexedRAMBundle(&script)) {
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
} else {
//bundle命令打包走此流程,instance_是Instan.h中类的实例
instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously);
}
}
在项目node_modules/react-native/ReactCommon的cxxReact的NativeToJsBridge.cpp文件:
void NativeToJsBridge::loadApplication(
std::unique_ptr<JSModulesUnbundle> unbundle,
std::unique_ptr<const JSBigString> startupScript,
std::string startupScriptSourceURL) {
//获取一个MessageQueueThread,探后在线程中执行一个Task。
runOnExecutorQueue(
m_mainExecutorToken,
[unbundleWrap=folly::makeMoveWrapper(std::move(unbundle)),
startupScript=folly::makeMoveWrapper(std::move(startupScript)),
startupScriptSourceURL=std::move(startupScriptSourceURL)]
(JSExecutor* executor) mutable {
auto unbundle = unbundleWrap.move();
if (unbundle) {
executor->setJSModulesUnbundle(std::move(unbundle));
}
//executor从runOnExecutorQueue()返回的map中取得,与OnLoad中的JSCJavaScriptExecutorHolder对应,也与
//Java中的JSCJavaScriptExecutor对应。它的实例在JSIExecutor.cpp中实现。
executor->loadApplicationScript(std::move(*startupScript),
std::move(startupScriptSourceURL));
});
}
关于unbundle命令
<unbundle命令,使用方式和bundle命令完全相同。unbundle命令是在bundle命令的基础上增加了一项功能,除了生成整合JS文件index.android.bundle外,还会
生成各个单独的未整合JS文件(但会被优化),全部放在js-modules目录下,同时会生成一个名为UNBUNDLE的标识文件,一并放在其中。UNBUNDLE标识文件的前4个字节
固定为0xFB0BD1E5,用于加载前的校验。
进入项目node_modules/react-native/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp进一步调用JSIExecutor.cpp的loadApplicationScript()方法。
//解释执行JS
runtime_->evaluateJavaScript(
std::make_unique<BigStringBuffer>(std::move(script)), sourceURL);
flush();
flushedQueueJS支线的是MessageQueue.js的flushedQueue()方法,此时JS已经被加载到队列中,等待Java层来驱动它。加载完JS后,返回reactApplicationContext,我们继续跟进它的实现。
我们回到ReactInstanceManager类的runCreateReactContextOnNewThread方法中,看到setupReactContext()方法,进入之后可以看到attachRootViewToInstance(reactRoot)方法,进入后
private void attachRootViewToInstance(final ReactRoot reactRoot) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.attachRootViewToInstance()");
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachRootViewToInstance");
UIManager uiManagerModule = UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType());
@Nullable Bundle initialProperties = reactRoot.getAppProperties();
final int rootTag = uiManagerModule.addRootView(
reactRoot.getRootViewGroup(),
initialProperties == null ?
new WritableNativeMap() : Arguments.fromBundle(initialProperties),
reactRoot.getInitialUITemplate());
reactRoot.setRootViewTag(rootTag);
// 启动入口
reactRoot.runApplication();
Systrace.beginAsyncSection(
TRACE_TAG_REACT_JAVA_BRIDGE,
"pre_rootView.onAttachedToReactInstance",
rootTag);
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
Systrace.endAsyncSection(
TRACE_TAG_REACT_JAVA_BRIDGE, "pre_rootView.onAttachedToReactInstance", rootTag);
reactRoot.onStage(ReactStage.ON_ATTACH_TO_INSTANCE);
}
});
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
catalystInstance.getJSModule(AppRegistry.class)AppRegistry.class是JS层暴露给Java层的接口方法,它的真正实现在AppRegistry.js里,AppRegistry.js是运行所有RN应用的JS层入口,
runApplication(appKey: string, appParameters: any): void {
const msg =
'Running application "' +
appKey +
'" with appParams: ' +
JSON.stringify(appParameters) +
'. ' +
'__DEV__ === ' +
String(__DEV__) +
', development-level warning are ' +
(__DEV__ ? 'ON' : 'OFF') +
', performance optimizations are ' +
(__DEV__ ? 'OFF' : 'ON');
infoLog(msg);
BugReporting.addSource(
'AppRegistry.runApplication' + runCount++,
() => msg,
);
invariant(
runnables[appKey] && runnables[appKey].run,
'Application ' +
appKey +
' has not been registered.\n\n' +
"Hint: This error often happens when you're running the packager " +
'(local dev server) from a wrong folder. For example you have ' +
'multiple apps and the packager is still running for the app you ' +
'were working on before.\nIf this is the case, simply kill the old ' +
'packager instance (e.g. close the packager terminal window) ' +
'and start the packager in the correct app folder (e.g. cd into app ' +
"folder and run 'npm start').\n\n" +
'This error can also happen due to a require() error during ' +
'initialization or failure to call AppRegistry.registerComponent.\n\n',
);
SceneTracker.setActiveScene({name: appKey});
runnables[appKey].run(appParameters);
},
😀,基本到这,就会去调用JS进行组件渲染,再通过Java层的UIManagerModule将JS组件转换为Android组件,最终显示在ReactRootView上,即完成启动过程。😀
阅读源代码还是挺耗时的事情,哈哈。
同步更新至个人公众号及网站。
个人网站:https://wayne214.github.io
CSDN:https://blog.csdn.net/wayne214
公众号:君伟说。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。