從java層看react-naive通信機(jī)制

-2趾盐,前言

最近我們公司突然開(kāi)始涉足react-native開(kāi)發(fā),老實(shí)說(shuō)小腊,我內(nèi)心是拒絕的救鲤。其一,是因?yàn)槟壳拔覍?duì)于原生開(kāi)發(fā)還不夠精通溢豆,不想突然轉(zhuǎn)向蜒简,其二是因?yàn)閞eact-native目前還沒(méi)有1.0的正式版本,仍然處于探索期不穩(wěn)定漩仙。其三搓茬,我特么開(kāi)發(fā)react-native用的是windows啊犹赖,人家facebook的工程師開(kāi)發(fā)這玩兒用的都是mac【砺兀看在工資的份兒上峻村,我開(kāi)始探索react-native。

-1锡凝,解釋說(shuō)明

  • 說(shuō)實(shí)話粘昨,一開(kāi)始就上這么難的話題,我也是沒(méi)辦法窜锯。關(guān)于環(huán)境集成张肾,跑demo等等遇到的這些坑,雖然積攢了一點(diǎn)經(jīng)驗(yàn)锚扎,但是很多時(shí)候吞瞪,我是懵逼的,所以總結(jié)這些經(jīng)驗(yàn)而不說(shuō)出問(wèn)題的根源驾孔,不去探究為什么芍秆,這不是我的風(fēng)格。而通信機(jī)制則是一整套嚴(yán)肅的設(shè)計(jì)翠勉,知根知底妖啥,而且隨著對(duì)于原理的深究,以后對(duì)于問(wèn)題的根源就會(huì)更加明了(不過(guò)windows環(huán)境下還是不要立這種flag比較好)对碌。
  • 其次荆虱,作為react-native的菜鳥(niǎo),我駕馭這個(gè)問(wèn)題是有一些難度的俭缓,但是克伊,這也正好是另一種優(yōu)勢(shì),那就是华坦,我能以一個(gè)react-native的菜鳥(niǎo)的角度愿吹,去解釋Java與js的通信機(jī)制,應(yīng)該是對(duì)于剛接觸react-native的原生開(kāi)發(fā)的工程師更加友好惜姐。
  • 最后犁跪,我在探究這個(gè)問(wèn)題的過(guò)程中,找到了很多很棒的博文歹袁,比如其實(shí)沒(méi)那么復(fù)雜坷衍!探究react-native通信機(jī)制等,對(duì)于這些前輩,我只有獻(xiàn)上自己的膝蓋条舔。 我目前用的RN的最新版本枫耳,而他們的版本應(yīng)該是有點(diǎn)老,因此代碼其實(shí)跟上面的作者分析有出入孟抗。

0迁杨,鋪墊

首先我們要明白以下幾點(diǎn):

  • 在react-native中的通信钻心,主要是Java與JavaScript之間的通信,而實(shí)際上铅协,Java與Js之間是根本沒(méi)辦法直接對(duì)話的捷沸,別看他們看起來(lái)好像是親戚,實(shí)際上他們的關(guān)系就相當(dāng)于雷鋒和雷峰塔的關(guān)系
  • 那么Java和Js之間想要能聽(tīng)懂對(duì)方的話狐史,有兩個(gè)必備條件:
    • 雙方的信息要能夠傳達(dá)到對(duì)方那里去痒给,就是,先不管聽(tīng)不聽(tīng)的懂 骏全,你首先要把話傳過(guò)去
    • 信息傳達(dá)前需要經(jīng)過(guò)翻譯苍柏,才能被接受方正確理解。
  • 第一個(gè)條件的解決方案是通過(guò)C++來(lái)做這個(gè)傳話筒姜贡,Java通過(guò)JNI來(lái)call到c++層序仙,然后c++層再把信息傳到j(luò)s,反之亦然鲁豪;第二個(gè)條件的解決方案就是通過(guò)在初始化的時(shí)候構(gòu)造兩本“詞典”,約定好以后說(shuō)話只說(shuō)對(duì)方的“詞典”上的單詞律秃。

所以我們的問(wèn)題其實(shí)只有兩點(diǎn):那就是集中精力觀察“詞典”是怎么傳遞到雙方手里的爬橡,以及兩方是怎么傳遞數(shù)據(jù)的

