博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React Native通信原理源码分析一
阅读量:7235 次
发布时间:2019-06-29

本文共 38851 字,大约阅读时间需要 129 分钟。

本篇文章已授权微信公众号 JueCode 独家发布

小伙伴们都知道在Android开发中实现Java和JS的通信可以通过WebView来实现,包括注册JSBridge或者在接口中拦截都可以。然而React Native中并没有用WebView控件的方式,而是基于WebKit内核的方式来实现Java与JS的通信,也就是Java与JS之间的通信都是通过中间层C++来实现的,今天我们来分析下Android中React Native怎么实现Java和JS之间的通信。

React Native中调用所有的行为都是从Native端发起的,用户操作直接面向的也是Native。所以这个通信模型又可以看成是Native发起会话,然后Javascript进行应答。

关于JavaScript调用Java,可以参考我的另外一篇博客:

Java要能调用到JS需要在Java层注册JS模块,先来看下JS模块的注册过程。

1.JavaScriptModule模块注册(Java层)

系统注册了一些常用的JS模块,在CoreModulesPackage的createJSModules中注册了一些系统核心的JS模块,比如AppRegistry(RN组件注册模块)/RCTEventEmitter(事件发射模块)等。

class CoreModulesPackage implements ReactPackage{  @Override  public List
createNativeModules( ReactApplicationContext catalystApplicationContext) { ...... return Arrays.
asList( new AnimationsDebugModule( catalystApplicationContext, mReactInstanceManager.getDevSupportManager().getDevSettings()), new AndroidInfoModule(), new DeviceEventManagerModule(catalystApplicationContext, mHardwareBackBtnHandler), new ExceptionsManagerModule(mReactInstanceManager.getDevSupportManager()), new Timing(catalystApplicationContext), new SourceCodeModule( mReactInstanceManager.getSourceUrl(), mReactInstanceManager.getDevSupportManager().getSourceMapUrl()), uiManagerModule, new DebugComponentOwnershipModule(catalystApplicationContext)); } @Override public List
> createJSModules() { return Arrays.asList( DeviceEventManagerModule.RCTDeviceEventEmitter.class, JSTimersExecution.class, RCTEventEmitter.class, RCTNativeAppEventEmitter.class, AppRegistry.class, com.facebook.react.bridge.Systrace.class, DebugComponentOwnershipModule.RCTDebugComponentOwnership.class); }}public interface ReactPackage { /** * @param reactContext react application context that can be used to create modules * @return list of native modules to register with the newly created catalyst instance */ List
createNativeModules(ReactApplicationContext reactContext); /** * @return list of JS modules to register with the newly created catalyst instance. * * IMPORTANT: Note that only modules that needs to be accessible from the native code should be * listed here. Also listing a native module here doesn't imply that the JS implementation of it * will be automatically included in the JS bundle. */ List
> createJSModules(); /** * @return a list of view managers that should be registered with {@link UIManagerModule} */ List
createViewManagers(ReactApplicationContext reactContext);}复制代码

以RCTEventEmitter这个JavaScriptModule模块为例来看下JS模块在Java层的实现。

所有JS层组件实现JavaScriptModule接口,比如RCTEventEmitter:

public interface RCTEventEmitter extends JavaScriptModule {  public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event);  public void receiveTouches(      String eventName,      WritableArray touches,      WritableArray changedIndices);}复制代码

可以看出来JS模块在Java层只是简单的继承JavaScriptModule,并没有具体的实现,那么问题就来了,光是一个接口是没法调用的,好像到这里就跟踪不下去了?其实可以换种思路,JS模块肯定是要在Native中注册的,我们先到ReactInstanceManagerImpl中的createReactContext方法中去看下怎么注册的。

所有的NativeModule和JSModule在ReactInstanceManagerImpl中注册

方法的代码比较多,但是逻辑不复杂,关键的几个步骤我都在代码中直接做了注释,就不多说了,这里主要分析JS模块的注册,所以我们看到JavaScriptModulesConfig中。

