@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对象。
/