1棒动,開(kāi)篇

1.1糙申,Java傳遞“詞典”

首先,對(duì)于詞典還是正確解釋一下船惨,它是某種config柜裸,某種配置文件,每次Java層收到j(luò)s層傳來(lái)的的信息粱锐,都會(huì)讀取這個(gè)文件疙挺,然后才能理解Java層的意思。Java層也是一樣怜浅。他們對(duì)應(yīng)RN的代碼的類分別是:NativeModuleRegistry和JavaScriptModuleRegistry

初始化的開(kāi)端源自ReactActivity铐然,這是react-native中的類,它的onCreate()方法中是這么做的:

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
      // Get permission to show redbox in dev builds.
      if (!Settings.canDrawOverlays(this)) {
        Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
        startActivity(serviceIntent);
        FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
        Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
      }
    }

    mReactRootView = createRootView();
    //這是最重要的一步
    mReactRootView.startReactApplication(
      getReactNativeHost().getReactInstanceManager(),
      getMainComponentName(),
      getLaunchOptions());
    setContentView(mReactRootView);
    mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
  }

mRootView是一個(gè)layout,繼承自FrameLayout,一切的js渲染從這個(gè)Layout上開(kāi)始恶座,它的startReactApplication()方法如下:

  public void startReactApplication(
      ReactInstanceManager reactInstanceManager,
      String moduleName,
      @Nullable Bundle launchOptions) {
    UiThreadUtil.assertOnUiThread();

    // TODO(6788889): Use POJO instead of bundle here, apparently we can't just use WritableMap
    // here as it may be deallocated in native after passing via JNI bridge, but we want to reuse
    // it in the case of re-creating the catalyst instance
    Assertions.assertCondition(
        mReactInstanceManager == null,
        "This root view has already been attached to a catalyst instance manager");

    mReactInstanceManager = reactInstanceManager;
    mJSModuleName = moduleName;
    mLaunchOptions = launchOptions;

    //這是關(guān)鍵
    if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
      mReactInstanceManager.createReactContextInBackground();
    }

    // We need to wait for the initial onMeasure, if this view has not yet been measured, we set which
    // will make this view startReactApplication itself to instance manager once onMeasure is called.
    if (mWasMeasured) {
      attachToReactInstanceManager();
    }
  }

這里有一個(gè)ReactInstanceManager,它的作用就是管理CatalystInstance的實(shí)例搀暑,CatalystInstance是什么?這是一個(gè)上層抽象的調(diào)用接口)跨琳,Java和Js都可以通過(guò)這個(gè)去調(diào)用對(duì)方自点,當(dāng)然,那兩個(gè)類都是抽象的脉让,實(shí)際上都是通過(guò)它們的XXXXImpl類來(lái)實(shí)現(xiàn)具體的功能桂敛。

那么我們接著往下功炮,注意我們的目的:了解初始化時(shí)如何傳遞那兩本“詞典”的,mReactInstanceManager.createReactContextInBackground();這個(gè)方法就直接調(diào)用到了它的實(shí)現(xiàn)類:XReactInstanceManagerImpl中的createReactContextInBackground然后接下來(lái)的流程就是:

createReactContextInBackground()------> recreateReactContextInBackgroundInner(); -------> recreateReactContextInBackgroundFromBundleLoader(); ---------> recreateReactContextInBackground() ;

到了recreateReactContextInBackground()這個(gè)方法大概是這樣的:


  private void recreateReactContextInBackground(
      JavaScriptExecutor.Factory jsExecutorFactory,
      JSBundleLoader jsBundleLoader) {
    UiThreadUtil.assertOnUiThread();

    //構(gòu)造參數(shù)
    ReactContextInitParams initParams =
        new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
    if (mReactContextInitAsyncTask == null) {
      // No background task to create react context is currently running, create and execute one.
      //執(zhí)行了一個(gè)AsyncTask.......
      mReactContextInitAsyncTask = new ReactContextInitAsyncTask();
      mReactContextInitAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, initParams);
    } else {
      // Background task is currently running, queue up most recent init params to recreate context
      // once task completes.
      mPendingReactContextInitParams = initParams;
    }
  }
  