private ReactApplicationContext createReactContext(      JavaScriptExecutor jsExecutor,      JSBundleLoader jsBundleLoader) {    FLog.i(ReactConstants.TAG, "Creating react context.");  //Native模块    NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder();  //JS模块    JavaScriptModulesConfig.Builder jsModulesBuilder = new JavaScriptModulesConfig.Builder();  //React Context    ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);    if (mUseDeveloperSupport) {      reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);    }  //处理CoreModules---包含Native模块和JS模块    Systrace.beginSection(        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,        "createAndProcessCoreModulesPackage");    try {      CoreModulesPackage coreModulesPackage =          new CoreModulesPackage(this, mBackBtnHandler, mUIImplementationProvider);      processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);    } finally {      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);    }    // 处理用户注册的模块    for (ReactPackage reactPackage : mPackages) {      Systrace.beginSection(          Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,          "createAndProcessCustomReactPackage");      try {        processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);      } finally {        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);      }    }  //buildNativeModuleRegistry    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry");    NativeModuleRegistry nativeModuleRegistry;    try {       nativeModuleRegistry = nativeRegistryBuilder.build();    } finally {      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);    }  //buildJSModuleConfig    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildJSModuleConfig");    JavaScriptModulesConfig javaScriptModulesConfig;    try {      javaScriptModulesConfig = jsModulesBuilder.build();    } finally {      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);    }  ...    //createCatalystInstance---Java/JS/C++三方通信总管    CatalystInstanceImpl.Builder catalystInstanceBuilder = new 		CatalystInstanceImpl.Builder()        .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())        .setJSExecutor(jsExecutor)        .setRegistry(nativeModuleRegistry)        .setJSModulesConfig(javaScriptModulesConfig)        .setJSBundleLoader(jsBundleLoader)        .setNativeModuleCallExceptionHandler(exceptionHandler);    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");    CatalystInstance catalystInstance;    try {      catalystInstance = catalystInstanceBuilder.build();    } finally {      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);    }    if (mBridgeIdleDebugListener != null) {      catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);    }    reactContext.initializeWithInstance(catalystInstance);  //runJSBundle    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle");    try {      catalystInstance.runJSBundle();    } finally {      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);    }    ReactMarker.logMarker("CREATE_REACT_CONTEXT_END");    return reactContext;  }复制代码

看到JavaScriptModulesConfig,主要是对每个JavaScriptModule构造JavaScriptModuleRegistration,存放在mModules中

/** * Class stores configuration of javascript modules that can be used across the bridge */public class JavaScriptModulesConfig {  private final List
mModules; private JavaScriptModulesConfig(List
modules) { mModules = modules; } /*package*/ List
getModuleDefinitions() { return mModules; } /*package*/ void writeModuleDescriptions(JsonGenerator jg) throws IOException { jg.writeStartObject(); for (JavaScriptModuleRegistration registration : mModules) { jg.writeObjectFieldStart(registration.getName()); appendJSModuleToJSONObject(jg, registration); jg.writeEndObject(); } jg.writeEndObject(); } private void appendJSModuleToJSONObject( JsonGenerator jg, JavaScriptModuleRegistration registration) throws IOException { jg.writeObjectField("moduleID", registration.getModuleId()); jg.writeObjectFieldStart("methods"); for (Method method : registration.getMethods()) { jg.writeObjectFieldStart(method.getName()); jg.writeObjectField("methodID", registration.getMethodId(method)); jg.writeEndObject(); } jg.writeEndObject(); } public static class Builder { private int mLastJSModuleId = 0; private List
mModules = new ArrayList
(); public Builder add(Class
moduleInterfaceClass) { int moduleId = mLastJSModuleId++; mModules.add(new JavaScriptModuleRegistration(moduleId, moduleInterfaceClass)); return this; } public JavaScriptModulesConfig build() { return new JavaScriptModulesConfig(mModules); } }}复制代码
/** * Registration info for a {@link JavaScriptModule}.  	Maps its methods to method ids. */class JavaScriptModuleRegistration {  private final int mModuleId;  private final Class
mModuleInterface; private final Map
mMethodsToIds; private final Map
mMethodsToTracingNames; JavaScriptModuleRegistration(int moduleId, Class
moduleInterface) { mModuleId = moduleId; mModuleInterface = moduleInterface; mMethodsToIds = MapBuilder.newHashMap(); mMethodsToTracingNames = MapBuilder.newHashMap(); final Method[] declaredMethods = mModuleInterface.getDeclaredMethods(); Arrays.sort(declaredMethods, new Comparator
() { @Override public int compare(Method lhs, Method rhs) { return lhs.getName().compareTo(rhs.getName()); } }); // Methods are sorted by name so we can dupe check and have obvious ordering String previousName = null; for (int i = 0; i < declaredMethods.length; i++) { Method method = declaredMethods[i]; String name = method.getName(); Assertions.assertCondition( !name.equals(previousName), "Method overloading is unsupported: " + mModuleInterface.getName() + "#" + name); previousName = name; mMethodsToIds.put(method, i); mMethodsToTracingNames.put(method, "JSCall__" + getName() + "_" + method.getName()); } } ......}复制代码

到这里就有了所有的JavaScriptModules,并且都扫描存放在JavaScriptModulesConfig中,那么RN框架是怎么使用的?再回顾前面ReactInstanceManagerImpl,将JavaScriptModulesConfig用来实例化catalystInstance,这个是三方通信的中转站。

//createCatalystInstance---Java/JS/C++三方通信总管    CatalystInstanceImpl.Builder catalystInstanceBuilder = new 	CatalystInstanceImpl.Builder()        .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())        .setJSExecutor(jsExecutor)        .setRegistry(nativeModuleRegistry)        .setJSModulesConfig(javaScriptModulesConfig)        .setJSBundleLoader(jsBundleLoader)        .setNativeModuleCallExceptionHandler(exceptionHandler);Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");    CatalystInstance catalystInstance;    try {      catalystInstance = catalystInstanceBuilder.build();    } finally {      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);    }复制代码

catalystInstance是一个接口,实现类是CatalystInstanceImpl,跟到构造函数中:

private CatalystInstanceImpl(      final CatalystQueueConfigurationSpec catalystQueueConfigurationSpec,      final JavaScriptExecutor jsExecutor,      final NativeModuleRegistry registry,      final JavaScriptModulesConfig jsModulesConfig,      final JSBundleLoader jsBundleLoader,      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {   	...    mJSModuleRegistry = new JavaScriptModuleRegistry(CatalystInstanceImpl.this, jsModulesConfig);    ...  }复制代码

通过JavaScriptModulesConfig实例化JavaScriptModuleRegistry,前面分析过JavaScriptModule在Java层都是implements JavaScriptModule的接口,那么怎么去调用方法?这里就是对每个接口通过动态代理实例化一个代理对象,Java调用JS方法时统一分发到JavaScriptModuleInvocationHandler中的invoke进行处理,在invoke中其实就是调用mCatalystInstance.callFunction

很明显,接下来需要到JavaScriptModuleRegistry中看看:

/** * Class responsible for holding all the {@link JavaScriptModule}s registered to this * {@link CatalystInstance}.  Uses Java proxy objects to dispatch method calls on JavaScriptModules * to the bridge using the corresponding module and method ids so the proper function is executed in * JavaScript. *//*package*/ class JavaScriptModuleRegistry {  private final HashMap
, JavaScriptModule> mModuleInstances; public JavaScriptModuleRegistry( CatalystInstanceImpl instance, JavaScriptModulesConfig config) { mModuleInstances = new HashMap<>(); for (JavaScriptModuleRegistration registration : config.getModuleDefinitions()) { Class
moduleInterface = registration.getModuleInterface(); JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance( moduleInterface.getClassLoader(), new Class[]{moduleInterface}, new JavaScriptModuleInvocationHandler(instance, registration)); mModuleInstances.put(moduleInterface, interfaceProxy); } } public
T getJavaScriptModule(Class
moduleInterface) { return (T) Assertions.assertNotNull( mModuleInstances.get(moduleInterface), "JS module " + moduleInterface.getSimpleName() + " hasn't been registered!"); } private static class JavaScriptModuleInvocationHandler implements InvocationHandler { private final CatalystInstanceImpl mCatalystInstance; private final JavaScriptModuleRegistration mModuleRegistration; public JavaScriptModuleInvocationHandler( CatalystInstanceImpl catalystInstance, JavaScriptModuleRegistration moduleRegistration) { mCatalystInstance = catalystInstance; mModuleRegistration = moduleRegistration; } @Override public @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String tracingName = mModuleRegistration.getTracingName(method); mCatalystInstance.callFunction( mModuleRegistration.getModuleId(), mModuleRegistration.getMethodId(method), Arguments.fromJavaArgs(args), tracingName); return null; } }}复制代码

在Java调用JS模块的方法时,都会通过代理对象调用invoke方法,在invoke方法中调用CatalystInstance.callFunction,CatalystInstance是一个接口,实现类CatalystInstanceImpl,看到CatalystInstanceImpl中的callFunction:

/* package */ void callFunction(      final int moduleId,      final int methodId,      final NativeArray arguments,      final String tracingName) {    if (mDestroyed) {      FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");      return;    }    incrementPendingJSCalls();    final int traceID = mTraceID++;    Systrace.startAsyncFlow(        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,        tracingName,        traceID);    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(        new Runnable() {          @Override          public void run() {            mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();            Systrace.endAsyncFlow(                Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,                tracingName,                traceID);            if (mDestroyed) {              return;            }            Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, tracingName);            try {              Assertions.assertNotNull(mBridge).callFunction(moduleId, methodId, arguments);            } finally {              Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);            }          }        });  }复制代码

所有Java层向Javascript层的通信请求都是走的ReactBridge.callFunction

其实就是在JSQueueThread线程中调用ReactBridge的callFunction,是Native函数,到这里就从Java转到C++层了

/** * Interface to the JS execution environment and means of transport for messages Java<->JS. */@DoNotStrippublic class ReactBridge extends Countable {  /* package */ static final String REACT_NATIVE_LIB = "reactnativejni";  static {    SoLoader.loadLibrary(REACT_NATIVE_LIB);  }  private final ReactCallback mCallback;  private final JavaScriptExecutor mJSExecutor;  private final MessageQueueThread mNativeModulesQueueThread;  /**   * @param jsExecutor the JS executor to use to run JS   * @param callback the callback class used to invoke native modules   * @param nativeModulesQueueThread the MessageQueueThread the callbacks should be invoked on   */  public ReactBridge(      JavaScriptExecutor jsExecutor,      ReactCallback callback,      MessageQueueThread nativeModulesQueueThread) {    mJSExecutor = jsExecutor;    mCallback = callback;    mNativeModulesQueueThread = nativeModulesQueueThread;    initialize(jsExecutor, callback, mNativeModulesQueueThread);  }  @Override  public void dispose() {    mJSExecutor.close();    mJSExecutor.dispose();    super.dispose();  }  public void handleMemoryPressure(MemoryPressure level) {    switch (level) {      case MODERATE:        handleMemoryPressureModerate();        break;      case CRITICAL:        handleMemoryPressureCritical();        break;      default:        throw new IllegalArgumentException("Unknown level: " + level);    }  }  private native void initialize(      JavaScriptExecutor jsExecutor,      ReactCallback callback,      MessageQueueThread nativeModulesQueueThread);  /**   * All native functions are not thread safe and appropriate queues should be used   */  public native void loadScriptFromAssets(AssetManager assetManager, String assetName);  public native void loadScriptFromFile(@Nullable String fileName, @Nullable String sourceURL);  public native void callFunction(int moduleId, int methodId, NativeArray arguments);  public native void invokeCallback(int callbackID, NativeArray arguments);  public native void setGlobalVariable(String propertyName, String jsonEncodedArgument);  public native boolean supportsProfiling();  public native void startProfiler(String title);  public native void stopProfiler(String title, String filename);  private native void handleMemoryPressureModerate();  private native void handleMemoryPressureCritical();}复制代码

再回头看看ReactBridge在CatalystInstanceImpl里面的初始化,初始化会ReactBridge调用setGlobalVariable,这是个Native函数,是在C++层注册用的,先按下后面再分析组件调用过程再分析,先看看 buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig)做了什么。

private CatalystInstanceImpl(      final CatalystQueueConfigurationSpec catalystQueueConfigurationSpec,      final JavaScriptExecutor jsExecutor,      final NativeModuleRegistry registry,      final JavaScriptModulesConfig jsModulesConfig,      final JSBundleLoader jsBundleLoader,      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {	......    try {      mBridge = mCatalystQueueConfiguration.getJSQueueThread().callOnQueue(          new Callable
() { @Override public ReactBridge call() throws Exception { Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "initializeBridge"); try { return initializeBridge(jsExecutor, jsModulesConfig); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } } }).get(BRIDGE_SETUP_TIMEOUT_MS, TimeUnit.MILLISECONDS); } catch (Exception t) { throw new RuntimeException("Failed to initialize bridge", t); } } private ReactBridge initializeBridge( JavaScriptExecutor jsExecutor, JavaScriptModulesConfig jsModulesConfig) { mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread(); Assertions.assertCondition(mBridge == null, "initializeBridge should be called once"); Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactBridgeCtor"); ReactBridge bridge; try { bridge = new ReactBridge( jsExecutor, new NativeModulesReactCallback(), mCatalystQueueConfiguration.getNativeModulesQueueThread()); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "setBatchedBridgeConfig"); try { bridge.setGlobalVariable( "__fbBatchedBridgeConfig", buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig)); bridge.setGlobalVariable( "__RCTProfileIsProfiling", Systrace.isTracing(Systrace.TRACE_TAG_REACT_APPS) ? "true" : "false"); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } return bridge; }复制代码

在CatalystInstanceImpl中的实现,其实就是写一个JSON字符串,有两个字段"remoteModuleConfig"和"localModulesConfig",分别对应NativeModule(Native提供给JS调用)和JSModule(JS提供给Native调用)

private String buildModulesConfigJSONProperty(      NativeModuleRegistry nativeModuleRegistry,      JavaScriptModulesConfig jsModulesConfig) {    JsonFactory jsonFactory = new JsonFactory();    StringWriter writer = new StringWriter();    try {      JsonGenerator jg = jsonFactory.createGenerator(writer);      jg.writeStartObject();      jg.writeFieldName("remoteModuleConfig");      nativeModuleRegistry.writeModuleDescriptions(jg);      jg.writeFieldName("localModulesConfig");      jsModulesConfig.writeModuleDescriptions(jg);      jg.writeEndObject();      jg.close();    } catch (IOException ioe) {      throw new RuntimeException("Unable to serialize JavaScript module declaration", ioe);    }    return writer.getBuffer().toString();  }复制代码

再看看localModulesConfig都写入了什么,跟进去JavaScriptModulesConfig.java,就是往JSON字符创中先写入接口名、moduleID、methods(方法名、methodID)等。

/*package*/ void writeModuleDescriptions(JsonGenerator jg) throws IOException {    jg.writeStartObject();    for (JavaScriptModuleRegistration registration : mModules) {      jg.writeObjectFieldStart(registration.getName());      appendJSModuleToJSONObject(jg, registration);      jg.writeEndObject();    }    jg.writeEndObject();  }  private void appendJSModuleToJSONObject(      JsonGenerator jg,      JavaScriptModuleRegistration registration) throws IOException {    jg.writeObjectField("moduleID", registration.getModuleId());    jg.writeObjectFieldStart("methods");    for (Method method : registration.getMethods()) {      jg.writeObjectFieldStart(method.getName());      jg.writeObjectField("methodID", registration.getMethodId(method));      jg.writeEndObject();    }    jg.writeEndObject();  }复制代码

initializeBridge->setGlobalVariable->buildModulesConfigJSONProperty->writeModuleDescriptions

整个过程作用是将所有JavaScriptModule的信息生成JSON字符串预先保存到Bridge中, 通过methodID标识作为key存入JSON生成器中,用来最终生成JSON字符串:

其中setGlobalVariable也是Native函数,buildModulesConfigJSONProperty把所有的JavaScriptModule模块以moduleID+methodID形式生成JSON字符串,通过setGlobalVariable把JSON字符串预先存入了ReactBridge

bridge.setGlobalVariable(          "__fbBatchedBridgeConfig",          buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));复制代码

Java层的调用就是上面的过程,最后通过JNI调用到C++层,接下来进入这一层看看。

2.ReactBridge实现

通信模型图中要调用WebKit的实现,少不了Bridge这个桥梁,因为Java是不能直接调用WebKit,但是可以Java通过JNIJNI再调用WebKit

JNI入口react/jni/OnLoad.cpp,通过RegisterNatives方式注册的,JNI_OnLoad里面注册了setGlobalVariablecallFunctionnative本地方法

//jni/react/jni/OnLoad.cppnamespace bridge {  ......static void setGlobalVariable(JNIEnv* env, jobject obj, jstring propName, jstring jsonValue) {  auto bridge = extractRefPtr
(env, obj); bridge->setGlobalVariable(fromJString(env, propName), fromJString(env, jsonValue));} ...} // namespace bridgeextern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { return initialize(vm, [] { // get the current env JNIEnv* env = Environment::current(); registerNatives("com/facebook/react/bridge/ReadableNativeMap$ReadableNativeMapKeySetIterator", { ...... registerNatives("com/facebook/react/bridge/ReactBridge", { makeNativeMethod("initialize", "(Lcom/facebook/react/bridge/JavaScriptExecutor;Lcom/facebook/react/bridge/ReactCallback;Lcom/facebook/react/bridge/queue/MessageQueueThread;)V", bridge::create), makeNativeMethod( "loadScriptFromAssets", "(Landroid/content/res/AssetManager;Ljava/lang/String;)V", bridge::loadScriptFromAssets), makeNativeMethod("loadScriptFromFile", bridge::loadScriptFromFile), makeNativeMethod("callFunction", bridge::callFunction), makeNativeMethod("invokeCallback", bridge::invokeCallback), makeNativeMethod("setGlobalVariable", bridge::setGlobalVariable), makeNativeMethod("supportsProfiling", bridge::supportsProfiling), makeNativeMethod("startProfiler", bridge::startProfiler), makeNativeMethod("stopProfiler", bridge::stopProfiler), makeNativeMethod("handleMemoryPressureModerate", bridge::handleMemoryPressureModerate), makeNativeMethod("handleMemoryPressureCritical", bridge::handleMemoryPressureCritical), });}复制代码

可以看到setGlobalVariable真正调用的是Bridge.cpp里面的setGlobalVariable:

//jni/react/Bridge.hclass JSThreadState;class Bridge : public Countable {public:  typedef std::function
, bool isEndOfBatch)> Callback; Bridge(const RefPtr
& jsExecutorFactory, Callback callback); virtual ~Bridge(); /** * Flush get the next queue of changes. */ void flush(); /** * Executes a function with the module ID and method ID and any additional * arguments in JS. */ void callFunction(const double moduleId, const double methodId, const folly::dynamic& args); /** * Invokes a callback with the cbID, and optional additional arguments in JS. */ void invokeCallback(const double callbackId, const folly::dynamic& args); void executeApplicationScript(const std::string& script, const std::string& sourceURL); void setGlobalVariable(const std::string& propName, const std::string& jsonValue); bool supportsProfiling(); void startProfiler(const std::string& title); void stopProfiler(const std::string& title, const std::string& filename); void handleMemoryPressureModerate(); void handleMemoryPressureCritical();private: Callback m_callback; std::unique_ptr
m_threadState; // This is used to avoid a race condition where a proxyCallback gets queued after ~Bridge(), // on the same thread. In that case, the callback will try to run the task on m_callback which // will have been destroyed within ~Bridge(), thus causing a SIGSEGV. std::shared_ptr
m_destroyed;};void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) { m_threadState->setGlobalVariable(propName, jsonValue);}复制代码

