本篇来分析一下,RN js和java的通信机制,在上一篇启动流程 看完后,通信的过程,你应该也能猜出个大概。具体过程,也是很简单
1、React Native 源码分析(一)—— 启动流程 2、React Native 源码分析(二)—— 通信机制 3、React Native 源码分析(三)—— UI渲染流程 4、React Native 源码分析(四)—— 任务调度 5、React Native 源码分析(五)—— 事件分发
一、 Java->JS 通信
先来一张图,看一下通信的整体过程 图片来源
这里接着上一篇的代码1.9 reactRoot.runApplication(); 继续分析,从java启动react的过程
1.1 runApplication
@Override
public void runApplication() {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactRootView.runApplication");
try {
if (mReactInstanceManager == null || !mIsAttachedToInstance) {
return;
}
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
return;
}
CatalystInstance catalystInstance = reactContext.getCatalystInstance();
String jsAppModuleName = getJSModuleName();
if (mWasMeasured) {
updateRootLayoutSpecs(true, mWidthMeasureSpec, mHeightMeasureSpec);
}
WritableNativeMap appParams = new WritableNativeMap();
appParams.putDouble("rootTag", getRootViewTag());
@Nullable Bundle appProperties = getAppProperties();
if (appProperties != null) {
appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
}
mShouldLogContentAppeared = true;
catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
getJSModule的调用流程catalystInstance.getJSModule ->mJSModuleRegistry.getJavaScriptModule ,调用到了JavaScriptModuleRegistry中,这里是通过动态代理的方式,让 继承了JavaScriptModule的Interface中的方法的 调用,都被代理到 mCatalystInstance.callFunction
2、JavaScriptModuleRegistry # getJavaScriptModule
public final class JavaScriptModuleRegistry {
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;
public JavaScriptModuleRegistry() {
mModuleInstances = new HashMap<>();
}
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
CatalystInstance instance, Class<T> moduleInterface) {
JavaScriptModule module = mModuleInstances.get(moduleInterface);
if (module != null) {
return (T) module;
}
JavaScriptModule interfaceProxy =
(JavaScriptModule)
Proxy.newProxyInstance(
moduleInterface.getClassLoader(),
new Class[] {moduleInterface},
new JavaScriptModuleInvocationHandler(instance, moduleInterface));
mModuleInstances.put(moduleInterface, interfaceProxy);
return (T) interfaceProxy;
}
private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
private final CatalystInstance mCatalystInstance;
private final Class<? extends JavaScriptModule> mModuleInterface;
private @Nullable String mName;
public JavaScriptModuleInvocationHandler(
CatalystInstance catalystInstance, Class<? extends JavaScriptModule> moduleInterface) {
mCatalystInstance = catalystInstance;
mModuleInterface = moduleInterface;
...
}
....
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
mCatalystInstance.callFunction(getJSModuleName(), method.getName(), jsArgs);
return null;
}
}
....
}
1.3 CatalystInstance的函数 callFunction 和 runJSBundle
public void callFunction(PendingJSCall function) {
if (mDestroyed) {
final String call = function.toString();
FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed: " + call);
return;
}
if (!mAcceptCalls) {
synchronized (mJSCallsPendingInitLock) {
if (!mAcceptCalls) {
mJSCallsPendingInit.add(function);
return;
}
}
}
function.call(this);
}
mAcceptCalls 的初始值是false,callFunction 和 runJSBundle 都是从React Native 源码分析(一)—— 启动流程的代码1.4的 runCreateReactContextOnNewThread,callFunction 是在nativeModule线程运行,由于并发的原因,为了保证js bundle加载后,再去调用js的函数。引入mAcceptCalls 来控制,
@Override
public void runJSBundle() {
mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
synchronized (mJSCallsPendingInitLock) {
mAcceptCalls = true;
for (PendingJSCall function : mJSCallsPendingInit) {
function.call(this);
}
mJSCallsPendingInit.clear();
mJSBundleHasLoaded = true;
}
}
最终都是调用了function.call(this); ,下面来分析该函数
1.4 PendingJSCall # call
void call(CatalystInstanceImpl catalystInstance) {
NativeArray arguments = mArguments != null ? mArguments : new WritableNativeArray();
catalystInstance.jniCallJSFunction(mModule, mMethod, arguments);
}
1.5 CatalystInstanceImpl::jniCallJSFunction
void CatalystInstanceImpl::jniCallJSFunction(
std::string module,
std::string method,
NativeArray *arguments) {
instance_->callJSFunction(
std::move(module), std::move(method), arguments->consume());
}
1.6 Instance::callJSFunction
void Instance::callJSFunction(
std::string &&module,
std::string &&method,
folly::dynamic &¶ms) {
callback_->incrementPendingJSCalls();
nativeToJsBridge_->callFunction(
std::move(module), std::move(method), std::move(params));
}
1.7 NativeToJsBridge::callFunction
void NativeToJsBridge::callFunction(
std::string &&module,
std::string &&method,
folly::dynamic &&arguments) {
...
runOnExecutorQueue([this,
module = std::move(module),
method = std::move(method),
arguments = std::move(arguments),
systraceCookie](JSExecutor *executor) {
if (m_applicationScriptHasFailure) {
...
executor->callFunction(module, method, arguments);
});
}
最终调用m_executor ,(本例)也就是JSIExecutor 的callFunction,(也可能是其他的jsexecutor 的callFunction)
1.8 JSIExecutor:: callFunction
void JSIExecutor::callFunction(
const std::string &moduleId,
const std::string &methodId,
const folly::dynamic &arguments) {
if (!callFunctionReturnFlushedQueue_) {
bindBridge();
}
...
try {
scopedTimeoutInvoker_(
[&] {
ret = callFunctionReturnFlushedQueue_->call(
*runtime_,
moduleId,
methodId,
valueFromDynamic(*runtime_, arguments));
},
std::move(errorProducer));
} catch (...) {
std::throw_with_nested(
std::runtime_error("Error calling " + moduleId + "." + methodId));
}
callNativeModules(ret, true);
}
下面到js看看,callFunctionReturnFlushedQueue_ 的实现
1.9 MessageQueue & callFunctionReturnFlushedQueue
MessageQueue 类的位置在 Libraries/BatchedBridge/MessageQueue.js
callFunctionReturnFlushedQueue(
module: string,
method: string,
args: mixed[],
): null | [Array<number>, Array<number>, Array<mixed>, number] {
this.__guard(() => {
this.__callFunction(module, method, args);
});
return this.flushedQueue();
}
__callFunction(module: string, method: string, args: mixed[]): void {
this._lastFlush = Date.now();
this._eventLoopStartTime = this._lastFlush;
...
const moduleMethods = this.getCallableModule(module);
...
moduleMethods[method].apply(moduleMethods, args);
}
至此,java-> js 的通信流程就分析完了,下面来看看js->java的
二、 JS->Java 通信
在开始分析之前,首先要知道,JS->Java 通信是两种的,表现在通信中的差异,下面会介绍一些。具体原因是传递的 JavaScriptExecutorFactory不同(可在ReactNativeHost中设置),但是 如果你本地跑了metro,那么会自动使用 ProxyJavaScriptExecutor(可自己翻阅代码 ReactInstanceManager 的onReloadWithJSDebugger函数)
我们在JS中调用Java的方法,是通过这样的形式
- 继承 ReactContextBaseJavaModule,使用@ReactMethod 注解 暴露给js的方法,
- 把 上一步创建的类 添加到ReactPackage
- 把ReactPackage添加到ReactNativeHost 的getPackages() 的返回值中
- 在js侧,通过
NativeModules.xxxModuleName.xxxMethodName() 调用到原生
下面我们就从 NativeModules.xxxModuleName 这样的代码开始分析:
先来看张图,对整体过程,有个感觉。图片来源
首先需要搞清楚,这个NativeModules 是什么,在js侧,代码路径 Libraries/BatchedBridge/NativeModules.js
2.1、 NativeModules.js
let NativeModules: {[moduleName: string]: $FlowFixMe, ...} = {};
if (global.nativeModuleProxy) {
NativeModules = global.nativeModuleProxy;
} else if (!global.nativeExtensions) {
const bridgeConfig = global.__fbBatchedBridgeConfig;
const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty');
(bridgeConfig.remoteModuleConfig || []).forEach(
(config: ModuleConfig, moduleID: number) => {
const info = genModule(config, moduleID);
if (!info) {
return;
}
if (info.module) {
NativeModules[info.name] = info.module;
}
else {
defineLazyObjectProperty(NativeModules, info.name, {
get: () => loadModule(info.name, moduleID),
});
}
},
);
}
module.exports = NativeModules;
不同的JavaScriptExecutor 最终都会执行到genModule,下面我们分析JSIExecutor 分支 的流程。
简单回忆一下,在 JSIExecutor::initializeRuntime() 中设置了 global.nativeModuleProxy 的值,
runtime_->global().setProperty(
*runtime_,
"nativeModuleProxy",
Object::createFromHostObject(
*runtime_, std::make_shared<NativeModuleProxy>(nativeModules_)));
可以看到global.nativeModuleProxy 是NativeModuleProxy 类型,在获取对应的module,会执行NativeModuleProxy的get方法,下面来到c++层:
2.2、 JSIExecutor::NativeModuleProxy
class JSIExecutor::NativeModuleProxy : public jsi::HostObject {
public:
NativeModuleProxy(std::shared_ptr<JSINativeModules> nativeModules)
: weakNativeModules_(nativeModules) {}
Value get(Runtime &rt, const PropNameID &name) override {
...
auto nativeModules = weakNativeModules_.lock();
if (!nativeModules) {
return nullptr;
}
return nativeModules->getModule(rt, name);
}
...
private:
std::weak_ptr<JSINativeModules> weakNativeModules_;
};
2.3、 JSIExecutor # getModule
Value JSINativeModules::getModule(Runtime &rt, const PropNameID &name) {
if (!m_moduleRegistry) {
return nullptr;
}
std::string moduleName = name.utf8(rt);
const auto it = m_objects.find(moduleName);
if (it != m_objects.end()) {
...
return Value(rt, it->second);
}
auto module = createModule(rt, moduleName);
...省略判空逻辑...
auto result = m_objects.emplace(std::move(moduleName), std::move(*module)).first;
Value ret = Value(rt, result->second);
return ret;
}
createModule 是核心,下面来分析
2.4 JSINativeModules::createModule
folly::Optional<Object> JSINativeModules::createModule(
Runtime &rt,
const std::string &name) {
if (!m_genNativeModuleJS) {
m_genNativeModuleJS =
rt.global().getPropertyAsFunction(rt, "__fbGenNativeModule");
}
auto result = m_moduleRegistry->getConfig(name);
if (!result.hasValue()) {
return folly::none;
}
Value moduleInfo = m_genNativeModuleJS->call(
rt,
valueFromDynamic(rt, result->config),
static_cast<double>(result->index));
folly::Optional<Object> module(
moduleInfo.asObject(rt).getPropertyAsObject(rt, "module"));
return module;
}
m_moduleRegistry->getConfig(name); 的结果,会传递到js中去处理module,下面来分析一下这句代码
2.5 ModuleRegistry::getConfig
folly::Optional<ModuleConfig> ModuleRegistry::getConfig(
const std::string &name) {
SystraceSection s("ModuleRegistry::getConfig", "module", name);
if (modulesByName_.empty() && !modules_.empty()) {
moduleNames();
}
auto it = modulesByName_.find(name);
if (it == modulesByName_.end()) {
if (unknownModules_.find(name) != unknownModules_.end()) {
return folly::none;
}
if (!moduleNotFoundCallback_) {
unknownModules_.insert(name);
return folly::none;
}
bool wasModuleLazilyLoaded = moduleNotFoundCallback_(name);
it = modulesByName_.find(name);
bool wasModuleRegisteredWithRegistry =
wasModuleLazilyLoaded && it != modulesByName_.end();
if (!wasModuleRegisteredWithRegistry) {
unknownModules_.insert(name);
return folly::none;
}
} else {
BridgeNativeModulePerfLogger::moduleJSRequireBeginningEnd(name.c_str());
}
size_t index = it->second;
NativeModule *module = modules_[index].get();
folly::dynamic config = folly::dynamic::array(name);
{
SystraceSection s_("ModuleRegistry::getConstants", "module", name);
config.push_back(module->getConstants());
}
{
SystraceSection s_("ModuleRegistry::getMethods", "module", name);
std::vector<MethodDescriptor> methods = module->getMethods();
folly::dynamic methodNames = folly::dynamic::array;
folly::dynamic promiseMethodIds = folly::dynamic::array;
folly::dynamic syncMethodIds = folly::dynamic::array;
for (auto &descriptor : methods) {
methodNames.push_back(std::move(descriptor.name));
if (descriptor.type == "promise") {
promiseMethodIds.push_back(methodNames.size() - 1);
} else if (descriptor.type == "sync") {
syncMethodIds.push_back(methodNames.size() - 1);
}
}
if (!methodNames.empty()) {
config.push_back(std::move(methodNames));
if (!promiseMethodIds.empty() || !syncMethodIds.empty()) {
config.push_back(std::move(promiseMethodIds));
if (!syncMethodIds.empty()) {
config.push_back(std::move(syncMethodIds));
}
}
}
}
...
return ModuleConfig{index, config};
}
代码回到2.4,继续往下执行,调用到js层
2.6 NativeModule # genModule
function genModule(
config: ?ModuleConfig,
moduleID: number,
): ?{
name: string,
module?: {...},
...
} {
...
const [moduleName, constants, methods, promiseMethods, syncMethods] = config;
if (!constants && !methods) {
return {name: moduleName};
}
const module = {};
methods &&
methods.forEach((methodName, methodID) => {
const isPromise = (promiseMethods && arrayContains(promiseMethods, methodID)) || false;
const isSync = (syncMethods && arrayContains(syncMethods, methodID)) || false;
const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
module[methodName] = genMethod(moduleID, methodID, methodType);
});
Object.assign(module, constants);
...
return {name: moduleName, module};
}
接着到genMethod
2.7 NativeModule # genMethod
function genMethod(moduleID: number, methodID: number, type: MethodType) {
let fn = null;
if (type === 'promise') {
fn = function promiseMethodWrapper(...args: Array<mixed>) {
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';
const onSuccess: ?(mixed) => void = hasSuccessCallback ? lastArg : null;
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;
}
到此, NativeModules.xxxModuleName 的流程就结束了,后面调用函数,就是调用代码2.7 生成的函数,最终会调到,例如 BatchedBridge.enqueueNativeCall ,下面来分析
2.8 MessageQueue # enqueueNativeCall
enqueueNativeCall(
moduleID: number,
methodID: number,
params: mixed[],
onFail: ?(...mixed[]) => void,
onSucc: ?(...mixed[]) => void,
) {
this.processCallbacks(moduleID, methodID, params, onFail, onSucc);
this._queue[MODULE_IDS].push(moduleID);
this._queue[METHOD_IDS].push(methodID);
...省略dev的逻辑...
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);
}
...
}
在上篇文章都有介绍 ,这里就不再看nativeFlushQueueImmediate 的赋值过程了,直接看它映射到的函数callNativeModules
2.9 JSIExecutor # callNativeModules
void JSIExecutor::callNativeModules(const Value &queue, bool isEndOfBatch) {
...
delegate_->callNativeModules(
*this, dynamicFromValue(*runtime_, queue), isEndOfBatch);
}
2.10 JsToNativeBridge # callNativeModules
void callNativeModules(
__unused JSExecutor &executor,
folly::dynamic &&calls,
bool isEndOfBatch) override {
m_batchHadNativeModuleOrTurboModuleCalls =
m_batchHadNativeModuleOrTurboModuleCalls || !calls.empty();
std::vector<MethodCall> methodCalls = parseMethodCalls(std::move(calls));
BridgeNativeModulePerfLogger::asyncMethodCallBatchPreprocessEnd(
(int)methodCalls.size());
for (auto &call : methodCalls) {
m_registry->callNativeMethod(call.moduleId, call.methodId, std::move(call.arguments), call.callId);
}
if (isEndOfBatch) {
if (m_batchHadNativeModuleOrTurboModuleCalls) {
m_callback->onBatchComplete();
m_batchHadNativeModuleOrTurboModuleCalls = false;
}
m_callback->decrementPendingJSCalls();
}
}
下面来看看m_registry->callNativeMethod 的调用
2.11 ModuleRegistry::callNativeMethod
void ModuleRegistry::callNativeMethod(
unsigned int moduleId,
unsigned int methodId,
folly::dynamic &¶ms,
int callId) {
modules_[moduleId]->invoke(methodId, std::move(params), callId);
}
你会不会有疑问,为什么这里根据moduleId,就能找到module。因为在代码2.5 的 ModuleRegistry::getConfig ,其实在modules_中找到指定name module的id
下面来继续分析invoke ,在CatalystInstanceImpl::initializeBridge 参数查看,知道了 module的类型是JavaModuleWrapper,跟随断点,来到JavaNativeModule::invoke
2.12 JavaModuleWrapper
void JavaNativeModule::invoke(
unsigned int reactMethodId,
folly::dynamic &¶ms,
int callId) {
messageQueueThread_->runOnQueue(
[this, reactMethodId, params = std::move(params), callId] {
static auto invokeMethod =
wrapper_->getClass()
->getMethod<void(jint, ReadableNativeArray::javaobject)>(
"invoke");
invokeMethod(
wrapper_,
static_cast<jint>(reactMethodId),
ReadableNativeArray::newObjectCxxArgs(std::move(params)).get());
});
}
看过上一篇的小伙伴,应该记得JMessageQueueThread ,messageQueueThread_类型就是JMessageQueueThread,它是通往java的一个类,runOnQueue 最终调用到的具体实现,是Java的MessageQueueThreadImpl的runOnQueue,发往Looper队列
public class MessageQueueThreadImpl implements MessageQueueThread {
public void runOnQueue(Runnable runnable) {
...
mHandler.post(runnable);
}
}
invoke 函数最终会调用到 Java层的JavaModuleWrapper#invoke
2.13 JavaModuleWrapper#invoke
public class JavaModuleWrapper {
...
public void invoke(int methodId, ReadableNativeArray parameters) {
if (mMethods == null || methodId >= mMethods.size()) {
return;
}
mMethods.get(methodId).invoke(mJSInstance, parameters);
}
}
2.14 JavaMethodWrapper#invoke
public class JavaMethodWrapper implements NativeModule.NativeMethod {
@Override
public void invoke(JSInstance jsInstance, ReadableArray parameters) {
try {
if (!mArgumentsProcessed) {
processArguments();
}
...
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 e) {
...
}
try {
mMethod.invoke(mModuleWrapper.getModule(), mArguments);
} catch (IllegalArgumentException ie) {
...
}
}
}
至此,js->java的通信流程,就分析完了
按照我的国际惯例,欢迎小伙伴们 点赞、评论 支持一下,欢迎吐槽,U·ェ·U
|