React Native的JS调用原生接口流程

328 阅读2分钟

JS调用原生接口流程

NativeModule使用流程

集成ReactContextBaseJavaModule​类,复写getName方法,该方法提供NativeModule的名称,给js直接访问。

@ReactMethod注解是将接口暴露给js层,给js层直接调用。

通过ReactPackage的createNativeModules​方法,将NativeModule注册

NativeModule是如何被注册的

java层信息保存

public class ReactInstanceManager {
	// 省略部分代码
	private ReactApplicationContext createReactContext(
      JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
	// 省略部分代码
	 NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
	// 省略部分代码
	}
}

private NativeModuleRegistry processPackages(
      ReactApplicationContext reactContext,
      List<ReactPackage> packages,
      boolean checkAndUpdatePackageMembership) {
	// 省略部分代码
	synchronized (mPackages) {
      for (ReactPackage reactPackage : packages) {
        if (checkAndUpdatePackageMembership && mPackages.contains(reactPackage)) {
          continue;
        }
        Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createAndProcessCustomReactPackage");
        try {
          if (checkAndUpdatePackageMembership) {
            mPackages.add(reactPackage);
          }
	// 逐个处理package
          processPackage(reactPackage, nativeModuleRegistryBuilder);
        } finally {
          Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
        }
      }
    }
	// 省略部分代码
  }

private void processPackage(
      ReactPackage reactPackage, NativeModuleRegistryBuilder nativeModuleRegistryBuilder) {
// 省略部分代码
    // 通过NativeModuleRegistryBuilder来处理reactPackage
    nativeModuleRegistryBuilder.processPackage(reactPackage);
// 省略部分代码
  }

首先在RN初始化的时候,通过调用processPackages方法,来统一处理解析所有的package。

通过NativeModuleRegistryBuilder​来处理单个reactPacage

public class NativeModuleRegistryBuilder {

// 将reactPackage中的nativeModule全部取出保存到NativeModuleRegistry中
 public void processPackage(ReactPackage reactPackage) {
    // We use an iterable instead of an iterator here to ensure thread safety, and that this list
    // cannot be modified
    Iterable<ModuleHolder> moduleHolders;
    if (reactPackage instanceof LazyReactPackage) {
      moduleHolders =
          ((LazyReactPackage) reactPackage).getNativeModuleIterator(mReactApplicationContext);
    } else if (reactPackage instanceof TurboReactPackage) {
      moduleHolders =
          ((TurboReactPackage) reactPackage).getNativeModuleIterator(mReactApplicationContext);
    } else {
      moduleHolders =
          ReactPackageHelper.getNativeModuleIterator(
              reactPackage, mReactApplicationContext, mReactInstanceManager);
    }

    for (ModuleHolder moduleHolder : moduleHolders) {
      String name = moduleHolder.getName();
      if (mModules.containsKey(name)) {
        ModuleHolder existingNativeModule = mModules.get(name);
        if (!moduleHolder.getCanOverrideExistingModule()) {
          throw new IllegalStateException(
              "Native module "
                  + name
                  + " tried to override "
                  + existingNativeModule.getClassName()
                  + ". Check the getPackages() method in MainApplication.java, it might be that module is being created twice. If this was your intention, set canOverrideExistingModule=true. "
                  + "This error may also be present if the package is present only once in getPackages() but is also automatically added later during build time by autolinking. Try removing the existing entry and rebuild.");
        }
        mModules.remove(existingNativeModule);
      }
      mModules.put(name, moduleHolder);
    }
  }

public NativeModuleRegistry build() {
    return new NativeModuleRegistry(mReactApplicationContext, mModules);
  }
}

将reactPackage转换成NativeModuleRegistry

public class CatalystInstanceImpl implements CatalystInstance {
private CatalystInstanceImpl(
      final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
      final JavaScriptExecutor jsExecutor,
      final NativeModuleRegistry nativeModuleRegistry,
      final JSBundleLoader jsBundleLoader,
      JSExceptionHandler jSExceptionHandler) {
// 省略部分代码
    // 初始化nativemodules
    initializeBridge(
        new BridgeCallback(this),
        jsExecutor,
        mReactQueueConfiguration.getJSQueueThread(),
        mNativeModulesQueueThread,
        mNativeModuleRegistry.getJavaModules(this),
        mNativeModuleRegistry.getCxxModules());
  }
// 省略部分代码
}
void CatalystInstanceImpl::initializeBridge(
    jni::alias_ref<ReactCallback::javaobject> callback,
    // This executor is actually a factory holder.
    JavaScriptExecutorHolder *jseh,
    jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
    jni::alias_ref<JavaMessageQueueThread::javaobject> nativeModulesQueue,
    jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject>
        javaModules,
    jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject>
        cxxModules) {
  // 省略部分代码

  moduleRegistry_ = std::make_shared<ModuleRegistry>(buildNativeModuleList(
      std::weak_ptr<Instance>(instance_),
      javaModules,
      cxxModules,
      moduleMessageQueue_));

  instance_->initializeBridge(
      std::make_unique<JInstanceCallback>(callback, moduleMessageQueue_),
      jseh->getExecutorFactory(),
      std::make_unique<JMessageQueueThread>(jsQueue),
      moduleRegistry_);
// 省略部分代码
}

在c++层,将java层的nativemodule的信息进行保存

js调用流程

在NativeModules.js中,记录原生方法的信息,通过bridge,调用原生方法

// enqueueNativeCall具体实现在MessageQueue.js中
function genMethod(moduleID: number, methodID: number, type: MethodType) {
  let fn = null;
  if (type === 'promise') {
    fn = function promiseMethodWrapper(...args: Array<mixed>) {
      // In case we reject, capture a useful stack trace here.
      /* $FlowFixMe[class-object-subtyping] added when improving typing for
       * this parameters */
      const enqueueingFrameError: ExtendedError = new Error();
      return new Promise((resolve, reject) => {
        BatchedBridge.enqueueNativeCall(
          moduleID,
          methodID,
          args,
          data => resolve(data),
          errorData =>
            reject(
              updateErrorWithErrorData(
                (errorData: $FlowFixMe),
                enqueueingFrameError,
              ),
            ),
        );
      });
    };
  } else {
    fn = function nonPromiseMethodWrapper(...args: Array<mixed>) {
      const lastArg = args.length > 0 ? args[args.length - 1] : null;
      const secondLastArg = args.length > 1 ? args[args.length - 2] : null;
      const hasSuccessCallback = typeof lastArg === 'function';
      const hasErrorCallback = typeof secondLastArg === 'function';
      hasErrorCallback &&
        invariant(
          hasSuccessCallback,
          'Cannot have a non-function arg after a function arg.',
        );
      // $FlowFixMe[incompatible-type]
      const onSuccess: ?(mixed) => void = hasSuccessCallback ? lastArg : null;
      // $FlowFixMe[incompatible-type]
      const onFail: ?(mixed) => void = hasErrorCallback ? secondLastArg : null;
      const callbackCount = hasSuccessCallback + hasErrorCallback;
      const newArgs = args.slice(0, args.length - callbackCount);
      if (type === 'sync') {
        return BatchedBridge.callNativeSyncHook(
          moduleID,
          methodID,
          newArgs,
          onFail,
          onSuccess,
        );
      } else {
        BatchedBridge.enqueueNativeCall(
          moduleID,
          methodID,
          newArgs,
          onFail,
          onSuccess,
        );
      }
    };
  }
  fn.type = type;
  return fn;
}