前言
- 文中所有 RN 缩写指代React Native For Android
- 分析的 RN 代码基于
1 2 3 4
| { "react": "15.4.1", "react-native": "0.39.2" }
|
- 本文主要分析 Java 层实现,对 C++ 和 JS 笔墨较少。
- 阅读正文将花费您大约20分钟。
背景
公司内几个 APP 已经接入并上线了多个 RN 模块,后续规划的定制化需求及性能优化需要我们对 RN 底层原理有更深入的理解。下面通过研读源代码来分析和总结下 Android 中的 RN 实现原理。
从示例入手
之前写过一篇弹射起步:Android原生项目集成React Native模块。
示例代码如下:
1 2 3 4 5 6
| public class MainActivity extends ReactActivity { @Override protected String getMainComponentName() { return "RN_Demo"; } }
|
可以发现 RN 容器外层本质也是一个 Activity ,继承了 ReactActivity ,需要我们覆写 getMainComponentName()
方法,更改其返回值为组件名。
ReactActivity
接着跟踪到 ReactActivity
中,类结构如下:
根据上述的结构转换成 UML 图如下(后面相关类将直接给出 UML ):
这里使用了委托模式将 Activity
的生命周期及事件传递委托给 ReactActivityDelegate
的实例对象 mDelegate
进行处理,之所以使用这种形式是为了让 ReactFragmentActivity
也能复用该处理逻辑。
此外如果你有自定义的委托实现,可以在自己的 Activity
中覆写 createReactActivityDelegate()
方法。这个方法将在 ReactActivity
的构造函数中调用生成 mDelegate
实例,之后在 onCreate()
方法调用这个委托对象的执行入口,也就是loadApp()
方法。
ReactActivityDelegate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class ReactActivityDelegate { protected void onCreate(Bundle savedInstanceState) { if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) { } if (mMainComponentName != null) { loadApp(mMainComponentName); } }
protected void loadApp(String appKey) { mReactRootView = createRootView(); mReactRootView.startReactApplication( getReactNativeHost().getReactInstanceManager(), appKey, getLaunchOptions()); getPlainActivity().setContentView(mReactRootView); } }
|
ReactRootView
因此可以认为所谓的 RN 其实就是一个特殊的“自定义 View ”– ReactRootView
。
这里的关键调用则是 startReactApplication()
方法。下面是该方法需要的三个参数:
形参 |
类型 |
功能描述 |
reactInstanceManager |
ReactInstanceManager |
用来创建及管理 CatalyInstance (提供原生与JS互调环境)的实例,同时连接调试功能,其生命周期与 ReactRootView 所在 Activity 保持一致。 |
moduleName |
String |
即实参 appKey ,需要保证JS中的 AppRegistry.registerComponent 参数值与 Acitvity 中的 getMainComponentName 返回值一致。 |
launchOptions |
Bundle(后续版本可能更改为POJO) |
默认为null,如果你需要传 Props 给 JS 的话,请覆写 createReactActivityDelegate() 方法,并覆写 getLaunchOptions() 的返回值即可。 |
1 2 3 4 5 6 7 8 9 10 11 12
| public void startReactApplication( ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle launchOptions) { if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { mReactInstanceManager.createReactContextInBackground(); } }
|
startReactApplication()
将调用其中的 createReactContextInBackground()
方法,我们下面来看看这个通过构造者模式创建的实现类– XReactInstanceManagerImpl
。
ReactInstanceManager
1 2 3 4 5 6 7 8 9 10
|
@Override public void createReactContextInBackground() { mHasStartedCreatingInitialContext = true; recreateReactContextInBackgroundInner(); }
|
可以看到不管是 createReactContextInBackground()
还是 recreateReactContextInBackground()
,都是通过 recreateReactContextInBackgroundInner()
来初始化 ReactContext
的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| private void recreateReactContextInBackgroundInner() { if (mUseDeveloperSupport && mJSMainModuleName != null) { return; } recreateReactContextInBackgroundFromBundleLoader(); } private void recreateReactContextInBackgroundFromBundleLoader() { recreateReactContextInBackground( new JSCJavaScriptExecutor.Factory(mJSCConfig.getConfigMap()), mBundleLoader); } }
|
形参 |
类型 |
功能描述 |
jsExecutorFactory |
JavaScriptExecutor.Factory |
管理Webkit 的 JavaScriptCore,JS与C++的双向通信在这里中转 |
jsBundleLoader |
JSBundleLoader |
bundle加载器,根据ReactNativeHost 中的配置决定从哪里加载bundle文件 |
XReactInstanceManagerImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| private void recreateReactContextInBackground( JavaScriptExecutor.Factory jsExecutorFactory, JSBundleLoader jsBundleLoader) {
/ 把两个参数封装成ReactContextInitParams对象 ReactContextInitParams initParams = new ReactContextInitParams(jsExecutorFactory, jsBundleLoader); if (mReactContextInitAsyncTask == null) { mReactContextInitAsyncTask = new ReactContextInitAsyncTask(); mReactContextInitAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, initParams); } else { } }
|
ReactContextInitAsyncTask
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| private ReactApplicationContext createReactContext( JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) { JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder();
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext); if (mUseDeveloperSupport) { reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager); }
try { CoreModulesPackage coreModulesPackage = new CoreModulesPackage(this, mBackBtnHandler, mUIImplementationProvider); processPackage( coreModulesPackage, reactContext, moduleSpecs, reactModuleInfoMap, jsModulesBuilder); } finally { }
for (ReactPackage reactPackage : mPackages) { try { processPackage( reactPackage, reactContext, moduleSpecs, reactModuleInfoMap, jsModulesBuilder); } finally { } } NativeModuleRegistry nativeModuleRegistry; try { nativeModuleRegistry = new NativeModuleRegistry(moduleSpecs, reactModuleInfoMap); } finally { }
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null ? mNativeModuleCallExceptionHandler : mDevSupportManager; CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder() .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) .setJSExecutor(jsExecutor) .setRegistry(nativeModuleRegistry) .setJSModuleRegistry(jsModulesBuilder.build()) .setJSBundleLoader(jsBundleLoader) .setNativeModuleCallExceptionHandler(exceptionHandler);
final CatalystInstance catalystInstance; try { catalystInstance = catalystInstanceBuilder.build(); } finally { }
if (mBridgeIdleDebugListener != null) { catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener); } reactContext.initializeWithInstance(catalystInstance); catalystInstance.runJSBundle();
return reactContext; }
|
原生模块 |
功能描述 |
AndroidInfoModule |
获取Android版本号和本地服务器地址 |
AnimationsDebugModule |
监听动画过渡性能 |
DeviceEventManagerModule |
事件监听,比如后退键 |
ExceptionsManagerModule |
异常处理 |
HeadlessJsTaskSupportModule |
通知部分JS任务执行完成 |
SourceCodeModule |
传递Bundle文件地址 |
Timing |
在绘制帧率变化时触发JS定时器 |
UIManagerModule |
提供JS去创建和更新原生视图的能力 |
DebugComponentOwnershipModule |
调试功能:异步请求视图结构 |
JSCHeapCapture |
调试功能:获取堆内存信息 |
JSCSamplingProfiler |
调试功能:dump工具 |
CatalystInstance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| private CatalystInstanceImpl( final ReactQueueConfigurationSpec ReactQueueConfigurationSpec, final JavaScriptExecutor jsExecutor, final NativeModuleRegistry registry, final JavaScriptModuleRegistry jsModuleRegistry, final JSBundleLoader jsBundleLoader, NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) { mReactQueueConfiguration = ReactQueueConfigurationImpl.create( ReactQueueConfigurationSpec, new NativeExceptionHandler()); initializeBridge( new BridgeCallback(this), jsExecutor, mReactQueueConfiguration.getJSQueueThread(), mReactQueueConfiguration.getNativeModulesQueueThread(), mJavaRegistry.getModuleRegistryHolder(this)); mMainExecutorToken = getMainExecutorToken(); } @Override public void runJSBundle() { mJSBundleHasLoaded = true; mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
}
|
1 2 3 4 5 6 7 8 9
| private native void initializeBridge(ReactCallback callback, JavaScriptExecutor jsExecutor, MessageQueueThread jsQueue, MessageQueueThread moduleQueue, ModuleRegistryHolder registryHolder); native void loadScriptFromAssets(AssetManager assetManager, String assetURL); native void loadScriptFromFile(String fileName, String sourceURL); native void loadScriptFromOptimizedBundle(String path, String sourceURL, int flags);
|
此时已经发现Java层的逻辑已经走完,不管是 CatalystInstance
实例的初始化还是 Bundle 的加载逻辑都将由 C++
层进行处理。
CatalystInstance的创建
CatalystInstanceImpl.cpp
中是空实现,具体实现在 Instance.cpp
中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| void CatalystInstanceImpl::initializeBridge( std::unique_ptr<InstanceCallback> callback, std::shared_ptr<JSExecutorFactory> jsef, std::shared_ptr<MessageQueueThread> jsQueue, std::unique_ptr<MessageQueueThread> nativeQueue, std::shared_ptr<ModuleRegistry> moduleRegistry) { callback_ = std::move(callback);
jsQueue->runOnQueueSync( [this, &jsef, moduleRegistry, jsQueue, nativeQueue=folly::makeMoveWrapper(std::move(nativeQueue))] () mutable { nativeToJsBridge_ = folly::make_unique<NativeToJsBridge>( jsef.get(), moduleRegistry, jsQueue, nativeQueue.move(), callback_);
std::lock_guard<std::mutex> lock(m_syncMutex); m_syncReady = true; m_syncCV.notify_all(); });
CHECK(nativeToJsBridge_); }
|
Bundle 的加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| void CatalystInstanceImpl::loadScriptFromAssets(jobject assetManager, const std::string& assetURL) { const int kAssetsLength = 9; auto sourceURL = assetURL.substr(kAssetsLength); auto manager = react::extractAssetManager(assetManager); auto script = react::loadScriptFromAssets(manager, sourceURL); if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) { instance_->loadUnbundle( folly::make_unique<JniJSModulesUnbundle>(manager, sourceURL), std::move(script), sourceURL); return; } else { instance_->loadScriptFromString(std::move(script), sourceURL); } }
|
至此 C++
层的调用逻辑到此为止,感兴趣的同学可以继续跟踪进入,或者可以参考文末的资料,我们下面假设底层执行完成,回到 ReactContextInitAsyncTask
的 onPostExecute
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| @Override protected void onPostExecute(Result<ReactApplicationContext> result) { setupReactContext(result.get());
} private void setupReactContext(ReactApplicationContext reactContext) { Assertions.assertCondition(mCurrentReactContext == null); CatalystInstance catalystInstance = Assertions.assertNotNull(reactContext.getCatalystInstance()); catalystInstance.initialize(); mDevSupportManager.onNewReactContextCreated(reactContext); mMemoryPressureRouter.addMemoryPressureListener(catalystInstance); moveReactContextToCurrentLifecycleState();
for (ReactRootView rootView : mAttachedRootViews) { attachMeasuredRootViewToInstance(rootView, catalystInstance); } } private void attachMeasuredRootViewToInstance( ReactRootView rootView, CatalystInstance catalystInstance) {
rootView.removeAllViews(); rootView.setId(View.NO_ID);
UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class); int rootTag = uiManagerModule.addMeasuredRootView(rootView); rootView.setRootViewTag(rootTag); @Nullable Bundle launchOptions = rootView.getLaunchOptions(); WritableMap initialProps = Arguments.makeNativeMap(launchOptions); String jsAppModuleName = rootView.getJSModuleName();
WritableNativeMap appParams = new WritableNativeMap(); appParams.putDouble("rootTag", rootTag); appParams.putMap("initialProps", initialProps); catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams); }
|
AppRegistry
1 2 3 4 5
| public interface AppRegistry extends JavaScriptModule { void runApplication(String appKey, WritableMap appParameters); void unmountApplicationComponentAtRootTag(int rootNodeTag); void startHeadlessTask(int taskId, String taskKey, WritableMap data); }
|
AppRegistry
的 runApplication()
方法成为了加载 index.android.js
的主入口,而所有的 JS 方法调用都会经过 JavaScriptModuleInvocationHandler
。
JavaScriptModuleInvocationHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ExecutorToken executorToken = mExecutorToken.get(); NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray(); mCatalystInstance.callFunction( executorToken, mModuleRegistration.getName(), method.getName(), jsArgs ); return null; }
|
以上就是 RN Android 的执行主流程,如有疏漏,欢迎留言。
参考资料
- https://github.com/facebook/react-native
- ReactNative Android源码分析
- React Native Android 源码框架浅析(主流程及 Java 与 JS 双边通信)
- React Native通讯原理
- ReactNativeAndroid源码分析-Js如何调用Native的代码