最终调用的是JSThreadState里面的setGlobalVariable:

//jni/react/Bridge.cppclass JSThreadState {public:  JSThreadState(const RefPtr
& jsExecutorFactory, Bridge::Callback&& callback) : m_callback(callback) { m_jsExecutor = jsExecutorFactory->createJSExecutor([this, callback] (std::string queueJSON, bool isEndOfBatch) { m_callback(parseMethodCalls(queueJSON), false /* = isEndOfBatch */); }); } void setGlobalVariable(const std::string& propName, const std::string& jsonValue) { m_jsExecutor->setGlobalVariable(propName, jsonValue); }private: std::unique_ptr
m_jsExecutor; Bridge::Callback m_callback;};复制代码

最终调用JSExecutor里面setGlobalVariable:

//jni/react/JSCExecutor.hclass JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {public:  /**   * Should be invoked from the JS thread.   */  explicit JSCExecutor(FlushImmediateCallback flushImmediateCallback);  ~JSCExecutor() override;  virtual void executeApplicationScript(    const std::string& script,    const std::string& sourceURL) override;  virtual std::string flush() override;  virtual std::string callFunction(    const double moduleId,    const double methodId,    const folly::dynamic& arguments) override;  virtual std::string invokeCallback(    const double callbackId,    const folly::dynamic& arguments) override;  virtual void setGlobalVariable(    const std::string& propName,    const std::string& jsonValue) override;  virtual bool supportsProfiling() override;  virtual void startProfiler(const std::string &titleString) override;  virtual void stopProfiler(const std::string &titleString, const std::string &filename) override;  virtual void handleMemoryPressureModerate() override;  virtual void handleMemoryPressureCritical() override;  void flushQueueImmediate(std::string queueJSON);  void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);  virtual void onMessageReceived(int workerId, const std::string& message) override;  virtual JSGlobalContextRef getContext() override;  virtual std::shared_ptr
getMessageQueueThread() override;};} }//jni/react/JSCExecutor.cppvoid JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) { auto globalObject = JSContextGetGlobalObject(m_context); String jsPropertyName(propName.c_str()); String jsValueJSON(jsonValue.c_str()); auto valueToInject = JSValueMakeFromJSONString(m_context, jsValueJSON); JSObjectSetProperty(m_context, globalObject, jsPropertyName, valueToInject, 0, NULL);}复制代码