好我們接下來(lái)看這個(gè)線程內(nèi)部的細(xì)節(jié),重點(diǎn)看doInBackground()這個(gè)方法:

 @Override
    protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) {
      // TODO(t11687218): Look over all threading
      // Default priority is Process.THREAD_PRIORITY_BACKGROUND which means we'll be put in a cgroup
      // that only has access to a small fraction of CPU time. The priority will be reset after
      // this task finishes: https://android.googlesource.com/platform/frameworks/base/+/
      d630f105e8bc0021541aacb4dc6498a49048ecea/core/java/android/os/AsyncTask.java#256
      Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);

      Assertions.assertCondition(params != null && params.length > 0 && params[0] != null);
      try {
        JavaScriptExecutor jsExecutor = params[0].getJsExecutorFactory().create();
        
        //createReactContext()這個(gè)方法被執(zhí)行
        return Result.of(createReactContext(jsExecutor, params[0].getJsBundleLoader()));
      } catch (Exception e) {
        // Pass exception to onPostExecute() so it can be handled on the main thread
        return Result.of(e);
      }
    }

接下去看createReactContext(jsExecutor, params[0].getJsBundleLoader())這個(gè)方法:

/**
   * @return instance of {@link ReactContext} configured a {@link CatalystInstance} set
   */
  private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor,
      JSBundleLoader jsBundleLoader) {
    FLog.i(ReactConstants.TAG, "Creating react context.");
    ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);
    mSourceUrl = jsBundleLoader.getSourceUrl();
    
    //你瞧埠啃,之前提到的兩本“詞典”死宣,他們的Builder已經(jīng)露面了。
    NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder();
    JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder();

    final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
    if (mUseDeveloperSupport) {
      reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
    }

    ReactMarker.logMarker(PROCESS_PACKAGES_START);
    Systrace.beginSection(
        TRACE_TAG_REACT_JAVA_BRIDGE,
        "createAndProcessCoreModulesPackage");
    try {
    
    //CoreModulesPackage里面定義了RN框架核心的一些Java和JS的module
    //通過(guò)processPackage()方法寫(xiě)入到兩本“詞典”的Builder中
      CoreModulesPackage coreModulesPackage =
          new CoreModulesPackage(this, mBackBtnHandler, mUIImplementationProvider);
          
      processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
    }

    // TODO(6818138): Solve use-case of native/js modules overriding
    //這里是開(kāi)發(fā)者自己定義或封裝的一些組件或者事件的package
    for (ReactPackage reactPackage : mPackages) {
      Systrace.beginSection(
          TRACE_TAG_REACT_JAVA_BRIDGE,
          "createAndProcessCustomReactPackage");
      try {
        processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
      } finally {
        Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      }
    }
    ReactMarker.logMarker(PROCESS_PACKAGES_END);

    ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START);
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry");
    NativeModuleRegistry nativeModuleRegistry;
    try {
        //好了碴开,創(chuàng)建了用于翻譯Java端的“詞典”
       nativeModuleRegistry = nativeRegistryBuilder.build();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);
    }

    NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
        ? mNativeModuleCallExceptionHandler
        : mDevSupportManager;
    CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
        .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
        .setJSExecutor(jsExecutor)
        .setRegistry(nativeModuleRegistry)
        //創(chuàng)建了用于翻譯JS端的“詞典”
        .setJSModuleRegistry(jsModulesBuilder.build())
        .setJSBundleLoader(jsBundleLoader)
        .setNativeModuleCallExceptionHandler(exceptionHandler);
    
    //到目前為止毅该。兩本“詞典”都已經(jīng)創(chuàng)建完畢,而且全部都在CatalystInstance這個(gè)類的**實(shí)現(xiàn)類的Builder中**潦牛,此時(shí)你可以回憶一下整個(gè)過(guò)程眶掌,理清一下思路。
    
    ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
    // CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
    final CatalystInstance catalystInstance;
    try {
      //這個(gè)Build()很關(guān)鍵巴碗,它用實(shí)現(xiàn)類的Builder創(chuàng)建了一個(gè)CatalystInstance類朴爬。
      catalystInstance = catalystInstanceBuilder.build();
    } finally {
      Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
      ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
    }

    if (mBridgeIdleDebugListener != null) {
      catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
    }

    ReactMarker.logMarker(RUN_JS_BUNDLE_START);
    try {
      catalystInstance.getReactQueueConfiguration().getJSQueueThread().callOnQueue(
        new Callable<Void>() {
          @Override
          public Void call() throws Exception {
            reactContext.initializeWithInstance(catalystInstance);

            Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle");
            try {
                //在這里就運(yùn)行js代碼說(shuō)明至少在這個(gè)方法之前,“詞典”應(yīng)該傳過(guò)去了
                //于是我們刻印回去聚焦到catalystInstance = catalystInstanceBuilder.build();這段代碼
              catalystInstance.runJSBundle();
            } finally {
              Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
              ReactMarker.logMarker(RUN_JS_BUNDLE_END);
            }
            return null;
          }
        }).get();
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    } catch (ExecutionException e) {
      if (e.getCause() instanceof RuntimeException) {
        throw (RuntimeException) e.getCause();
      } else {
        throw new RuntimeException(e);
      }
    }

    return reactContext;
  }
  
  //將package中的關(guān)于Java和js的東西分別添加到兩本“詞典”的builder中
   private void processPackage(
      ReactPackage reactPackage,
      ReactApplicationContext reactContext,
      NativeModuleRegistry.Builder nativeRegistryBuilder,
      JavaScriptModuleRegistry.Builder jsModulesBuilder) {
    for (NativeModule nativeModule : reactPackage.createNativeModules(reactContext)) {
      nativeRegistryBuilder.add(nativeModule);
    }
    for (Class<? extends JavaScriptModule> jsModuleClass : reactPackage.createJSModules()) {
      jsModulesBuilder.add(jsModuleClass);
    }
  }

