2019-02-19
CatalystInstanceImpl 是 React Native 中很重要的一个类。因为它横跨 Java、C++ 两侧(这在 React Native 中称为 Hybrid),所以它的创建过程有点复杂。在本文中我们一探它的创建过程。
我们先从 Java 层下手。还记得 CatalystInstanceImpl 是通过 Builder 模式构造的吗?
在整个 React Native 中只有一个地方会创建这个 Builder,即在 ReactInstanceManager 的 createReactContext 方法中。具体创建流程在之前的系列中已有讲解这里不再赘述。
在这里我们再向前进一步,ReactInstanceManager 是在哪里创建的呢?还记得在 React Native 官方文档中,如何在 Android 项目中集成 React Native 吗?
示例代码如下:
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { private ReactInstanceManager mReactInstanceManager; private ReactRootView mReactRootView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModuleName("index.android") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); mReactRootView.startReactApplication(mReactInstanceManager, "Basic", null); setContentView(mReactRootView); }
我们可以看出,一个包含 ReactRootView 的 Activity 中,只会有一个 ReactInstanceManager 实例,进而只会有一个 CatalystInstanceImpl 实例。
在这里我先卖个关子。CatalystInstanceImpl 在 C++ 侧对应的类是 ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h。
我们可以在 React Native 的 C++ 代码中搜索,看看哪里有创建这个实例的地方?
我们会发现,就算把代码都找遍了,也找不到。
奇怪了吧?这里就要说到 React Native 底层的一个 Native 依赖库,叫 fbjni,它包含一个框架,通过这个框架,我们能在 C++ 侧建立一个与 Java 侧为映射关系的类。相当于提供了一种机制,对 JVM 中的类建立一个 C++ 侧的映像。
在本文中,我们不展开讲 fbjni 的实现原理(涉及篇幅太长,等我梳理好后会放在后面的文章中),而是把它当做一个黑盒,主要精力放在这个问题:
我们先来看 CatalystInstanceImpl 类的继承关系:
class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> { public: static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/CatalystInstanceImpl;"; static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>); ~CatalystInstanceImpl() override;
其中:
HybridClass 位于 ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/Hybrid.h。这是 fbjni 中的类。
在这里我们把 fbjni 当做黑盒,先速成一下 fbjni 的使用。
假设我们在 Java 侧有一个类叫 Foo(它的完整类名是 com.maxiee.Foo),我们想要创建一个它在 C++ 侧的映射类。
因此我们声明这样一个 C++ 类:
class Foo : public jni::HybridClass<Foo> { public: static constexpr auto kJavaDescriptor = "Lcom/maxiee/Foo"; static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>); static void registerNatives(); }
其中:
下面先看 initHybrid 实现:
jni::local_ref<Foo::jhybriddata> Foo::initHybrid(jni::alias_ref<jclass>) { return makeCxxInstance(); }
其中:
::::::<><>::::::><><:::::><>><><
跟象形文字一样这个对象是返回到 Java 层的,我们看下 Java 层的实现:
public class Foo { static { SoLoader.loadLibrary("my-lib-contains-foo"); } // C++ parts private final HybridData mHybridData; private native static HybridData initHybrid(); public Foo() { mHybridData = initHybrid(); } public destroy() { mHybridData.resetNative(); } }
其中:
最后再看 registerNatives 方法,它用于在 Native 库 OnLoad 时注册 JNI 方法:
registerHybrid({ makeNativeMethod("initHybrid", Foo::initHybrid) });
其中:
至此我们对 CatalystInstanceImpl 的 Java 侧和 C++ 侧两头怎么创建的都明了了。
我们也开始接触到 fbjni 这个库,这个库很有意思,也不容易掌握。希望我未来能够写一篇详解它的文章。