从JSCExecutor::setGlobalVariable中可以看到java层传过来的JSON串(包含Native Modules和JS Modules)和属性名(__fbBatchedBridgeConfig),赋值给全局变量globalObject,这个全局变量通过JSContextGetGlobalObject获取到,在JSCExecutor.h头文件中:

#include 
#include
#include
#include "Executor.h"#include "JSCHelpers.h"#include "JSCWebWorker.h"复制代码

JavaScriptCore/JSContextRef.h是Webkit这个库中的文件,在ReactAndroid下的build.gradle中有索引这个库,到build.gradle中看看:

//ReactAndroid/build.gradletask downloadJSCHeaders(type: Download) {    def jscAPIBaseURL = 'https://svn.webkit.org/repository/webkit/!svn/bc/174650/trunk/Source/JavaScriptCore/API/'    def jscHeaderFiles = ['JSBase.h', 'JSContextRef.h', 'JSObjectRef.h', 'JSRetainPtr.h', 'JSStringRef.h', 'JSValueRef.h', 'WebKitAvailability.h']    def output = new File(downloadsDir, 'jsc')    output.mkdirs()    src(jscHeaderFiles.collect { headerName -> "$jscAPIBaseURL$headerName" })    onlyIfNewer true    overwrite false    dest output}复制代码