catalystInstanceBuilder.build()這段代碼具體實(shí)現(xiàn)如下:

    public CatalystInstanceImpl build() {
      return new CatalystInstanceImpl(
          Assertions.assertNotNull(mReactQueueConfigurationSpec),
          Assertions.assertNotNull(mJSExecutor),
          Assertions.assertNotNull(mRegistry),
          Assertions.assertNotNull(mJSModuleRegistry),
          Assertions.assertNotNull(mJSBundleLoader),
          Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
    }

這個(gè)方法的作用就是直接new了一個(gè)CatalystInstanceImpl類橡淆,那么我們接下去看CatalystInstanceImpl類的構(gòu)造方法:

 private CatalystInstanceImpl(
      final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,
      final JavaScriptExecutor jsExecutor,
      final NativeModuleRegistry registry,
      final JavaScriptModuleRegistry jsModuleRegistry,
      final JSBundleLoader jsBundleLoader,
      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
    FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
    mHybridData = initHybrid();

    mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
        ReactQueueConfigurationSpec,
        new NativeExceptionHandler());
    mBridgeIdleListeners = new CopyOnWriteArrayList<>();
    //這個(gè)就是Java層要傳遞給Js層的“詞典”
    mJavaRegistry = registry;
    mJSModuleRegistry = jsModuleRegistry;
    mJSBundleLoader = jsBundleLoader;
    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
    mTraceListener = new JSProfilerTraceListener(this);
    
    //在這個(gè)方法里召噩,就把Java暴露給Js的詞典傳了進(jìn)去
    initializeBridge(
      new BridgeCallback(this),
      jsExecutor,
      mReactQueueConfiguration.getJSQueueThread(),
      mReactQueueConfiguration.getNativeModulesQueueThread(),
      //getModuleRegistryHolder()這個(gè)方法不過(guò)是一種holder,對(duì)“詞典”做了一些封裝。
      mJavaRegistry.getModuleRegistryHolder(this));
    mMainExecutorToken = getMainExecutorToken();
  }
  
  //你瞧逸爵,native方法具滴,直接call到C++層,接下來(lái)师倔,由C++層通過(guò)各種折騰构韵,然后生成某種配置文件,轉(zhuǎn)發(fā)到Js端
   private native void initializeBridge(ReactCallback callback,
                                       JavaScriptExecutor jsExecutor,
                                       MessageQueueThread jsQueue,
                                       MessageQueueThread moduleQueue,
                                       ModuleRegistryHolder registryHolder);

