1.JS调用java模块中的方法
1.1 分析java模块
以官方案例为例
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import {TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {
add(a: number, b: number): Promise<number>;
}
export default TurboModuleRegistry.get<Spec>(
'RTNCalculator',
) as Spec | null;
首先必须访问NativeModules模块
Libraries\BatchedBridge\NativeModules.js
let NativeModules: {[moduleName: string]: $FlowFixMe, ...} = {};
if (global.nativeModuleProxy) {
NativeModules = global.nativeModuleProxy;
} else if (!global.nativeExtensions) {
// ...
}
module.exports = NativeModules;
模块返回的是一个全局的对象nativeModuleProxy
,定位到JSIExecutor.cpp中
ReactCommon\jsiexecutor\jsireact\JSIExecutor.cpp
void JSIExecutor::initializeRuntime() {
// ...
runtime_->global().setProperty(
*runtime_,
"nativeModuleProxy",
Object::createFromHostObject(
*runtime_, std::make_shared<NativeModuleProxy>(nativeModules_)));
// ...
}
发现cpp通过jsi提供的方法setProperty
往js运行时全局注入了NativeModuleProxy
类型的对象
class JSIExecutor::NativeModuleProxy : public jsi::HostObject {
public:
NativeModuleProxy(std::shared_ptr<JSINativeModules> nativeModules)
: weakNativeModules_(nativeModules) {}
Value get(Runtime& rt, const PropNameID& name) override {
if (name.utf8(rt) == "name") {
return jsi::String::createFromAscii(rt, "NativeModules");
}
auto nativeModules = weakNativeModules_.lock();
if (!nativeModules) {
return nullptr;
}
return nativeModules->getModule(rt, name);
}
void set(Runtime&, const PropNameID&, const Value&) override {
throw std::runtime_error(
"Unable to put on NativeModules: Operation unsupported");
}
private:
std::weak_ptr<JSINativeModules> weakNativeModules_;
};
发现NativeModuleProxy
最终调用了入参nativeModules即为JSINativeModules
类型对象的getModule
方法,记住这里
JSIExecutor::JSIExecutor(
std::shared_ptr<jsi::Runtime> runtime,
std::shared_ptr<ExecutorDelegate> delegate,
const JSIScopedTimeoutInvoker& scopedTimeoutInvoker,
RuntimeInstaller runtimeInstaller)
: runtime_(runtime),
delegate_(delegate),
// 此处构建nativeModules delegate对象反推
nativeModules_(std::make_shared<JSINativeModules>(
delegate ? delegate->getModuleRegistry() : nullptr)),
moduleRegistry_(delegate ? delegate->getModuleRegistry() : nullptr),
scopedTimeoutInvoker_(scopedTimeoutInvoker),
runtimeInstaller_(runtimeInstaller) {
runtime_->global().setProperty(
*runtime, "__jsiExecutorDescription", runtime->description());
}
找到入参对象nativeModules_
的构造方法接收一个ModuleRegistry
类型的参数delegate->getModuleRegistry(),开始反推delegate对象的获取
直接上调用堆栈:
- ReactCommon\jsiexecutor\jsireact\JSIExecutor.cpp --- JSIExecutor::JSIExecutor
- ReactAndroid\src\main\jni\react\jscexecutor\OnLoad.cpp --- JSExecutorFactory::createJSExecutor
- ReactCommon\cxxreact\NativeToJsBridge.cpp --- NativeToJsBridge::NativeToJsBridge
- ReactCommon\cxxreact\Instance.cpp --- Instance::initializeBridge
- ReactAndroid\src\main\jni\react\jni\CatalystInstanceImpl.cpp --- CatalystInstanceImpl::initializeBridge
- CatalystInstanceImpl.java --- CatalystInstanceImpl::initializeBridge
// ReactCommon\cxxreact\NativeToJsBridge.cpp
NativeToJsBridge::NativeToJsBridge(
JSExecutorFactory* jsExecutorFactory,
std::shared_ptr<ModuleRegistry> registry,
std::shared_ptr<MessageQueueThread> jsQueue,
std::shared_ptr<InstanceCallback> callback)
: m_destroyed(std::make_shared<bool>(false)),
// 此处得到delegate对象
m_delegate(std::make_shared<JsToNativeBridge>(registry, callback)),
m_executor(jsExecutorFactory->createJSExecutor(m_delegate, jsQueue)),
m_executorMessageQueueThread(std::move(jsQueue)),
m_inspectable(m_executor->isInspectable()) {}
class JsToNativeBridge : public react::ExecutorDelegate {
public:
JsToNativeBridge(
std::shared_ptr<ModuleRegistry> registry,
std::shared_ptr<InstanceCallback> callback)
: m_registry(registry), m_callback(callback) {}
// 此处返回注册的模块
std::shared_ptr<ModuleRegistry> getModuleRegistry() override {
return m_registry;
}
//...
};
// ReactCommon\cxxreact\Instance.cpp
void Instance::initializeBridge(
std::unique_ptr<InstanceCallback> callback,
std::shared_ptr<JSExecutorFactory> jsef,
std::shared_ptr<MessageQueueThread> jsQueue,
std::shared_ptr<ModuleRegistry> moduleRegistry) {
callback_ = std::move(callback);
moduleRegistry_ = std::move(moduleRegistry);
jsQueue->runOnQueueSync([this, &jsef, jsQueue]() mutable {
nativeToJsBridge_ = std::make_shared<NativeToJsBridge>(
jsef.get(), moduleRegistry_, jsQueue, callback_);
// 此处向js运行时注入全局对象nativeModuleProxy
nativeToJsBridge_->initializeRuntime();
/**
* After NativeToJsBridge is created, the jsi::Runtime should exist.
* Also, the JS message queue thread exists. So, it's safe to
* schedule all queued up js Calls.
*/
jsCallInvoker_->setNativeToJsBridgeAndFlushCalls(nativeToJsBridge_);
std::scoped_lock lock(m_syncMutex);
m_syncReady = true;
m_syncCV.notify_all();
});
CHECK(nativeToJsBridge_);
}
public class NativeModuleRegistry {
Collection<JavaModuleWrapper> getJavaModules(JSInstance jsInstance) {
ArrayList<JavaModuleWrapper> javaModules = new ArrayList<>();
for (Map.Entry<String, ModuleHolder> entry : mModules.entrySet()) {
if (!entry.getValue().isCxxModule()) {
javaModules.add(new JavaModuleWrapper(jsInstance, entry.getValue()));
}
}
return javaModules;
}
}
mNativeModuleRegistry.getJavaModules方法将所有模块封装成JavaModuleWrapper
,以集合形式返回,
JavaModuleWrapper中大量使用反射对模块实例进行操作,等下会讲到
// CatalystInstanceImpl.java
initializeBridge(
new BridgeCallback(this),
jsExecutor,
mReactQueueConfiguration.getJSQueueThread(),
mNativeModulesQueueThread,
// 此处传入所有java模块
mNativeModuleRegistry.getJavaModules(this),
mNativeModuleRegistry.getCxxModules());
至此得到delegate对象,再看JSINativeModules实现
// ReactCommon\jsiexecutor\jsireact\JSINativeModules.h
class JSINativeModules {
public:
explicit JSINativeModules(std::shared_ptr<ModuleRegistry> moduleRegistry);
jsi::Value getModule(jsi::Runtime& rt, const jsi::PropNameID& name);
void reset();
private:
std::optional<jsi::Function> m_genNativeModuleJS;
std::shared_ptr<ModuleRegistry> m_moduleRegistry;
std::unordered_map<std::string, jsi::Object> m_objects;
std::optional<jsi::Object> createModule(
jsi::Runtime& rt,
const std::string& name);
};
// ReactCommon\jsiexecutor\jsireact\JSINativeModules.cpp
JSINativeModules::JSINativeModules(
std::shared_ptr<ModuleRegistry> moduleRegistry)
: m_moduleRegistry(std::move(moduleRegistry)) {}
// NativeModuleProxy主要用到此方法
Value JSINativeModules::getModule(Runtime& rt, const PropNameID& name) {
if (!m_moduleRegistry) {
return nullptr;
}
std::string moduleName = name.utf8(rt);
BridgeNativeModulePerfLogger::moduleJSRequireBeginningStart(
moduleName.c_str());
// m_objects是一个缓存模块实例的map,优先从map中获取实例
const auto it = m_objects.find(moduleName);
if (it != m_objects.end()) {
BridgeNativeModulePerfLogger::moduleJSRequireBeginningCacheHit(
moduleName.c_str());
BridgeNativeModulePerfLogger::moduleJSRequireBeginningEnd(
moduleName.c_str());
return Value(rt, it->second);
}
// m_objects中不存在实例则创建一个
auto module = createModule(rt, moduleName);
if (!module.has_value()) {
BridgeNativeModulePerfLogger::moduleJSRequireEndingFail(moduleName.c_str());
// Allow lookup to continue in the objects own properties, which allows for
// overrides of NativeModules
return nullptr;
}
// 放入m_objects中缓存起来
auto result =
m_objects.emplace(std::move(moduleName), std::move(*module)).first;
Value ret = Value(rt, result->second);
BridgeNativeModulePerfLogger::moduleJSRequireEndingEnd(moduleName.c_str());
return ret;
}
std::optional<Object> JSINativeModules::createModule(
Runtime& rt,
const std::string& name) {
bool hasLogger(ReactMarker::logTaggedMarkerImpl);
if (hasLogger) {
ReactMarker::logTaggedMarker(
ReactMarker::NATIVE_MODULE_SETUP_START, name.c_str());
}
if (!m_genNativeModuleJS) {
m_genNativeModuleJS =
rt.global().getPropertyAsFunction(rt, "__fbGenNativeModule");
}
// 通过JavaModuleWrapper暴露的反射方法实现动态分析模块的能力
// 通过反射调用模块的getConstants方法,将常量放入结果中
// 通过反射获取模块下的所有方法,并且获取注解的描述信息将方法区分为同步或者异步
auto result = m_moduleRegistry->getConfig(name);
if (!result.has_value()) {
return std::nullopt;
}
Value moduleInfo = m_genNativeModuleJS->call(
rt,
valueFromDynamic(rt, result->config),
static_cast<double>(result->index));
CHECK(!moduleInfo.isNull()) << "Module returned from genNativeModule is null";
CHECK(moduleInfo.isObject())
<< "Module returned from genNativeModule isn't an Object";
std::optional<Object> module(
moduleInfo.asObject(rt).getPropertyAsObject(rt, "module"));
if (hasLogger) {
ReactMarker::logTaggedMarker(
ReactMarker::NATIVE_MODULE_SETUP_STOP, name.c_str());
}
return module;
}
至此获取java模块的配置信息
export type ModuleConfig = [
string /* name */,
?{...} /* constants */,
?$ReadOnlyArray<string> /* functions */,
?$ReadOnlyArray<number> /* promise method IDs */,
?$ReadOnlyArray<number> /* sync method IDs */,
];
function genModule(
config: ?ModuleConfig,
moduleID: number,
): ?{
name: string,
module?: {...},
...
} {
if (!config) {
return null;
}
const [moduleName, constants, methods, promiseMethods, syncMethods] = config;
invariant(
!moduleName.startsWith('RCT') && !moduleName.startsWith('RK'),
"Module name prefixes should've been stripped by the native side " +
"but wasn't for " +
moduleName,
);
if (!constants && !methods) {
// Module contents will be filled in lazily later
return {name: moduleName};
}
const module: {[string]: mixed} = {};
methods &&
methods.forEach((methodName, methodID) => {
const isPromise =
(promiseMethods && arrayContains(promiseMethods, methodID)) || false;
const isSync =
(syncMethods && arrayContains(syncMethods, methodID)) || false;
invariant(
!isPromise || !isSync,
'Cannot have a method that is both async and a sync hook',
);
const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
module[methodName] = genMethod(moduleID, methodID, methodType);
});
Object.assign(module, constants);
if (module.getConstants == null) {
module.getConstants = () => constants || Object.freeze({});
} else {
console.warn(
`Unable to define method 'getConstants()' on NativeModule '${moduleName}'. NativeModule '${moduleName}' already has a constant or method called 'getConstants'. Please remove it.`,
);
}
if (__DEV__) {
BatchedBridge.createDebugLookup(moduleID, moduleName, methods);
}
return {name: moduleName, module};
}
// export this method as a global so we can call it from native
global.__fbGenNativeModule = genModule;
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;
// $FlowFixMe[unsafe-addition]
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,
);
}
};
}
// $FlowFixMe[prop-missing]
fn.type = type;
return fn;
}
调用js全局方法__fbGenNativeModule
生成对应java模块的js对象,此时访问该对象会包含java模块下的配置信息,包括模块名常量与所有方法,通过genMethod
可以发现调用模块方法时同步方法使用BatchedBridge.callNativeSyncHook
,异步方法使用BatchedBridge.enqueueNativeCall
,至此js侧得到了访问对应java模块的能力,接下来看如何调用java模块方法并获得方法返回内容。
// Libraries\BatchedBridge\BatchedBridge.js
'use strict';
const MessageQueue = require('./MessageQueue');
const BatchedBridge: MessageQueue = new MessageQueue();
// Wire up the batched bridge on the global object so that we can call into it.
// Ideally, this would be the inverse relationship. I.e. the native environment
// provides this global directly with its script embedded. Then this module
// would export it. A possible fix would be to trim the dependencies in
// MessageQueue to its minimal features and embed that in the native runtime.
Object.defineProperty(global, '__fbBatchedBridge', {
configurable: true,
value: BatchedBridge,
});
module.exports = BatchedBridge;
// Libraries\BatchedBridge\MessageQueue.js
class MessageQueue {
callNativeSyncHook(
moduleID: number,
methodID: number,
params: mixed[],
onFail: ?(...mixed[]) => void,
onSucc: ?(...mixed[]) => void,
): mixed {
// 注册回调方法
this.processCallbacks(moduleID, methodID, params, onFail, onSucc);
// 调用通过jsi注册的cpp方法
return global.nativeCallSyncHook(moduleID, methodID, params);
}
enqueueNativeCall(
moduleID: number,
methodID: number,
params: mixed[],
onFail: ?(...mixed[]) => void,
onSucc: ?(...mixed[]) => void,
): void {
this.processCallbacks(moduleID, methodID, params, onFail, onSucc);
this._queue[MODULE_IDS].push(moduleID);
this._queue[METHOD_IDS].push(methodID);
// Replacement allows normally non-JSON-convertible values to be
// seen. There is ambiguity with string values, but in context,
// it should at least be a strong hint.
const replacer = (key: string, val: $FlowFixMe) => {
const t = typeof val;
if (t === 'function') {
return '<<Function ' + val.name + '>>';
} else if (t === 'number' && !isFinite(val)) {
return '<<' + val.toString() + '>>';
} else {
return val;
}
};
// Note that JSON.stringify
invariant(
isValidArgument(params),
'%s is not usable as a native method argument',
JSON.stringify(params, replacer),
);
// The params object should not be mutated after being queued
deepFreezeAndThrowOnMutationInDev(params);
}
this._queue[PARAMS].push(params);
const now = Date.now();
if (
global.nativeFlushQueueImmediate &&
now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS
) {
const queue = this._queue;
this._queue = [[], [], [], this._callID];
this._lastFlush = now;
global.nativeFlushQueueImmediate(queue);
}
Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length);
if (__DEV__ && this.__spy && isFinite(moduleID)) {
// $FlowFixMe[not-a-function]
this.__spy({
type: TO_NATIVE,
module: this._remoteModuleTable[moduleID],
method: this._remoteMethodTable[moduleID][methodID],
args: params,
});
} else if (this.__spy) {
this.__spy({
type: TO_NATIVE,
module: moduleID + '',
method: methodID,
args: params,
});
}
}
processCallbacks(
moduleID: number,
methodID: number,
params: mixed[],
onFail: ?(...mixed[]) => void,
onSucc: ?(...mixed[]) => void,
): void {
if (onFail || onSucc) {
// Encode callIDs into pairs of callback identifiers by shifting left and using the rightmost bit
// to indicate fail (0) or success (1)
// eslint-disable-next-line no-bitwise
onFail && params.push(this._callID << 1);
// eslint-disable-next-line no-bitwise
onSucc && params.push((this._callID << 1) | 1);
this._successCallbacks.set(this._callID, onSucc);
this._failureCallbacks.set(this._callID, onFail);
}
this._callID++;
}
}
梳理流程
- CatalsyInstanceImpl中调用initializeBridge方式通过jni的方式初始化NativeToJsBridge.
- NativeToJsBridge构造方法中初始化JsToNativeBridge与JSExecutor,其中JsToNativeBridge构建时包含initializeBridge方法传入的ModuleRegistry,ModuleRegistry是一个向量包含所有的javaModules与cxxModules,JSIExecutor在构造时会得到JsToNativeBridge即delegate.
- JSIExecutor初始化过程中生成一个JSINativeModules对象,该对象构造方法通过delegate->getModuleRegistry()获取到ModuleRegistry,如此JSINativeModules就获得了访问所有javaModules的能力.
- initializeBridge方法调用到JSIExecutor的initializeRuntime方法,该方法会通过jsi向js运行时全局注入一个名为nativeModuleProxy的对象,该对象初始化时接收JSINativeModules,因此js运行时也具有了访问所有javaModules的能力.
- 当js侧访问模块时,会调用JSINativeModules的getModule方法,getModule在第一次获取某个模块会调用createModule方法在ModuleRegistry获取到对应模块在向量中的下标此为moduleID,利用JavaModuleWrapper提供的反射方法分析模块的配置,包括模块名和模块的常量和模块下的所有方法(包含注解信息以区分同步方法和异步方法类型)此为config,随后调用js全局方法__fbGenNativeModule传入config和moduleId生成js对象,至此js侧获得对应java模块的js对象.
章节总结
CatalsyInstanceImpl中通过jni调用cpp初始化JSIExecutor,当js侧访问对应java模块时,cpp通过jni调用java的反射方法分析java模块获得模块信息config,之后cpp通过jsi调用js侧全局方法__fbGenNativeModule传入模块信息config生成对应java模块的js对象返回给js侧,至此js侧可以获取对应java模块的js对象,该对象下有java模块下的模块名、常量、所有方法,达到分析java模块的目的。
1.2 同步方法调用
先看同步调用global.nativeCallSyncHook
的实现
// ReactCommon\jsiexecutor\jsireact\JSIExecutor.cpp
void JSIExecutor::initializeRuntime() {
runtime_->global().setProperty(
*runtime_,
"nativeCallSyncHook",
Function::createFromHostFunction(
*runtime_,
PropNameID::forAscii(*runtime_, "nativeCallSyncHook"),
1,
[this](
jsi::Runtime&,
const jsi::Value&,
const jsi::Value* args,
size_t count) { return nativeCallSyncHook(args, count); }));
}
Value JSIExecutor::nativeCallSyncHook(const Value* args, size_t count) {
if (count != 3) {
throw std::invalid_argument("nativeCallSyncHook arg count must be 3");
}
if (!args[2].isObject() || !args[2].asObject(*runtime_).isArray(*runtime_)) {
throw std::invalid_argument(
folly::to<std::string>("method parameters should be array"));
}
unsigned int moduleId = static_cast<unsigned int>(args[0].getNumber());
unsigned int methodId = static_cast<unsigned int>(args[1].getNumber());
std::string moduleName;
std::string methodName;
if (moduleRegistry_) {
moduleName = moduleRegistry_->getModuleName(moduleId);
methodName = moduleRegistry_->getModuleSyncMethodName(moduleId, methodId);
BridgeNativeModulePerfLogger::syncMethodCallStart(
moduleName.c_str(), methodName.c_str());
BridgeNativeModulePerfLogger::syncMethodCallArgConversionStart(
moduleName.c_str(), methodName.c_str());
}
// 关键调用
MethodCallResult result = delegate_->callSerializableNativeHook(
*this, moduleId, methodId, dynamicFromValue(*runtime_, args[2]));
/**
* Note:
* In RCTNativeModule, std::nullopt is returned from
* callSerializableNativeHook when executing a NativeModule method fails.
* Therefore, it's safe to not terminate the syncMethodCall when std::nullopt
* is returned.
*
* TODO: In JavaNativeModule, std::nullopt is returned when the synchronous
* NativeModule method has the void return type. Change this to return
* folly::dynamic(nullptr) instead, so that std::nullopt is reserved for
* exceptional scenarios.
*
* TODO: Investigate CxxModule infra to see if std::nullopt is used for
* returns in exceptional scenarios.
**/
if (!result.has_value()) {
return Value::undefined();
}
Value returnValue = valueFromDynamic(*runtime_, result.value());
if (moduleRegistry_) {
BridgeNativeModulePerfLogger::syncMethodCallReturnConversionEnd(
moduleName.c_str(), methodName.c_str());
BridgeNativeModulePerfLogger::syncMethodCallEnd(
moduleName.c_str(), methodName.c_str());
}
return returnValue;
}
通过jsi全局注入nativeCallSyncHook
方法, 调用类型为JsToNativeBridge
的delegate_
对象的callSerializableNativeHook
方法
// ReactCommon\cxxreact\NativeToJsBridge.cpp
class JsToNativeBridge : public react::ExecutorDelegate {
MethodCallResult callSerializableNativeHook(
[[maybe_unused]] JSExecutor& executor,
unsigned int moduleId,
unsigned int methodId,
folly::dynamic&& args) override {
return m_registry->callSerializableNativeHook(
moduleId, methodId, std::move(args));
}
}
// ReactCommon\cxxreact\ModuleRegistry.cpp
MethodCallResult ModuleRegistry::callSerializableNativeHook(
unsigned int moduleId,
unsigned int methodId,
folly::dynamic&& params) {
if (moduleId >= modules_.size()) {
throw std::runtime_error(folly::to<std::string>(
"moduleId ", moduleId, "out of range [0..", modules_.size(), ")"));
}
return modules_[moduleId]->callSerializableNativeHook(
methodId, std::move(params));
}
// ReactAndroid\src\main\jni\react\jni\JavaModuleWrapper.cpp
MethodCallResult JavaNativeModule::callSerializableNativeHook(
unsigned int reactMethodId,
folly::dynamic&& params) {
// TODO: evaluate whether calling through invoke is potentially faster
if (reactMethodId >= syncMethods_.size()) {
throw std::invalid_argument(folly::to<std::string>(
"methodId ",
reactMethodId,
" out of range [0..",
syncMethods_.size(),
"]"));
}
auto& method = syncMethods_[reactMethodId];
CHECK(method.has_value() && method->isSyncHook())
<< "Trying to invoke a asynchronous method as synchronous hook";
return method->invoke(instance_, wrapper_->getModule(), params);
}
// ReactAndroid\src\main\java\com\facebook\react\bridge\JavaModuleWrapper.java
class JavaModuleWrapper {
@DoNotStrip
public void invoke(int methodId, ReadableNativeArray parameters) {
if (mMethods == null || methodId >= mMethods.size()) {
return;
}
mMethods.get(methodId).invoke(mJSInstance, parameters);
}
}
class JavaMethodWrapper implements NativeModule.NativeMethod {
@Override
public void invoke(JSInstance jsInstance, ReadableArray parameters) {
try {
if (!mArgumentsProcessed) {
processArguments();
}
if (mArguments == null || mArgumentExtractors == null) {
throw new Error("processArguments failed");
}
if (mJSArgumentsNeeded != parameters.size()) {
throw new NativeArgumentsParseException(
traceName + " got " + parameters.size() + " arguments, expected " + mJSArgumentsNeeded);
}
int i = 0, jsArgumentsConsumed = 0;
try {
for (; i < mArgumentExtractors.length; i++) {
mArguments[i] =
mArgumentExtractors[i].extractArgument(jsInstance, parameters, jsArgumentsConsumed);
jsArgumentsConsumed += mArgumentExtractors[i].getJSArgumentsNeeded();
}
} catch (UnexpectedNativeTypeException | NullPointerException e) {
throw new NativeArgumentsParseException(
e.getMessage()
+ " (constructing arguments for "
+ traceName
+ " at argument index "
+ getAffectedRange(
jsArgumentsConsumed, mArgumentExtractors[i].getJSArgumentsNeeded())
+ ")",
e);
}
try {
// 最终通过反射执行模块对应方法
mMethod.invoke(mModuleWrapper.getModule(), mArguments);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(createInvokeExceptionMessage(traceName), e);
} catch (InvocationTargetException ite) {
// Exceptions thrown from native module calls end up wrapped in InvocationTargetException
// which just make traces harder to read and bump out useful information
if (ite.getCause() instanceof RuntimeException) {
throw (RuntimeException) ite.getCause();
}
throw new RuntimeException(createInvokeExceptionMessage(traceName), ite);
}
} finally {
SystraceMessage.endSection(TRACE_TAG_REACT_JAVA_BRIDGE).flush();
}
}
}
章节总结
cpp通过jsi注入的名为nativeCallSyncHook的js全局方法,在分析模块时产生的js对象通过闭包的方法保存了moduleId、metheId,调用js对象下的指定java模块方法时会将两个id与函数入参传达给cpp,cpp通过根据两个id找到对应模块和对应方法通过反射执行方法拿到执行结果,最终cpp通过jni返回执行结果给js侧。
1.3 异步方法调用
待续
2. Java调用js方法
待续