打开jscAPIBaseURL这个url可以找到JSContextRef.h头文件:

//JavaScriptCore/API/JSContextRef.h.../*!@function@abstract Gets the global object of a JavaScript execution context.@param ctx The JSContext whose global object you want to get.@result ctx's global object.*/JS_EXPORT JSObjectRef JSContextGetGlobalObject(JSContextRef ctx);...复制代码

JSCExecutor::setGlobalVariable最后给JS的全局变量设置一个属性__fbBatchedBridgeConfig,这个属性的值就是JavaScriptModule,Java调用JS的时候从属性中查找,看下callFunction:

//jni/react/JSCExecutor.cppstd::string JSCExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {  // TODO:  Make this a first class function instead of evaling. #9317773  std::vector
call{ (double) moduleId, (double) methodId, std::move(arguments), }; return executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));}static std::string executeJSCallWithJSC( JSGlobalContextRef ctx, const std::string& methodName, const std::vector
& arguments) { #ifdef WITH_FBSYSTRACE FbSystraceSection s( TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.executeJSCall", "method", methodName); #endif // Evaluate script with JSC folly::dynamic jsonArgs(arguments.begin(), arguments.end()); auto js = folly::to
( "__fbBatchedBridge.", methodName, ".apply(null, ", folly::toJson(jsonArgs), ")"); auto result = evaluateScript(ctx, String(js.c_str()), nullptr); return Value(ctx, result).toJSONString();}复制代码