好了趋艘,關(guān)于“詞典”是如何傳遞過(guò)去的疲恢,就解釋到這里,雖然C++層可能有更多操作瓷胧,但是目的就是一個(gè)显拳,把Java類轉(zhuǎn)化成一個(gè)JS讀得懂的格式的文件。
那么我們接下來(lái)看看C++是如何做好傳聲筒的

1.2抖单,數(shù)據(jù)傳遞過(guò)程

初始化完成之后萎攒,Java端和Js端都有了“詞典”,就可把自己的意圖翻譯成對(duì)方能聽(tīng)得懂的話了矛绘,這個(gè)時(shí)候交流就會(huì)暢通了耍休。

1.2.1,Java --> Js

這個(gè)問(wèn)題首先Java層應(yīng)該做的是找到那本Js的詞典货矮,所以我們應(yīng)該尋找Java層是在哪里調(diào)用到了JSModuleRegistry這個(gè)類的羊精,

讓我們退回到ReactContextInitAsyncTask的doInBackground方法中,在詞典傳遞完畢之后,這個(gè)方法基本執(zhí)行完畢喧锦,接下來(lái)是

  @Override
    protected void onPostExecute(Result<ReactApplicationContext> result) {
      try {
        setupReactContext(result.get());
      } catch (Exception e) {
        mDevSupportManager.handleException(e);
      } finally {
        mReactContextInitAsyncTask = null;
      }

      // Handle enqueued request to re-initialize react context.
      if (mPendingReactContextInitParams != null) {
        recreateReactContextInBackground(
            mPendingReactContextInitParams.getJsExecutorFactory(),
            mPendingReactContextInitParams.getJsBundleLoader());
        mPendingReactContextInitParams = null;
      }
    }

setupReactContext(result.get())這個(gè)方法,然后這個(gè)方法又會(huì)調(diào)用attachMeasuredRootViewToInstance()方法:

 private void attachMeasuredRootViewToInstance(
      ReactRootView rootView,
      CatalystInstance catalystInstance) {
    Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachMeasuredRootViewToInstance");
    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);
    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);
    
    //在這里读规,Java找到了那本Js的“詞典”,然后runApplication
    catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
    Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
  }

其實(shí)catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams)這段代碼比較復(fù)雜燃少,首先getJSModule方法具體實(shí)現(xiàn)在catalystInstanceImpl中束亏,然后會(huì)調(diào)用到mJSModuleRegistry.getJavaScriptModule(this, executorToken, jsInterface)中,代碼如下:

  public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
    CatalystInstance instance,
    ExecutorToken executorToken,
    Class<T> moduleInterface) {
    HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> instancesForContext =
        mModuleInstances.get(executorToken);
    if (instancesForContext == null) {
      instancesForContext = new HashMap<>();
      mModuleInstances.put(executorToken, instancesForContext);
    }

    JavaScriptModule module = instancesForContext.get(moduleInterface);
    if (module != null) {
      return (T) module;
    }

    JavaScriptModuleRegistration registration =
        Assertions.assertNotNull(
            mModuleRegistrations.get(moduleInterface),
            "JS module " + moduleInterface.getSimpleName() + " hasn't been registered!");
    //關(guān)鍵
    JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
        moduleInterface.getClassLoader(),
        new Class[]{moduleInterface},
        new JavaScriptModuleInvocationHandler(executorToken, instance, registration));
    instancesForContext.put(moduleInterface, interfaceProxy);
    return (T) interfaceProxy;
  }

什么動(dòng)態(tài)代理不用理他阵具,看 new JavaScriptModuleInvocationHandler(executorToken, instance, registration)這個(gè)類:

  private static class JavaScriptModuleInvocationHandler implements InvocationHandler {

    private final WeakReference<ExecutorToken> mExecutorToken;
    private final CatalystInstance mCatalystInstance;
    private final JavaScriptModuleRegistration mModuleRegistration;

    public JavaScriptModuleInvocationHandler(
        ExecutorToken executorToken,
        CatalystInstance catalystInstance,
        JavaScriptModuleRegistration moduleRegistration) {
      mExecutorToken = new WeakReference<>(executorToken);
      mCatalystInstance = catalystInstance;
      mModuleRegistration = moduleRegistration;
    }

    //關(guān)鍵
    @Override
    public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
      ExecutorToken executorToken = mExecutorToken.get();
      if (executorToken == null) {
        FLog.w(ReactConstants.TAG, "Dropping JS call, ExecutorToken went away...");
        return null;
      }
      NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
      mCatalystInstance.callFunction(
        executorToken,
        mModuleRegistration.getName(),
        method.getName(),
        jsArgs
      );
      return null;
    }
  }
}

