react-native源码分析系列一

react-native源码目前我看到过的最好的分析文章是qq空间分析的这篇。

http://zhuanlan.zhihu.com/magilu/20259704

不得不说大厂推出的分析确实牛逼,逻辑清晰。

不过由于博主自己也读过源码,也做过一些分析,因此准备将这些分析整理一下放出来(这个系列会比较长。

react-native 官网https://github.com/facebook/react-native

这里不介绍怎么使用,有兴趣的可以参考我的个人项目https://github.com/xiaoshenke/React-Online-News

照例我们从demo开始分析,我看的demo是react-native/Examples/Movies工程。

以下rn代指react-native。


可以看到初始化代码只有两行。
先看第一行代码,初始化构建ReactInstanceManager。
ReactInstanceManager
mReactInstanceManager = ReactInstanceManager.builder()           //builder模式
.setApplication(getApplication())
.setBundleAssetName("MoviesApp.android.bundle")                        //bundleName貌似可以随便取
.setJSMainModuleName("Examples/Movies/MoviesApp.android")  //这里的名字必须是对应js文件入口的名字
.addPackage(new MainReactPackage())                                            //注意名字 这里就是主要的rn包//官网有说明怎么加自定义包
.setUseDeveloperSupport(true)                                                      //manifest中的DevSettingsActivity
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();

public ReactInstanceManager build() {
  return new ReactInstanceManager(
     Assertions.assertNotNull(
         mApplication,
         "Application property has not been set with this builder"),
     mBundleAssetName,
     mJSMainModuleName,
     mPackages,
     mUseDeveloperSupport,
     mBridgeIdleDebugListener,
     Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"));
}

private ReactInstanceManager(                                          //ReactInstanceManager构造函数 
   Context applicationContext,
   @Nullable String bundleAssetName,
   @Nullable String jsMainModuleName,
   List<ReactPackage> packages,
   boolean useDeveloperSupport,
   @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
   LifecycleState initialLifecycleState) {
  initializeSoLoaderIfNecessary(applicationContext);
  mApplicationContext = applicationContext;
  mBundleAssetName = bundleAssetName ;                         //这里传入的是“ MoviesApp.android.bundle"
  mJSMainModuleName = jsMainModuleName;                  //这里传入的是“Examples/Movies/MoviesApp.android
  mPackages = packages;                
  mUseDeveloperSupport = useDeveloperSupport;              //这里传入的是true
  // We need to instantiate DevSupportManager regardless to the useDeveloperSupport option,
  // although will prevent dev support manager from displaying any options or dialogs by
  // checking useDeveloperSupport option before calling setDevSupportEnabled on this manager
  // TODO(6803830): Don't instantiate devsupport manager when useDeveloperSupport is false
  mDevSupportManager = new DevSupportManager(         //调试用 这里不分析
     applicationContext,
     mDevInterface,
     mJSMainModuleName,
     useDeveloperSupport);
  mBridgeIdleDebugListener = bridgeIdleDebugListener;
  mLifecycleState = initialLifecycleState;
}

                通过以上过程构造出了ReactInstanceManager
然后是第二行代码。ReactRootView.startReactApplication
我们看一下ReactRootView是干啥的。
     所以ReactRootView是React工程中的rootview,并且负责分发各种touch事件。
public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
public class SizeMonitoringFrameLayout extends FrameLayout
public interface RootView {
  void onChildStartedNativeGesture(MotionEvent androidEvent);
}

继续看真正的初始化入口startReactApplication函数。
/**
* 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 launchOptions) {         //这里的moduleName传入的是“MoviesApp”
        //如果你懂一点React.js的话 js代码大概长这样 module.exports=MoviesApp-->就是说这是一个可以被其他mudule调用的对象
  mReactInstanceManager = reactInstanceManager;
  mJSModuleName = moduleName;
  mLaunchOptions = launchOptions;
  if (mWasMeasured && mIsAttachedToWindow) {
   mReactInstanceManager.attachMeasuredRootView(this);      //真正的入口
   mIsAttachedToInstance = true;
   getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
  } else {
   mAttachScheduled = true;
  }
}   

/**
* Attach given {@param rootView} to a catalyst instance manager and start JS application using
* JS module provided by {@link ReactRootView#getJSModuleName}. This view will then be tracked
* by this manager and in case of catalyst instance restart it will be re-attached.
*/
/* package */ void attachMeasuredRootView(ReactRootView rootView) {
  UiThreadUtil.assertOnUiThread();
  mAttachedRootViews.add(rootView);
  if (mCurrentReactContext == null) {
   initializeReactContext();       //生成重要对象ReactContext(很眼熟是不是~ 这个context继承自android的ContextWrapper
      //关于context 老罗的这篇文章http://blog.csdn.net/luoshengyang/article/details/8201936里
      //可以看到Activity是继承自ContextWrapper的  
  } else {
   attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
  }
}

initializeReactContext  —> createReactContext   //中间一系列调用略去

/**
* @return instance of {@link ReactContext} configured a {@link CatalystInstance} set
*/
private ReactApplicationContext createReactContext(
   JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
   ...
}                              重要函数  //后面一篇文章具体分析这个函数
      //剧透一下 大概就是干了生成一个context 注册了一堆双方共用的控件 服务 其实就是打通了js native代码交互的通道
       
createReactContext后会调用attachMeasuredRootViewToInstance
private void attachMeasuredRootViewToInstance(
   ReactRootView rootView, CatalystInstance catalystInstance) {
  UiThreadUtil.assertOnUiThread();
  // Reset view content as it's going to be populated by the application content from JS
  rootView.removeAllViews();
  rootView.setId(View.NO_ID);
  UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class); //注意名字 nativeModule
      //统一处理js java两边对应控件的manager
      // rn是用js封装了一套native的对应控件 比如native里的DrawerLayout js那边对应的是drawerLayoutAndroid
      //因此需要一个manager来进行协调
  int rootTag = uiManagerModule.addMeasuredRootView(rootView) ;   
                               //这里调用了native的addMeasuredRootView
  @Nullable Bundle launchOptions = rootView.getLaunchOptions();
  WritableMap initialProps = launchOptions != null
     ? Arguments.fromBundle(launchOptions)
     : Arguments.createMap();
  String jsAppModuleName = rootView.getJSModuleName();          //注意名字 jsModule
  WritableNativeMap appParams = new WritableNativeMap();
  appParams.putDouble("rootTag", rootTag);
  appParams.putMap("initialProps", initialProps);
  catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
                //这里获取了js的一个模块 AppRegistry 并调用了js模块里的runApplication函数
}  

ctrl f搜索runApplication。可以看到对应的js文件及runApplication这个接口。


AppRegistry.js文件。


好了,第一篇文章先到这里。
总结一下,这篇文章分析了react-native初始化的过程(两行代码。
第一行代码,构造出一个reactInstanceManager类(这个类就是一个调度类。
第二行代码,ReactRootView.startApplication(这里是初始化入口,包括生成重要的ReactContext 以及后面的打通js java native通信等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值