最终以

__fbBatchedBridge.callFunctionReturnFlushedQueue.apply(null,{moduleId, methodId, arguments})的形式拼接一个applyJavascript执行语句,最后调用jni/react/JSCHelpers.cppevaluateScript的来执行这个语句,完成BridgeJavascript的调用,JSCHelpersWebKit的一些API做了封装,它负责最终调用WebKit

//jni/react/JSCHelpers.hnamespace facebook {namespace react {void installGlobalFunction(    JSGlobalContextRef ctx,    const char* name,    JSObjectCallAsFunctionCallback callback);JSValueRef makeJSCException(    JSContextRef ctx,    const char* exception_text);JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source);} }复制代码

Bridge层的调用过程: OnLoad.cpp->Bridge.cpp->JSCExecutor.cpp->JSCHelpers.cpp->WebKit

3.JavaScript层实现

Javascript的通信,实质上是Weikit执行Javascript语句,调用流程是Bridge->WebKit->JavascriptWebKit中提供了许多与Javascript通信的API,比如evaluateScriptJSContextGetGlobalObjectJSObjectSetProperty等。

回顾一下前面JSCExecutor::setGlobalVariable:

//jni/react/JSCExecutor.cppvoid JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {  auto globalObject = JSContextGetGlobalObject(m_context);  String jsPropertyName(propName.c_str());  String jsValueJSON(jsonValue.c_str());  auto valueToInject = JSValueMakeFromJSONString(m_context, jsValueJSON);  JSObjectSetProperty(m_context, globalObject, jsPropertyName, valueToInject, 0, NULL);}复制代码