invoke方法通過(guò)mCatalystInstance調(diào)用了callFunction()方法碍遍;不用多想,我們直接在實(shí)現(xiàn)類中去找這個(gè)方法:

@Override
  public void callFunction(
      ExecutorToken executorToken,
      final String module,
      final String method,
      final NativeArray arguments) {
    if (mDestroyed) {
      FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
      return;
    }
    if (!mAcceptCalls) {
      throw new RuntimeException("Attempt to call JS function before JS bundle is loaded.");
    }

    callJSFunction(executorToken, module, method, arguments);
  }
  
  
    private native void callJSFunction(ExecutorToken token,String module, String method,NativeArray arguments);

callFunction()方法里面調(diào)用了callJSFunction()這個(gè)本地方法阳液,然后由C++做轉(zhuǎn)發(fā)怕敬,這個(gè)本地方法傳遞的參數(shù)有token,包名,方法名帘皿,和參數(shù),

至此东跪,從Java端調(diào)用到Js端的過(guò)程,到這里可以宣告結(jié)束了鹰溜。

1.2.2虽填,js-->Java

待續(xù)。

2曹动,矯正

  • 暫無(wú)

3卤唉,總結(jié)

  • 首先這里沒(méi)有分析js端到j(luò)ava端的過(guò)程,是因?yàn)槲夷壳皩?duì)于js還不是十分熟悉仁期,目前還沒(méi)有把我能用自己的話吧這件事說(shuō)清楚,所以先挖坑竭恬,到時(shí)候一定填上跛蛋。
  • 從開(kāi)發(fā)的角度來(lái)看整個(gè)react-native兩端通信,其實(shí)我們最終是避不開(kāi)這些框架層的東西的痊硕,架構(gòu)在原生Android的系統(tǒng)之上的js無(wú)論如何都是需要和Java溝通的赊级,雖然react-native封裝了一些事件和組件,但是假如業(yè)務(wù)需要而框架沒(méi)有封裝岔绸,那你就不得不直面這種通信了理逊。
  • 還是原生開(kāi)發(fā)好,windows說(shuō)盒揉。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末晋被,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刚盈,更是在濱河造成了極大的恐慌羡洛,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藕漱,死亡現(xiàn)場(chǎng)離奇詭異欲侮,居然都是意外死亡崭闲,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門威蕉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)刁俭,“玉大人,你說(shuō)我怎么就攤上這事韧涨‰蛊荩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵氓奈,是天一觀的道長(zhǎng)翘魄。 經(jīng)常有香客問(wèn)我,道長(zhǎng)舀奶,這世上最難降的妖魔是什么暑竟? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮育勺,結(jié)果婚禮上但荤,老公的妹妹穿的比我還像新娘。我一直安慰自己涧至,他們只是感情好腹躁,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著南蓬,像睡著了一般纺非。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赘方,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天烧颖,我揣著相機(jī)與錄音,去河邊找鬼窄陡。 笑死炕淮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的跳夭。 我是一名探鬼主播涂圆,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼币叹!你這毒婦竟也來(lái)了润歉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤颈抚,失蹤者是張志新(化名)和其女友劉穎卡辰,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡九妈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年反砌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萌朱。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宴树,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晶疼,到底是詐尸還是另有隱情酒贬,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布翠霍,位于F島的核電站锭吨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏寒匙。R本人自食惡果不足惜零如,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锄弱。 院中可真熱鬧考蕾,春花似錦、人聲如沸会宪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)掸鹅。三九已至塞帐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間巍沙,已是汗流浹背壁榕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赎瞎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓颊咬,卻偏偏與公主長(zhǎng)得像务甥,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喳篇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容