React Native 源码浅析

React Native 源码浅析

1.RN是如何完成bundle文件加载的?

2.Native和JS之间是如何通讯的?

3.JS布局是怎么样被渲染到ReactRootView上的?

下面通过对RN源码(版本:0.40.0)的分析,尝试找找这3个问题的答案~

chengyuan-macpro:AwesomeProject chengyuan$ react-native -V
0.40.0

一、JSBundle加载过程

上一篇博客React Native 用法介绍有提到过将js文件打包成bundle,存放到assets目录下,RN页面启动后会加载bundle包,下面就具体看下bundle的加载过程~

public abstract class ReactActivity extends Activity
    implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
   

  private final ReactActivityDelegate mDelegate;

  protected ReactActivity() {
    mDelegate = createReactActivityDelegate();
  }
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mDelegate.onCreate(savedInstanceState);
  }
  //省略非关键代码
}

这里使用委托模式将 Activity 的生命周期及事件传递委托给 ReactActivityDelegate进行处理,这样用是为了让 ReactFragmentActivity 也能复用该处理逻辑。

在ReactActivityDelegate的onCreate中调用了loadApp

// ReactActivityDelegate.java
protected void loadApp(String appKey) {
    // 创建RN根视图
    mReactRootView = createRootView();
    mReactRootView.startReactApplication(
      getReactNativeHost().getReactInstanceManager(),
      appKey,
      getLaunchOptions());
     // 将RN视图添加到Activity中
    getPlainActivity().setContentView(mReactRootView);
}

通过startReactApplication完成ReactContext初始化

// ReactRootView.java
  public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle launchOptions) {
    // 确保再UI线程运行
    UiThreadUtil.assertOnUiThread();

    // 省略非关键代码
    if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
      mReactInstanceManager.createReactContextInBackground();
    }

    // 宽高计算完成后添加布局监听
    if (mWasMeasured) {
      attachToReactInstanceManager();
    }
  }

createReactContextInBackground这个方法只会在 Application 创建时调用一次,
重新加载 JS时将会调用 recreateReactContextInBackground方法。recreateReactContextInBackground调用了recreateReactContextInBackgroundInner方法

// XReactInstanceManagerImpl.java
private void recreateReactContextInBackgroundInner() {
    UiThreadUtil.assertOnUiThread();
    // 调试模式,从服务器加载 bundle
    if (mUseDeveloperSupport && mJSMainModuleName != null) {
      // 省略代码
      return;
    }

    // 正式环境,从本地加载 bundle
    recreateReactContextInBackgroundFromBundleLoader();
  }

继续跟踪,发现启动异步任务ReactContextInitAsyncTask完成ReactContext初始化

// XReactInstanceManagerImpl.java
  private final class ReactContextInitAsyncTask extends
      AsyncTask<ReactContextInitParams, Void, Result<ReactApplicationContext>> {
    @Override
    protected void onPreExecute() {
      if (mCurrentReactContext != null) {
        tearDownReactContext(mCurrentReactContext);
        mCurrentReactContext = null;
      }
    }

    @Override
    protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) {
    // 省略代码
      try {
        JavaScriptExecutor jsExecutor = params[0].getJsExecutorFactory().create();
        return Result.of(createReactContext(jsExecutor, params[0].getJsBundleLoader()));
      } catch (Exception e) {
        return Result.of(e);
      }
    }
    // 省略代码
}

doInBackground中调用createReactContext创建ReactContext,通过第二个参数params[0].getJsBundleLoader()携带的bundle信息决定从哪里加载bundle文件

 // XReactInstanceManagerImpl.java
 private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor,
      JSBundleLoader jsBundleLoader) {
    // 省略代码
    catalystInstance.runJSBundle();

    return reactContext;
  }

runJSBundle执行了mJSBundleLoader.loadScript(CatalystInstanceImpl.this);由于mJSBundleLoader由createAssetLoader创建,所以会调用如下方法

  public 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chengyuan9160

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值