React Native Android 通信原理

  React Native (Android)内置了一个用于解析JavaScript(以下简称JS)脚本的框架,方便把Java类暴漏给JS调用,具体的使用方法参见,这篇文章就用来研究一下Java和JS的通信原理,JS是如何调用Java的。

  总体结构

当初始化阶段,Java端会把所有要暴漏的Java类的信息封装成Config传给JS,然后根据Config生成对应Java类的Javascript镜像对象,以及要暴漏的方法,在JS中调用这个镜像对象的方法就会被转发到对应的Java对象上,如下所示

JS的代码总要被解析执行,那么React是在哪里执行JS的呢?React并没有通过webview去执行JS代码,它是通过Jni调用c++代码通过Javascriptcore来执行JS的,首先来看看生成so依赖的的文件,代码在react-native/ReactAndroid/src/main/jni目录下。 (用NDK编译在Android上运行的c/c++代码,关于NDK请自行google)

其中OnLoad.cpp很关键,里面通过Jni映射了本地的方法到Java中,是Java和C++之间的桥梁。在Java中主要通过ReactBridge.java来调用C++,NativeModulesReactCallback类是C++调用Java的桥梁。

  例如以下代码,截取自OnLoad.cpp的JNI_OnLoad方法 (这个方法会在Java载入so文件的时候由Jni首先调用)

  registerNatives("com/facebook/react/bridge/JSCJavaScriptExecutor", {

  makeNativeMethod("initialize", executors::createJSCExecutor),

  });

  意思是把Java中的JSCJavaScriptExecutor类的initialize方法映射为executors::createJSCExecutor的C++方法,这样当在Java中调用initialize就会在C++中执行executors::createJSCExecutor。

  Java端初始化

在第一个Activity创建的时候开始进行整个Brdige的Java端的初始化,流程图如下

  初始化主要做几件事情

  创建JSCJavaScriptExecutor,这个是个C++包装类,会调用到C++的executors::createJSCExecutor()

  创建NativeModuleRegistry管理所有的要暴漏给JS的Java类,暴漏给JS的java类的搜集是通过ReactActivity中的getPackages实现的,详看上图

  创建ReactBridge对象,这个对象也是个C++桥梁对象,用来调用C++代码,创建过程会调用到bridge::create()方法

  创建config(包含了要暴漏的所有java类的信息,json格式),并通过bridge设置到JS环境中的__fbBatchedBridgeConfig变量,这样在JS端就可以通过这个变量来获取所有的Java类信息了,然后根据config生产对应的镜像对象。

  config格式如下:

  {

  "remoteModuleConfig": {

  "MyToastAndroid": {

  "moduleID": 14,

  "methods": {

  "show": {

  "methodID": 0,

  "type": "remote"

  }

  },

  "constants": {

  "LONG": 1,

  "SHORT": 0

  }

  },...

  }

  }

Java端还会创建一个CatalystInstanceImpl对象,这个对象用来管理所有的NativeModules以及与C++通信的桥梁ReactBrdige,类图结构如下:

  几个重要的类

  NativeModuleRegistry, 维护一个mModuleInstances数组,这个数组的顺序很重要,因为这和在JS端维护的镜像对象的数组是一致的当JS调用Java的时候实际上传递的正是在这个数组中的索引

  NativeModuleReactCallBack, C++回调Java的对象,这个对象会在创建ReactBridge的时候传递给C++,当JS调用Java的方法的时候会调用这个类的方法

  ReactBridge,调用C++的桥梁

  最后catalystInstance.runJSBundle()开启JS端的初始化流程

  JS端的初始化

和React Native iOS的JS初始化是一样的,因为Android和iOS的react是同享一份JS代码的,在react命令生成的react native工程的node_modules目录下面存放着所有JS的模块。在编译的时候会把所有的JS模块合并成一个大的JS文件。初始化就是在JS环境中执行这个文件。其中MessageQueue.js, BatchedBridge.js和NativeModules.js三个文件是关于JS bridge的。初始化流程如下图