所有JavaScriptModule信息是调用的setGlobalVariable方法生成一张映射表,这张映射表最终肯定是要保存在Javascript层的,JSContextGetGlobalObjectWeiKit的方法,其目的是获取Global全局对象,jsPropertyName方法字面意思就是Javascript对象的属性名,参数propName是从Java层传递过来的,在CatalystInstanceImpl.java类中可以印证这一点,具体值有两个:__fbBatchedBridgeConfig和**__RCTProfileIsProfiling**.

//com/facebook/react/bridge/CatalystInstanceImplbridge.setGlobalVariable(          "__fbBatchedBridgeConfig",          buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));复制代码

翻译成JS语句大概是:

global.__fbBatchedBridgeConfig = jsonValue;复制代码

由于**__fbBatchedBridgeConfig对象是被直接定义成Global全局对象的属性,就可以直接调用了,类似于window对象,__fbBatchedBridgeConfig对象里又有两个属性:remoteModuleConfiglocalModulesConfig**,分别对应Java模块和JS模块。

到JS层的BatchedBridge.js:

//Libraries/BatchedBridge/BatchedBridge.jsconst MessageQueue = require('MessageQueue');const BatchedBridge = new MessageQueue(  __fbBatchedBridgeConfig.remoteModuleConfig,	//Native(Java)模块  __fbBatchedBridgeConfig.localModulesConfig,	//JS模块);// TODO: Move these around to solve the cycle in a cleaner way.const Systrace = require('Systrace');const JSTimersExecution = require('JSTimersExecution');BatchedBridge.registerCallableModule('Systrace', Systrace);BatchedBridge.registerCallableModule('JSTimersExecution', JSTimersExecution);if (__DEV__) {  BatchedBridge.registerCallableModule('HMRClient', require('HMRClient'));}Object.defineProperty(global, '__fbBatchedBridge', { value: BatchedBridge });module.exports = BatchedBridge;复制代码

1.在全局变量global中定义fbBatchedBridge,在前面JSCExecutor::callFunction中调用JS语句的形式是fbBatchedBridge.callFunctionReturnFlushedQueue.apply(null,{moduleId, methodId, arguments})

2.BatchedBridge=new MessageQueue

所以再继续跟到MessageQueue.js中:

class MessageQueue {  constructor(remoteModules, localModules) {    this.RemoteModules = {};    this._callableModules = {};    this._queue = [[], [], [], 0];    this._moduleTable = {};    this._methodTable = {};    this._callbacks = [];    this._callbackID = 0;    this._callID = 0;    this._lastFlush = 0;    this._eventLoopStartTime = new Date().getTime();    [      'invokeCallbackAndReturnFlushedQueue',      'callFunctionReturnFlushedQueue',      'flushedQueue',    ].forEach((fn) => this[fn] = this[fn].bind(this));    let modulesConfig = this._genModulesConfig(remoteModules);    this._genModules(modulesConfig);    localModules && this._genLookupTables(      this._genModulesConfig(localModules),this._moduleTable, this._methodTable    );    this._debugInfo = {};    this._remoteModuleTable = {};    this._remoteMethodTable = {};    this._genLookupTables(      modulesConfig, this._remoteModuleTable, this._remoteMethodTable    );  }  /**   * Public APIs   */  callFunctionReturnFlushedQueue(module, method, args) {    guard(() => {      this.__callFunction(module, method, args);      this.__callImmediates();    });    return this.flushedQueue();  }    _genLookupTables(modulesConfig, moduleTable, methodTable) {    modulesConfig.forEach((config, moduleID) => {      this._genLookup(config, moduleID, moduleTable, methodTable);    });  }  _genLookup(config, moduleID, moduleTable, methodTable) {    if (!config) {      return;    }    let moduleName, methods;    if (moduleHasConstants(config)) {      [moduleName, , methods] = config;    } else {      [moduleName, methods] = config;    }    moduleTable[moduleID] = moduleName;    methodTable[moduleID] = Object.assign({}, methods);  }}module.exports = MessageQueue;复制代码

