ReactNative源码解析-启动流程
栏目: JavaScript · 发布时间: 5年前
内容简介:在开始分析启动流程之前,我们先从混合开发流程入手,大致分两步。1.继承ReactActivity,并完成相关初始化工作。注意:
在开始分析启动流程之前,我们先从混合开发流程入手,大致分两步。
1.继承ReactActivity,并完成相关初始化工作。
public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler { private ReactRootView mReactRootView; private ReactInstanceManager mReactInstanceManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setCurrentActivity(this) .setBundleAssetName("index.android.bundle") .setJSMainModulePath("index") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); // The string here (e.g. "MyReactNativeApp") has to match // the string in AppRegistry.registerComponent() in index.js mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null); setContentView(mReactRootView); } @Override public void invokeDefaultOnBackPressed() { super.onBackPressed(); } @Override protected void onPause() { super.onPause(); if (mReactInstanceManager != null) { mReactInstanceManager.onHostPause(this); } } @Override protected void onResume() { super.onResume(); if (mReactInstanceManager != null) { mReactInstanceManager.onHostResume(this, this); } } @Override protected void onDestroy() { super.onDestroy(); if (mReactInstanceManager != null) { mReactInstanceManager.onHostDestroy(this); } if (mReactRootView != null) { mReactRootView.unmountReactApplication(); } } @Override public void onBackPressed() { if (mReactInstanceManager != null) { mReactInstanceManager.onBackPressed(); } else { super.onBackPressed(); } } } 复制代码
注意:
a.实际开发中,一般会写一个单例来获取mReactInstanceManager对象,多个ReactFragment or ReactActivity可以共享同一个mReactInstanceManager对象。
b.mReactRootView作为ReactActivity的根布局,是一个容器View,我们编写的react代码,最终就是被attach到这里的。
2.编写React代码
import React from 'react'; import {AppRegistry, StyleSheet, Text, View} from 'react-native'; class HelloWorld extends React.Component { render() { return ( <View style={styles.container}> <Text style={styles.hello}>Hello, World</Text> </View> ); } } var styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', }, hello: { fontSize: 20, textAlign: 'center', margin: 10, }, }); AppRegistry.registerComponent('MyReactNativeApp', () => HelloWorld); 复制代码
完成以上2步,在增加一些配置操作,相信你应该能把一个demo run起来了。
二、启动流程
启动流程分以下几步:
1 在程序启动的时候,也就是ReactActivity的onCreate()函数中,我们会去创建一个ReactInstanceManager对象,ReactInstanceManager用于管理生命周期,管理ReactRootView,以及一些配置等。 2 ReactRootView作为应用的根视图,通过调用ReactRootView.startReactApplication()方法启动应用。 3 RN应用页面渲染前,需要先创建ReactContext的创建流程在,异步任务ReactContextInitAsyncTask负责来完成这个任务。 4 ReactContextInitAsyncTask在后台ReactContextInitAsyncTask.doInBackground()执行ReactContext的创建,创建ReactContext的过程中,会依据ReactPackage创建JavaScriptModuleRegistry与 NativeModuleRegistry注册表以及它们的管理类CatalystInstanceImpl,同时创建JS、Native与UI线程队列,并最终调用CatalystInstanceImpl.runJSBundle()去异步 加载JS Bundle文件。 5 后台任务执行完成后,在ReactContextInitAsyncTask.onPostExecute()会调用ReactInstanceManager.setupReactContext()设置创建好的ReactContext,并将 ReactRootView加载进来,并调用RN应用的JS入口APPRegistry来启动应用。 6 JS层找到已经注册的对应的启动组件,执行renderApplication()来渲染整个应用。 复制代码
按照初始化流程,我们从ReactActivity入手。通过查看源码我们发现,ReactActivity并没有做太多事情,大部分事情的交给了代理类ReactActivityDelegate来实现,那我们一起看看ReactActivityDelegate都干了什么。
public class ReactActivityDelegate { private final @Nullable Activity mActivity; private final @Nullable String mMainComponentName; private @Nullable ReactRootView mReactRootView; private @Nullable DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; private @Nullable PermissionListener mPermissionListener; private @Nullable Callback mPermissionsCallback; protected ReactRootView createRootView() { return new ReactRootView(getContext()); } protected ReactNativeHost getReactNativeHost() { return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost(); } public ReactInstanceManager getReactInstanceManager() { return getReactNativeHost().getReactInstanceManager(); } protected void onCreate(Bundle savedInstanceState) { String mainComponentName = getMainComponentName(); if (mainComponentName != null) { loadApp(mainComponentName); } mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); } protected void loadApp(String appKey) { if (mReactRootView != null) { throw new IllegalStateException("Cannot loadApp while app is already running."); } mReactRootView = createRootView(); mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), appKey, getLaunchOptions()); getPlainActivity().setContentView(mReactRootView); } } 复制代码
可以发现,ReactActivityDelegate在创建时主要做了3件事:
1.创建ReactRootView 2.调用mReactRootView的startReactApplication方法,继续执行应用启动流程 3.调用setContentView方法,将mReactRootView作为ReactActivity的content view 复制代码
从中不难发现,ReactNative真正的核心就在ReactRootView,,ReactRootView本质上是一个FrameLayout,并没有什么神奇的魔法,好,接下来让我们看看跳进ReactRootView继续我们的启动流程分析。
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"); mReactInstanceManager = reactInstanceManager; mJSModuleName = moduleName; mAppProperties = initialProperties; mInitialUITemplate = initialUITemplate; if (mUseSurface) { // TODO initialize surface here } if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { mReactInstanceManager.createReactContextInBackground(); } attachToReactInstanceManager(); } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } } 复制代码
在这个方法中,主要创建了应用的上下文-ReactContext,同时把传入的参数赋给了成员变量。
我们来看看这4个参数:
ReactInstanceManager reactInstanceManager :管理React实例。 String moduleName:模块的名字,对应ReactActivity.getMainComponentName()与AppRegistry.registerComponent()。 Bundle initialProperties:Bundle类型的数据,可以通过这个参数在startActivity()时传递参数到JS层。 String initialUITemplate:0.59版本并没有用到,可能是代码还没写完吧,尴尬。 复制代码
继续我们的启动流程,ReactInstanceManager.createReactContextInBackground()。看名字好像是在后台线程创建上下文,我们跳进去看看。
@ThreadSafe public class ReactInstanceManager { @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(); } @ThreadConfined(UI) public void recreateReactContextInBackground() { Assertions.assertCondition( mHasStartedCreatingInitialContext, "recreateReactContextInBackground should only be called after the initial " + "createReactContextInBackground call."); recreateReactContextInBackgroundInner(); } @ThreadConfined(UI) private void recreateReactContextInBackgroundInner() { Log.d(ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackgroundInner()"); PrinterHolder.getPrinter() .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: recreateReactContextInBackground"); UiThreadUtil.assertOnUiThread(); 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. onJSBundleLoadedFromServer(null); return; } if (!Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) { 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; } } recreateReactContextInBackgroundFromBundleLoader(); } @ThreadConfined(UI) private void recreateReactContextInBackgroundFromBundleLoader() { Log.d( ReactConstants.TAG, "ReactInstanceManager.recreateReactContextInBackgroundFromBundleLoader()"); PrinterHolder.getPrinter() .logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: load from BundleLoader"); recreateReactContextInBackground(mJavaScriptExecutorFactory, mBundleLoader); } @ThreadConfined(UI) private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) { Log.d(ReactConstants.TAG, "ReactInstanceManager.runCreateReactContextOnNewThread()"); UiThreadUtil.assertOnUiThread(); synchronized (mAttachedReactRoots) { synchronized (mReactContextLock) { if (mCurrentReactContext != null) { tearDownReactContext(mCurrentReactContext); mCurrentReactContext = null; } } } 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); ReactMarker.logMarker(VM_INIT); final ReactApplicationContext reactApplicationContext = createReactContext( initParams.getJsExecutorFactory().create(), initParams.getJsBundleLoader()); mCreateReactContextThread = null; ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_START); 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 { setupReactContext(reactApplicationContext); } catch (Exception e) { mDevSupportManager.handleException(e); } } }; reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable); UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable); } catch (Exception e) { mDevSupportManager.handleException(e); } } }, "create_react_context"); ReactMarker.logMarker(REACT_CONTEXT_THREAD_START); mCreateReactContextThread.start(); } private ReactApplicationContext createReactContext( JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) { Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()"); ReactMarker.logMarker(CREATE_REACT_CONTEXT_START, jsExecutor.getName()); //在这里创建ReactContext,ReactApplicationContext继承自ReactContext final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext); //查看外部是否设置NativeModuleCallExceptionHandler,它是在ReactInstanceManagerBuilder构建ReactInstanceManager是传递进来的 //如果设置了则使用外部NativeModuleCallExceptionHandler,如果没有设置则使用DevSupportManager。 NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null ? mNativeModuleCallExceptionHandler : mDevSupportManager; reactContext.setNativeModuleCallExceptionHandler(exceptionHandler); NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false); //jsExecutor、nativeModuleRegistry、nativeModuleRegistry等各种参数处理好之后,开始构建CatalystInstanceImpl实例。 CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder() .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) .setJSExecutor(jsExecutor) .setRegistry(nativeModuleRegistry) .setJSBundleLoader(jsBundleLoader) .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)) { catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true"); } ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START); Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle"); //加载JS Bundle catalystInstance.runJSBundle(); Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); //关联ReacContext与CatalystInstance reactContext.initializeWithInstance(catalystInstance); return reactContext; } private NativeModuleRegistry processPackages( ReactApplicationContext reactContext, List<ReactPackage> packages, boolean checkAndUpdatePackageMembership) { //创建JavaModule注册表Builder,用来创建JavaModule注册表,JavaModule注册表将所有的JavaModule注册到CatalystInstance中。 NativeModuleRegistryBuilder nativeModuleRegistryBuilder = new NativeModuleRegistryBuilder( reactContext, this); ReactMarker.logMarker(PROCESS_PACKAGES_START); // TODO(6818138): Solve use-case of native modules overriding synchronized (mPackages) { for (ReactPackage reactPackage : packages) { if (checkAndUpdatePackageMembership && mPackages.contains(reactPackage)) { continue; } Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createAndProcessCustomReactPackage"); try { if (checkAndUpdatePackageMembership) { mPackages.add(reactPackage); } // 递归处理我们在Application里注入的ReactPackage,处理的过程就是把各自的Module添加到对应的注册表中。 processPackage(reactPackage, nativeModuleRegistryBuilder); } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } } } ReactMarker.logMarker(PROCESS_PACKAGES_END); ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START); Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry"); NativeModuleRegistry nativeModuleRegistry; try { //生成Java Module注册表 nativeModuleRegistry = nativeModuleRegistryBuilder.build(); } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END); } return nativeModuleRegistry; } } 复制代码
辗转反侧,最终通过runCreateReactContextOnNewThread开启了一个线程,然后调用createReactContext(JavaScriptExecutor jsExecutor,JSBundleLoader jsBundleLoader)创建了ReactContext。我们重点来看看传入的2给参数:
JavaScriptExecutor jsExecutor:当该类被加载时,它会自动去加载"reactnativejnifb.so"库,并会调用Native方 法initHybrid()初始化C++层RN与JSC通信的框架。 JSBundleLoader jsBundleLoader:缓存了JSBundle的信息,封装了上层加载JSBundle的相关接口,CatalystInstance通过其简介调用ReactBridge去加载JS文件,不同的场景会创建 不同的加载器,具体可以查看类JSBundleLoader。 复制代码
createReactContext->processPackages主要做了以下几件事:
1 创建JavaModule注册表并交由CatalystInstance管理。 3 处理ReactPackage,将JavaModule放进对应的注册表里。 3 创建CatalystInstance实例。 4 关联ReactContext与CatalystInstance,并加载JS Bundle。 复制代码
接着看catalystInstance.runJSBundle(),该方法的调用栈如下:
CatalystInstanceImpl.runJSBundle() -> JSBundleLoader.loadScript() ->CatalystInstanceImpl.loadScriptFromAssets()/loadScriptFromFile() -> CatalystInstanceImpl.jniLoadScriptFromAssets()/jniLoadScriptFromFile() -> CatalystInstanceImpl::jniLoadScriptFromAssets()/jniLoadScriptFromFile() -> Instance::loadScriptFromString()/loadScriptFromFile() -> NativeToJsBridge::loadApplication() -> JSCExecutor::loadApplicationScript() 复制代码
最终由C++中的JSCExecutor.cpp完成了JS Bundle的加载,核心逻辑都在JSCExecutor.cpp中,这一块的内容我们后续的文章在详细分析,我们先来看看CatalystInstanceImpl的创建流程。
public class CatalystInstanceImpl implements CatalystInstance { 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(); //创建三个核心线程:Native Modules Thread、JS Thread、UI Thread,都是通过Handler来管理的。 mReactQueueConfiguration = ReactQueueConfigurationImpl.create( reactQueueConfigurationSpec, new NativeExceptionHandler()); mBridgeIdleListeners = new CopyOnWriteArrayList<>(); mNativeModuleRegistry = nativeModuleRegistry; // 创建JavaScriptModule注册表 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方法,创建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()); } private native void initializeBridge( ReactCallback callback, JavaScriptExecutor jsExecutor, MessageQueueThread jsQueue, MessageQueueThread moduleQueue, Collection<JavaModuleWrapper> javaModules, Collection<ModuleHolder> cxxModules); } 复制代码
从CatalystInstanceImpl的构建过程可以看出,CatalystInstanceImpl是个封装管理类,封装了各种注册表,以及初始化JNI,我们来看看最后初始化Bridge传入的6个参数:
ReactCallback callback:CatalystInstanceImpl的静态内部类ReactCallback,负责接口回调。 JavaScriptExecutor jsExecutor:JS执行器,将JS的调用传递给C++层。 MessageQueueThread jsQueue.getJSQueueThread():JS线程,通过mReactQueueConfiguration.getJSQueueThread()获得,mReactQueueConfiguration通过ReactQueueConfigurationSpec.createDefault()创建。 MessageQueueThread moduleQueue:Native线程,通过mReactQueueConfiguration.getNativeModulesQueueThread()获得,mReactQueueConfiguration通过ReactQueueConfigurationSpec.createDefault()创建。 Collection<JavaModuleWrapper> javaModules:java modules,来源于mJavaRegistry.getJavaModules(this)。 Collection<ModuleHolder> cxxModules):c++ modules,来源于mJavaRegistry.getCxxModules()。 复制代码
我们接着看,CatalystInstanceImpl.runJSBundle()
@Override public void runJSBundle() { Log.d(ReactConstants.TAG, "CatalystInstanceImpl.runJSBundle()"); Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!"); // incrementPendingJSCalls(); //调用加载器加载JS Bundle,不同情况下加载器不同。 mJSBundleLoader.loadScript(CatalystInstanceImpl.this); synchronized (mJSCallsPendingInitLock) { // Loading the bundle is queued on the JS thread, but may not have // run yet. It's safe to set this here, though, since any work it // gates will be queued on the JS thread behind the load. mAcceptCalls = true; for (PendingJSCall function : mJSCallsPendingInit) { function.call(this); } mJSCallsPendingInit.clear(); mJSBundleHasLoaded = true; } // This is registered after JS starts since it makes a JS call Systrace.registerListener(mTraceListener); } 复制代码
接着调用JSBundleLoader.loadScript
public abstract class JSBundleLoader { /** * This loader is recommended one for release version of your app. In that case local JS executor * should be used. JS bundle will be read from assets in native code to save on passing large * strings from java to native memory. */ // 从assets文件加载 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; } }; } /** * This loader loads bundle from file system. The bundle will be read in native code to save on * passing large strings from java to native memory. */ public static JSBundleLoader createFileLoader(final String fileName) { return createFileLoader(fileName, fileName, false); } // 从文件加载 public static JSBundleLoader createFileLoader( final String fileName, final String assetUrl, final boolean loadSynchronously) { return new JSBundleLoader() { @Override public String loadScript(JSBundleLoaderDelegate delegate) { delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously); return fileName; } }; } /** * This loader is used when bundle gets reloaded from dev server. In that case loader expect JS * bundle to be prefetched and stored in local file. We do that to avoid passing large strings * between java and native code and avoid allocating memory in java to fit whole JS bundle in it. * Providing correct {@param sourceURL} of downloaded bundle is required for JS stacktraces to * work correctly and allows for source maps to correctly symbolize those. */ //从缓存加载 public static JSBundleLoader createCachedBundleFromNetworkLoader( final String sourceURL, final String cachedFileLocation) { return new JSBundleLoader() { @Override public String loadScript(JSBundleLoaderDelegate delegate) { try { delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false); return sourceURL; } catch (Exception e) { throw DebugServerException.makeGeneric(e.getMessage(), e); } } }; } /** * This loader is used to load delta bundles from the dev server. We pass each delta message to * the loader and process it in C++. Passing it as a string leads to inefficiencies due to memory * copies, which will have to be addressed in a follow-up. * @param nativeDeltaClient */ // 从dev server加载 public static JSBundleLoader createDeltaFromNetworkLoader( final String sourceURL, final NativeDeltaClient nativeDeltaClient) { return new JSBundleLoader() { @Override public String loadScript(JSBundleLoaderDelegate delegate) { try { delegate.loadScriptFromDeltaBundle(sourceURL, nativeDeltaClient, false); return sourceURL; } catch (Exception e) { throw DebugServerException.makeGeneric(e.getMessage(), e); } } }; } /** * This loader is used when proxy debugging is enabled. In that case there is no point in fetching * the bundle from device as remote executor will have to do it anyway. */ // debug时加载 public static JSBundleLoader createRemoteDebuggerBundleLoader( final String proxySourceURL, final String realSourceURL) { return new JSBundleLoader() { @Override public String loadScript(JSBundleLoaderDelegate delegate) { delegate.setSourceURLs(realSourceURL, proxySourceURL); return realSourceURL; } }; } /** Loads the script, returning the URL of the source it loaded. */ public abstract String loadScript(JSBundleLoaderDelegate delegate); } 复制代码
接下来我们以CatalystInstanceImpl.loadScriptFromAssets()举例。
@Override public void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously) { mSourceURL = assetURL; jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously); } 复制代码
可以看出该方法最终调用Native方法jniLoadScriptFromAssets去加载JS Bundle,来到CatalystInstanceImpl.cpp。
void CatalystInstanceImpl::jniLoadScriptFromAssets( jni::alias_ref<JAssetManager::javaobject> assetManager, const std::string& assetURL, bool loadSynchronously) { const int kAssetsLength = 9; // strlen("assets://"); // 获取source js Bundle的路径名 auto sourceURL = assetURL.substr(kAssetsLength); //获取AssetManager对象。 auto manager = extractAssetManager(assetManager); //读取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 { //bundle命令打包走此流程 instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously); } } 关于unbundle命令 <unbundle命令,使用方式和bundle命令完全相同。unbundle命令是在bundle命令的基础上增加了一项功能,除了生成整合JS文件index.android.bundle外,还会 生成各个单独的未整合JS文件(但会被优化),全部放在js-modules目录下,同时会生成一个名为UNBUNDLE的标识文件,一并放在其中。UNBUNDLE标识文件的前4个字节 固定为0xFB0BD1E5,用于加载前的校验。 复制代码
接着会调用Instance.cpp的loadScriptFromString()方法去解析JS Bundle里的内容。
void Instance::loadScriptFromString(std::unique_ptr<const JSBigString> string, std::string sourceURL, bool loadSynchronously) { SystraceSection s("Instance::loadScriptFromString", "sourceURL", sourceURL); if (loadSynchronously) { loadApplicationSync(nullptr, std::move(string), std::move(sourceURL)); } else { loadApplication(nullptr, std::move(string), std::move(sourceURL)); } } 复制代码
进一步调用NativeToJsBridge.cpp的loadApplication()方法,它的实现如下所示:
void NativeToJsBridge::loadApplication( std::unique_ptr<RAMBundleRegistry> bundleRegistry, std::unique_ptr<const JSBigString> startupScript, std::string startupScriptSourceURL) { runOnExecutorQueue( [this, bundleRegistryWrap=folly::makeMoveWrapper(std::move(bundleRegistry)), startupScript=folly::makeMoveWrapper(std::move(startupScript)), startupScriptSourceURL=std::move(startupScriptSourceURL)] (JSExecutor* executor) mutable { auto bundleRegistry = bundleRegistryWrap.move(); if (bundleRegistry) { executor->setBundleRegistry(std::move(bundleRegistry)); } try { //Java中的JSCJavaScriptExecutor对应。它的实例在JSIExecutor.cpp中实现。 executor->loadApplicationScript(std::move(*startupScript), std::move(startupScriptSourceURL)); } catch (...) { m_applicationScriptHasFailure = true; throw; } }); } 复制代码
进一步调用JSIExecutor.cpp的loadApplicationScript()方法。
void JSIExecutor::loadApplicationScript( std::unique_ptr<const JSBigString> script, std::string sourceURL) { SystraceSection s("JSIExecutor::loadApplicationScript"); // TODO: check for and use precompiled HBC runtime_->global().setProperty( *runtime_, "nativeModuleProxy", Object::createFromHostObject( *runtime_, std::make_shared<NativeModuleProxy>(*this))); runtime_->global().setProperty( *runtime_, "nativeFlushQueueImmediate", Function::createFromHostFunction( *runtime_, PropNameID::forAscii(*runtime_, "nativeFlushQueueImmediate"), 1, [this]( jsi::Runtime &, const jsi::Value &, const jsi::Value *args, size_t count) { if (count != 1) { throw std::invalid_argument( "nativeFlushQueueImmediate arg count must be 1"); } callNativeModules(args[0], false); return Value::undefined(); })); runtime_->global().setProperty( *runtime_, "nativeCallSyncHook", Function::createFromHostFunction( *runtime_, PropNameID::forAscii(*runtime_, "nativeCallSyncHook"), 1, [this]( jsi::Runtime &, const jsi::Value &, const jsi::Value *args, size_t count) { return nativeCallSyncHook(args, count); })); if (runtimeInstaller_) { runtimeInstaller_(*runtime_); } bool hasLogger(ReactMarker::logTaggedMarker); std::string scriptName = simpleBasename(sourceURL); if (hasLogger) { ReactMarker::logTaggedMarker( ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str()); } // //解释执行JS runtime_->evaluateJavaScript( std::make_unique<BigStringBuffer>(std::move(script)), sourceURL); flush(); if (hasLogger) { ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP); ReactMarker::logTaggedMarker( ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str()); } } void JSIExecutor::flush() { SystraceSection s("JSIExecutor::flush"); if (flushedQueue_) { callNativeModules(flushedQueue_->call(*runtime_), true); return; } // When a native module is called from JS, BatchedBridge.enqueueNativeCall() // is invoked. For that to work, require('BatchedBridge') has to be called, // and when that happens, __fbBatchedBridge is set as a side effect. Value batchedBridge = runtime_->global().getProperty(*runtime_, "__fbBatchedBridge"); // So here, if __fbBatchedBridge doesn't exist, then we know no native calls // have happened, and we were able to determine this without forcing // BatchedBridge to be loaded as a side effect. if (!batchedBridge.isUndefined()) { // If calls were made, we bind to the JS bridge methods, and use them to // get the pending queue of native calls. //绑定bridge bindBridge(); //把JS层相关通信数据通过flushedQUeue() //返回给callNativeModules callNativeModules(flushedQueue_->call(*runtime_), true); } else if (delegate_) { // If we have a delegate, we need to call it; we pass a null list to // callNativeModules, since we know there are no native calls, without // calling into JS again. If no calls were made and there's no delegate, // nothing happens, which is correct. callNativeModules(nullptr, true); } void JSIExecutor::bindBridge() { std::call_once(bindFlag_, [this] { SystraceSection s("JSIExecutor::bindBridge (once)"); Value batchedBridgeValue = runtime_->global().getProperty(*runtime_, "__fbBatchedBridge"); if (batchedBridgeValue.isUndefined()) { throw JSINativeException( "Could not get BatchedBridge, make sure your bundle is packaged correctly"); } Object batchedBridge = batchedBridgeValue.asObject(*runtime_); callFunctionReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction( *runtime_, "callFunctionReturnFlushedQueue"); invokeCallbackAndReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction( *runtime_, "invokeCallbackAndReturnFlushedQueue"); flushedQueue_ = batchedBridge.getPropertyAsFunction(*runtime_, "flushedQueue"); callFunctionReturnResultAndFlushedQueue_ = batchedBridge.getPropertyAsFunction( *runtime_, "callFunctionReturnResultAndFlushedQueue"); }); } void JSIExecutor::callNativeModules(const Value &queue, bool isEndOfBatch) { SystraceSection s("JSIExecutor::callNativeModules"); // If this fails, you need to pass a fully functional delegate with a // module registry to the factory/ctor. CHECK(delegate_) << "Attempting to use native modules without a delegate"; #if 0 // maybe useful for debugging std::string json = runtime_->global().getPropertyAsObject(*runtime_, "JSON") .getPropertyAsFunction(*runtime_, "stringify").call(*runtime_, queue) .getString(*runtime_).utf8(*runtime_); #endif //m_delegate为JsToNativeBridge对象。 delegate_->callNativeModules( *this, dynamicFromValue(*runtime_, queue), isEndOfBatch); } } 复制代码
m_flushedQueueJS支线的是MessageQueue.js的flushedQueue()方法,此时JS已经被加载到队列中,等待 Java 层来驱动它。加载完JS后,返回reactApplicationContext,我们继续跟进它的实现。
@ThreadConfined(UI) private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) { Log.d(ReactConstants.TAG, "ReactInstanceManager.runCreateReactContextOnNewThread()"); UiThreadUtil.assertOnUiThread(); synchronized (mAttachedReactRoots) { synchronized (mReactContextLock) { if (mCurrentReactContext != null) { tearDownReactContext(mCurrentReactContext); mCurrentReactContext = null; } } } 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); ReactMarker.logMarker(VM_INIT); final ReactApplicationContext reactApplicationContext = createReactContext( initParams.getJsExecutorFactory().create(), initParams.getJsBundleLoader()); mCreateReactContextThread = null; ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_START); 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 { setupReactContext(reactApplicationContext); } catch (Exception e) { mDevSupportManager.handleException(e); } } }; reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable); UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable); } catch (Exception e) { mDevSupportManager.handleException(e); } } }, "create_react_context"); ReactMarker.logMarker(REACT_CONTEXT_THREAD_START); mCreateReactContextThread.start(); } 复制代码
接着调用 setupReactContext(reactApplicationContext);
private void setupReactContext(final ReactApplicationContext reactContext) { Log.d(ReactConstants.TAG, "ReactInstanceManager.setupReactContext()"); ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_END); ReactMarker.logMarker(SETUP_REACT_CONTEXT_START); Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext"); synchronized (mAttachedReactRoots) { synchronized (mReactContextLock) { mCurrentReactContext = Assertions.assertNotNull(reactContext); } CatalystInstance catalystInstance = Assertions.assertNotNull(reactContext.getCatalystInstance()); // Native Java module的初始化 catalystInstance.initialize(); mDevSupportManager.onNewReactContextCreated(reactContext); mMemoryPressureRouter.addMemoryPressureListener(catalystInstance); //复位生命周期 moveReactContextToCurrentLifecycleState(); ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START); //遍历ReactRootView for (ReactRoot reactRoot : mAttachedReactRoots) { //遍历ReactRootView attachRootViewToInstance(reactRoot); } ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END); } ReactInstanceEventListener[] listeners = new ReactInstanceEventListener[mReactInstanceEventListeners.size()]; final ReactInstanceEventListener[] finalListeners = mReactInstanceEventListeners.toArray(listeners); UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { for (ReactInstanceEventListener listener : finalListeners) { listener.onReactContextInitialized(reactContext); } } }); Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(SETUP_REACT_CONTEXT_END); reactContext.runOnJSQueueThread( new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); ReactMarker.logMarker(CHANGE_THREAD_PRIORITY, "js_default"); } }); reactContext.runOnNativeModulesQueueThread( new Runnable() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); } }); } 复制代码
reactRootView的attach操作。
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(); // 将ReactRootView作为根布局 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); } 复制代码
reactRoot.runApplication(),我们跟进去看一下。
@Override public void runApplication() { Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactRootView.runApplication"); try { if (mReactInstanceManager == null || !mIsAttachedToInstance) { return; } ReactContext reactContext = mReactInstanceManager.getCurrentReactContext(); if (reactContext == null) { return; } CatalystInstance catalystInstance = reactContext.getCatalystInstance(); String jsAppModuleName = getJSModuleName(); if (mUseSurface) { // TODO call surface's runApplication } else { if (mWasMeasured) { updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec); } WritableNativeMap appParams = new WritableNativeMap(); appParams.putDouble("rootTag", getRootViewTag()); @Nullable Bundle appProperties = getAppProperties(); if (appProperties != null) { appParams.putMap("initialProps", Arguments.fromBundle(appProperties)); } if (getUIManagerType() == FABRIC) { appParams.putBoolean("fabric", true); } mShouldLogContentAppeared = true; catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams); } } finally { Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); } } 复制代码
ReactInstanceManager.attachMeasuredRootViewToInstance()最终进入了RN应用的启动流程入口,调用catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams)。 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' ); runnables[appKey].run(appParameters); }, 复制代码
到这里就会去调用JS进行组件渲染,再通过Java层的UIManagerModule将JS组件转换为Android组件,最终显示在ReactRootView上,下期我们再见。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- ReactNative源码解析-初识源码
- Spring源码系列:BeanDefinition源码解析
- Spring源码分析:AOP源码解析(下篇)
- Spring源码分析:AOP源码解析(上篇)
- 注册中心 Eureka 源码解析 —— EndPoint 与 解析器
- 新一代Json解析库Moshi源码解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Photoshop Anthology
Corrie Haffly / SitePoint Pty. Ltd. / 2006 / USD 39.95
The Photoshop Anthology is full-color, question-and-answer book for Web Designers who want to use Photoshop to build Websites and create better looking web graphics more effectively. The book covers: ......一起来看看 《The Photoshop Anthology》 这本书的介绍吧!