React Native Android 源碼-起始篇章

做了2年React Native,之前也看過一些Android 方面的文章,自己也都只是看了個大概,也就是一知半解,現在想着自己看一遍,好提升一下自己。 我文筆不怎麼好,這個主要是用於自己學習記錄的。

我們都知道一個RN項目創建出來的時候Android 原生會有2個文件 一個MainActivity,一個MainApplication。現在我們來看看MainApplication做的什麼東西。

MainApplication

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    public boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }

    @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.init(this, /* native exopackage */ false);
  }
}

這個Application 會 實現一個接口 ReactApplication 

public interface ReactApplication {

  /**
   * Get the default {@link ReactNativeHost} for this app.
   */
  ReactNativeHost getReactNativeHost();
}

這個接口值生命了一個方法,很簡單。

然後我們在去看MainApplication 裏面實現了getReactNativeHost 這個方法 返回了在MainApplication中生命的 ReactNativeHost(mReactNativeHost)

ReactNativeHost

public abstract class ReactNativeHost {

  private final Application mApplication; // Application上下文對象
  private @Nullable ReactInstanceManager mReactInstanceManager; // ReactInstanceManager實例

  protected ReactNativeHost(Application application) {
    mApplication = application; // 實例化的時候將 application 傳入並持有
  }

  /**
   *獲得當前的ReactInstanceManager, 如果沒有則進行創建
   */
  public ReactInstanceManager getReactInstanceManager() {
    if (mReactInstanceManager == null) {
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START);
      mReactInstanceManager = createReactInstanceManager();
      ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END);
    }
    return mReactInstanceManager;
  }

  /**
   * 判斷當前的ReactNativeHost是否持用ReactInstanceManager實例
   */
  public boolean hasInstance() {
    return mReactInstanceManager != null;
  }

  /**
   * 銷燬當前持有的ReactInstanceManager實例
   */
  public void clear() {
    if (mReactInstanceManager != null) {
      mReactInstanceManager.destroy();
      mReactInstanceManager = null;
    }
  }

  protected ReactInstanceManager createReactInstanceManager() {
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
    // 通過Builder設計模式,來構建ReactInstanceManager實例
    ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
      .setApplication(mApplication)
      .setJSMainModulePath(getJSMainModuleName())
      .setUseDeveloperSupport(getUseDeveloperSupport())
      .setRedBoxHandler(getRedBoxHandler())
      .setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
      .setUIImplementationProvider(getUIImplementationProvider())
      .setJSIModulesPackage(getJSIModulePackage())
      .setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
    // 將 getPackages 中註冊的ReactPackage 都註冊到 ReactInstanceManager 中
    for (ReactPackage reactPackage : getPackages()) {
      builder.addPackage(reactPackage);
    }
    // 這個方法是用於 如果你的jsbundle 不是放在assets中的時候可以指定bundle加載的路徑
    String jsBundleFile = getJSBundleFile();
    if (jsBundleFile != null) {
      builder.setJSBundleFile(jsBundleFile);
    } else {   //  Assertions.assertNotNull(getBundleAssetName()) 這個方法僅僅只是判斷 getBundleAssetName() 的              返回結果是否爲null
      builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
    }
    ReactInstanceManager reactInstanceManager = builder.build();
    ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
    return reactInstanceManager; // 返回 ReactInstanceManager 實例
  }

  /**
   * Get the {@link RedBoxHandler} to send RedBox-related callbacks to.
   */
  protected @Nullable RedBoxHandler getRedBoxHandler() {
    return null;
  }

  /**
   * Get the {@link JavaScriptExecutorFactory}.  Override this to use a custom
   * Executor.
   */
  protected @Nullable JavaScriptExecutorFactory getJavaScriptExecutorFactory() {
    return null;
  }

 
  protected final Application getApplication() {
    return mApplication;
  }

  /**
   * Get the {@link UIImplementationProvider} to use. Override this method if you want to use a
   * custom UI implementation.
   *
   * Note: this is very advanced functionality, in 99% of cases you don't need to override this.
   */
  protected UIImplementationProvider getUIImplementationProvider() {
    return new UIImplementationProvider();
  }

  protected @Nullable
  JSIModulePackage getJSIModulePackage() {
    return null;
  }

  /**
   * Returns the name of the main module. Determines the URL used to fetch the JS bundle
   * from the packager server. It is only used when dev support is enabled.
   * This is the first file to be executed once the {@link ReactInstanceManager} is created.
   * e.g. "index.android"
   */
  protected String getJSMainModuleName() {
    return "index.android";
  }

  /**
   * Returns a custom path of the bundle file. This is used in cases the bundle should be loaded
   * from a custom path. By default it is loaded from Android assets, from a path specified
   * by {@link getBundleAssetName}.
   * e.g. "file://sdcard/myapp_cache/index.android.bundle"
   */
  protected @Nullable String getJSBundleFile() {
    return null;
  }

  /**
   * Returns the name of the bundle in assets. If this is null, and no file path is specified for
   * the bundle, the app will only work with {@code getUseDeveloperSupport} enabled and will
   * always try to load the JS bundle from the packager server.
   * e.g. "index.android.bundle"
   */
  protected @Nullable String getBundleAssetName() {
    return "index.android.bundle";
  }

  /**
   * Returns whether dev mode should be enabled. This enables e.g. the dev menu.
   */
  public abstract boolean getUseDeveloperSupport();

  /**
   * Returns a list of {@link ReactPackage} used by the app.
   * You'll most likely want to return at least the {@code MainReactPackage}.
   * If your app uses additional views or modules besides the default ones,
   * you'll want to include more packages here.
   */
  protected abstract List<ReactPackage> getPackages();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章