React Native Android 源码框架浅析(主流程及 Java 与 JS 双边通信)

本文深入探讨React Native Android应用的启动过程,详细解析JSBundle加载、Java与JS间的双向通信,涉及CatalystInstanceImpl、JSBundleLoader、NativeToJsBridge等多个关键组件,揭示React Native Android内部的工作机制。
摘要由CSDN通过智能技术生成

@Override

public void runJSBundle() {

mJSBundleHasLoaded = true;

//mJSBundleLoader就是前面分析的依据不同设置决定是JSBundleLoader的createAssetLoader还是createFileLoader等静态方法的匿名实现类。

// incrementPendingJSCalls();

mJSBundleLoader.loadScript(CatalystInstanceImpl.this);

}

通过注释我们假设 Loader 是默认的,也即 JSBundleLoader 类的如下方法:

public static JSBundleLoader createAssetLoader(

final Context context,

final String assetUrl) {

return new JSBundleLoader() {

@Override

public void loadScript(CatalystInstanceImpl instance) {

instance.loadScriptFromAssets(context.getAssets(), assetUrl);

}

@Override

public String getSourceUrl() {

return assetUrl;

}

};

}

可以看见,它实质又调用了 CatalystInstanceImpl 的 loadScriptFromAssets 方法,我们继续跟踪 CatalystInstanceImpl 的这个方法吧,如下:

native void loadScriptFromAssets(AssetManager assetManager, String assetURL);

loadScriptFromAssets 既然是一个 native 方法,我们去 CatalystInstanceImpl.cpp 看下这个方法的实现,如下:

void CatalystInstanceImpl::loadScriptFromAssets(jobject assetManager,

const std::string& assetURL) {

const int kAssetsLength = 9; // strlen(“assets://”);

//获取source路径名,不计前缀,这里默认就是index.android.bundle

auto sourceURL = assetURL.substr(kAssetsLength);

//assetManager是Java传递的AssetManager。

//extractAssetManager是JSLoader.cpp中通过系统动态链接库android/asset_manager_jni.h的AAssetManager_fromJava方法来获取AAssetManager对象的。

auto manager = react::extractAssetManager(assetManager);

//通过JSLoader对象的loadScriptFromAssets方法读文件,得到大字符串script(即index.android.bundle文件的JS内容)。

auto script = react::loadScriptFromAssets(manager, sourceURL);

//判断是不是Unbundle,这里不是Unbundle,因为打包命令我们用了react.gradle的默认bundle,没用unbundle命令(感兴趣的自己分析这条路线)。

if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {

instance_->loadUnbundle(

folly::make_unique(manager, sourceURL),

std::move(script),

sourceURL);

return;

} else {

//bundle命令打包的,所以走这里。

//instance_为ReactCommon目录下 Instance.h 中类的实例,前面分析过了。

instance_->loadScriptFromString(std::move(script), sourceURL);

}

}

看来还没到头,这货又走到了 ReactCommon 目录下 Instance 实例的 loadScriptFromString 方法去了(由此可以看出来前面 ReactNativeAndroid 目录下的 jni 代码都是 Android 平台特有的封装,直到 ReactCommon 才是通用的),如下:

//string为index.android.bundle内容。

//sourceURL在这里默认为index.android.bundle。

void Instance::loadScriptFromString(std::unique_ptr string,

std::string sourceURL) {

//callback_就是initializeBridge传进来的,实质实现是CatalystInstanceImpl的BridgeCallback。

//说白了就是回传一个状态,要开始搞loadScriptFromString了

callback_->incrementPendingJSCalls();

SystraceSection s(“reactbridge_xplat_loadScriptFromString”,

“sourceURL”, sourceURL);

//厉害了,Word哥,年度大戏啊!

//nativeToJsBridge_也是Instance::initializeBridge方法里初始化的,实现在Common的NativeToJsBridge类里。

nativeToJsBridge_->loadApplication(nullptr, std::move(string), std::move(sourceURL));

}

妈的,没完没了了,继续跟吧,到 Common 的 NativeToJsBridge.cpp 看看 loadApplication 方法吧,如下:

//unbundle传入的是个空指针。

//startupScript为bundle文件内容。

//startupScript为bundle文件名。

void NativeToJsBridge::loadApplication(

std::unique_ptr unbundle,

std::unique_ptr startupScript,

std::string startupScriptSourceURL) {

//runOnExecutorQueue实质就是获取一个MessageQueueThread,然后在其线程中执行一个task。

runOnExecutorQueue(

m_mainExecutorToken,

[unbundleWrap=folly::makeMoveWrapper(std::move(unbundle)),

startupScript=folly::makeMoveWrapper(std::move(startupScript)),

startupScriptSourceURL=std::move(startupScriptSourceURL)]

(JSExecutor* executor) mutable {

auto unbundle = unbundleWrap.move();

if (unbundle) {

executor->setJSModulesUnbundle(std::move(unbundle));

}

//因为我们是bundle命令打包的,所以走这里继续执行!!!

executor->loadApplicationScript(std::move(*startupScript),

std::move(startupScriptSourceURL));

});

}

靠靠靠,还不到头,又特么绕到 JSExecutor 的 loadApplicationScript 方法里面去了,继续跟吧(这个 executor 是 runOnExecutorQueue 方法中回传的一个 map 中取的,实质是 OnLoad 中 JSCJavaScriptExecutorHolder 对应,也即 java 中 JSCJavaScriptExecutor,所以 JSExecutor 实例为 JSCExecutor.cpp 中实现),如下:

//script为bundle文件内容,sourceURL为bundle文件名

void JSCExecutor::loadApplicationScript(std::unique_ptr script, std::string sourceURL) throw(JSException) {

SystraceSection s(“JSCExecutor::loadApplicationScript”,

“sourceURL”, sourceURL);

//把bundle文件和文件名等内容转换成js可以识别的String

String jsScript = jsStringFromBigString(*script);

String jsSourceURL(sourceURL.c_str());

//使用webkit JSC去真正解释执行Javascript了!

evaluateScript(m_context, jsScript, jsSourceURL);

//绑定桥,核心是通过getGlobalObject将JS与C++通过webkit JSC bind

bindBridge();

flush();

}

去他大爷的,没完没了了,继续看看 bindBridge() 方法和 flush() 方法,如下:

void JSCExecutor::bindBridge() throw(JSException) {

auto global = Object::getGlobalObject(m_context);

auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");

auto batchedBridge = batchedBridgeValue.asObject();

m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty(“callFunctionReturnFlushedQueue”).asObject();

m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty(“invokeCallbackAndReturnFlushedQueue”).asObject();

//通过webkit JSC获取MessageQueue.js的flushedQueue

m_flushedQueueJS = batchedBridge.getProperty(“flushedQueue”).asObject();

m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty(“callFunctionReturnResultAndFlushedQueue”).asObject();

}

void JSCExecutor::flush() {

SystraceSection s(“JSCExecutor::flush”);

//m_flushedQueueJS->callAsFunction({})即调用MessageQueue.js的flushedQueue方法。

//即把JS端相关通信交互数据通过flushedQueue返回传给callNativeModules。

callNativeModules(m_flushedQueueJS->callAsFunction({}));

}

void JSCExecutor::callNativeModules(Value&& value) {

SystraceSection s(“JSCExecutor::callNativeModules”);

try {

//把JS端相关通信数据转为JSON格式字符串数据

auto calls = value.toJSONString();

//m_delegate实质为Executor.h中ExecutorDelegate类的实现类JsToNativeBridge对象。

/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值