把remoteModules, localModules传进了**_genLookupTables的方法里,同时还有两个参数_moduleTable**、_methodTable,就是我们找的映射表了,一张module映射表,一张method映射表

再回顾下前面Java调用JS的语句形式:__fbBatchedBridge.callFunctionReturnFlushedQueue.apply(null,{moduleId, methodId, arguments})

class MessageQueue { constructor(remoteModules, localModules) {   this.RemoteModules = {};   this._callableModules = {};   this._queue = [[], [], [], 0];   this._moduleTable = {};   this._methodTable = {};   this._callbacks = [];   this._callbackID = 0;   this._callID = 0;   this._lastFlush = 0;   this._eventLoopStartTime = new Date().getTime();   [     'invokeCallbackAndReturnFlushedQueue',     'callFunctionReturnFlushedQueue',     'flushedQueue',   ].forEach((fn) => this[fn] = this[fn].bind(this));   let modulesConfig = this._genModulesConfig(remoteModules);   this._genModules(modulesConfig);   localModules && this._genLookupTables(     this._genModulesConfig(localModules),this._moduleTable, this._methodTable   );   this._debugInfo = {};   this._remoteModuleTable = {};   this._remoteMethodTable = {};   this._genLookupTables(     modulesConfig, this._remoteModuleTable, this._remoteMethodTable   ); } /**  * Public APIs  */ callFunctionReturnFlushedQueue(module, method, args) {   guard(() => {     this.__callFunction(module, method, args);     this.__callImmediates();   });   return this.flushedQueue(); }  _genLookupTables(modulesConfig, moduleTable, methodTable) {   modulesConfig.forEach((config, moduleID) => {     this._genLookup(config, moduleID, moduleTable, methodTable);   }); } _genLookup(config, moduleID, moduleTable, methodTable) {   if (!config) {     return;   }   let moduleName, methods;   if (moduleHasConstants(config)) {     [moduleName, , methods] = config;   } else {     [moduleName, methods] = config;   }   moduleTable[moduleID] = moduleName;   methodTable[moduleID] = Object.assign({}, methods); }}module.exports = MessageQueue;复制代码

其中有个callableModules, 它就是用来存放哪些Javascript组件是可以被调用的,正常情况下callableModules的数据和JavaScriptModules的数据(包括方法名和参数)理应是完全对应的.

看下哪些JS组件调用registerCallableModule进行方法的注册

看一下RCTEventEmitter.js:

//Libraries/BatchedBridge/BatchedBridgedModules/RCTEventEmitter.jsvar BatchedBridge = require('BatchedBridge');var ReactNativeEventEmitter = require('ReactNativeEventEmitter');BatchedBridge.registerCallableModule(  'RCTEventEmitter',  ReactNativeEventEmitter);// Completely locally implemented - no native hooks.module.exports = ReactNativeEventEmitter;复制代码

ReactNativeEventEmitter.js:

var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {  receiveEvent: function(    tag: number,    topLevelType: string,    nativeEventParam: Object  ) {    ......  },  receiveTouches: function(    eventTopLevelType: string,    touches: Array,    changedIndices: Array
) { ...... });复制代码

对比下Java层的接口表示,方法名称和参数个数是一致的

public interface RCTEventEmitter extends JavaScriptModule {  public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event);  public void receiveTouches(      String eventName,      WritableArray touches,      WritableArray changedIndices);}复制代码

继续前面__callFunction的最后一步:moduleMethods[method].apply(moduleMethods, args);调用对应模块的方法。

###4.总结 Java调用JavaScript可以总结为下面:

欢迎关注哈,

公众号: JueCode

个人在简书博客:

转载地址:http://stlfm.baihongyu.com/

你可能感兴趣的文章
越狱后的ios如何用apt-get 安装各种命令
查看>>
JDBC、JTA、Spring的事务管理
查看>>
浏览器记住密码、浏览器记住密码表单自动加载
查看>>
洛谷P1280 尼克的任务[DP]
查看>>
Tomcat利用Redis存储Session
查看>>
java常见加密方式介绍
查看>>
android 从 phonegap 到 js webview 交互
查看>>
C#回顾 –6.特性
查看>>
Spring和cxf3的整合,以maven的方式
查看>>
Apache Shiro系列三,概述 —— 10分钟入门
查看>>
servlet生命周期
查看>>
Java 网络编程
查看>>
数据库的物理结构和逻辑结构
查看>>
Hadoop MapReduce编程 API入门系列之挖掘气象数据版本3(九)
查看>>
Hadoop HDFS编程 API入门系列之合并小文件到HDFS(三)
查看>>
【MyEcplise】build workspace卡死
查看>>
基于资源的权限系统-API设计
查看>>
如何区分USB 2.0 和USB 3.0插口
查看>>
排序及重复元素去重的说明,TreeSet,HashSet
查看>>
SQLServer 维护脚本分享(05)内存(Memory)
查看>>