Add ability to load “unbundles” to android

Summary:
public

This adds the ability to load “unbundles” in RN android apps. Unbundles are created by invoking the packager with the `unbundle` command rather than `bundle`.

The code detects usage of an “unbundle” by checking for the existence of a specific asset.

Reviewed By: astreet

Differential Revision: D2739596

fb-gh-sync-id: d0813c003fe0fa7b47798b970f56707079bfa5d7
This commit is contained in:
David Aurelio 2016-01-21 13:57:32 -08:00 committed by facebook-github-bot-3
parent 0963192b18
commit 17e1ceb543
18 changed files with 313 additions and 27 deletions

View File

@ -9,6 +9,7 @@ LOCAL_SRC_FILES := \
JSCExecutor.cpp \ JSCExecutor.cpp \
JSCHelpers.cpp \ JSCHelpers.cpp \
JSCWebWorker.cpp \ JSCWebWorker.cpp \
JSModulesUnbundle.cpp \
MethodCall.cpp \ MethodCall.cpp \
Value.cpp \ Value.cpp \

View File

@ -27,6 +27,13 @@ public:
m_jsExecutor->executeApplicationScript(script, sourceURL); m_jsExecutor->executeApplicationScript(script, sourceURL);
} }
void loadApplicationUnbundle(
JSModulesUnbundle&& unbundle,
const std::string& startupCode,
const std::string& sourceURL) {
m_jsExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
}
void flush() { void flush() {
auto returnedJSON = m_jsExecutor->flush(); auto returnedJSON = m_jsExecutor->flush();
m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */); m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
@ -95,6 +102,13 @@ void Bridge::executeApplicationScript(const std::string& script, const std::stri
m_threadState->executeApplicationScript(script, sourceURL); m_threadState->executeApplicationScript(script, sourceURL);
} }
void Bridge::loadApplicationUnbundle(
JSModulesUnbundle&& unbundle,
const std::string& startupCode,
const std::string& sourceURL) {
m_threadState->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
}
void Bridge::flush() { void Bridge::flush() {
if (*m_destroyed) { if (*m_destroyed) {
return; return;

View File

@ -11,6 +11,7 @@
#include "Value.h" #include "Value.h"
#include "Executor.h" #include "Executor.h"
#include "MethodCall.h" #include "MethodCall.h"
#include "JSModulesUnbundle.h"
namespace folly { namespace folly {
@ -45,7 +46,20 @@ public:
*/ */
void invokeCallback(const double callbackId, const folly::dynamic& args); void invokeCallback(const double callbackId, const folly::dynamic& args);
/**
* Starts the JS application from an "bundle", i.e. a JavaScript file that
* contains code for all modules and a runtime that resolves and
* executes modules.
*/
void executeApplicationScript(const std::string& script, const std::string& sourceURL); void executeApplicationScript(const std::string& script, const std::string& sourceURL);
/**
* Starts the JS application from an "unbundle", i.e. a backend that stores
* and injects each module as individual file.
*/
void loadApplicationUnbundle(
JSModulesUnbundle&& unbundle,
const std::string& startupCode,
const std::string& sourceURL);
void setGlobalVariable(const std::string& propName, const std::string& jsonValue); void setGlobalVariable(const std::string& propName, const std::string& jsonValue);
bool supportsProfiling(); bool supportsProfiling();
void startProfiler(const std::string& title); void startProfiler(const std::string& title);

View File

@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <jni/Countable.h> #include <jni/Countable.h>
#include "JSModulesUnbundle.h"
namespace folly { namespace folly {
@ -35,6 +36,14 @@ public:
const std::string& script, const std::string& script,
const std::string& sourceURL) = 0; const std::string& sourceURL) = 0;
/**
* Add an application "unbundle" file
*/
virtual void loadApplicationUnbundle(
JSModulesUnbundle&& bundle,
const std::string& startupCode,
const std::string& sourceURL) = 0;
/** /**
* Executes BatchedBridge.flushedQueue in JS to get the next queue of changes. * Executes BatchedBridge.flushedQueue in JS to get the next queue of changes.
*/ */

View File

@ -14,6 +14,7 @@
#include "Value.h" #include "Value.h"
#include "jni/JMessageQueueThread.h" #include "jni/JMessageQueueThread.h"
#include "jni/OnLoad.h" #include "jni/OnLoad.h"
#include <react/JSCHelpers.h>
#ifdef WITH_JSC_EXTRA_TRACING #ifdef WITH_JSC_EXTRA_TRACING
#include <react/JSCTracing.h> #include <react/JSCTracing.h>
@ -152,12 +153,24 @@ void JSCExecutor::executeApplicationScript(
env->DeleteLocalRef(startStringMarker); env->DeleteLocalRef(startStringMarker);
env->DeleteLocalRef(endStringMarker); env->DeleteLocalRef(endStringMarker);
String jsSourceURL(sourceURL.c_str());
#ifdef WITH_FBSYSTRACE #ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor::executeApplicationScript", FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor::executeApplicationScript",
"sourceURL", sourceURL); "sourceURL", sourceURL);
#endif #endif
evaluateScript(m_context, jsScript, jsSourceURL); evaluateScript(m_context, jsScript, String(sourceURL.c_str()));
}
void JSCExecutor::loadApplicationUnbundle(
JSModulesUnbundle&& unbundle,
const std::string& startupCode,
const std::string& sourceURL) {
m_unbundle = std::move(unbundle);
if (!m_isUnbundleInitialized) {
m_isUnbundleInitialized = true;
installGlobalFunction(m_context, "nativeRequire", nativeRequire);
}
executeApplicationScript(startupCode, sourceURL);
} }
std::string JSCExecutor::flush() { std::string JSCExecutor::flush() {
@ -238,6 +251,13 @@ void JSCExecutor::flushQueueImmediate(std::string queueJSON) {
m_flushImmediateCallback(queueJSON, false); m_flushImmediateCallback(queueJSON, false);
} }
void JSCExecutor::loadModule(uint32_t moduleId) {
auto module = m_unbundle.getModule(moduleId);
auto sourceUrl = String::createExpectingAscii(module.name);
auto source = String::createExpectingAscii(module.code);
evaluateScript(m_context, source, sourceUrl);
}
// WebWorker impl // WebWorker impl
JSGlobalContextRef JSCExecutor::getContext() { JSGlobalContextRef JSCExecutor::getContext() {
@ -287,12 +307,55 @@ void JSCExecutor::terminateWebWorker(int workerId) {
m_webWorkerJSObjs.erase(workerId); m_webWorkerJSObjs.erase(workerId);
} }
// Native JS hooks
static JSValueRef makeInvalidModuleIdJSCException(
JSContextRef ctx,
const JSValueRef id,
JSValueRef *exception) {
std::string message = "Received invalid module ID: ";
message += String::adopt(JSValueToStringCopy(ctx, id, exception)).str();
return makeJSCException(ctx, message.c_str());
}
JSValueRef JSCExecutor::nativeRequire(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception) {
if (argumentCount != 1) {
*exception = makeJSCException(ctx, "Got wrong number of args");
return JSValueMakeUndefined(ctx);
}
JSCExecutor *executor;
try {
executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx));
} catch (std::out_of_range& e) {
*exception = makeJSCException(ctx, "Global JS context didn't map to a valid executor");
return JSValueMakeUndefined(ctx);
}
double moduleId = JSValueToNumber(ctx, arguments[0], exception);
if (moduleId <= (double) UINT32_MAX && moduleId >= 0.0) {
try {
executor->loadModule(moduleId);
} catch (JSModulesUnbundle::ModuleNotFound&) {
*exception = makeInvalidModuleIdJSCException(ctx, arguments[0], exception);
}
} else {
*exception = makeInvalidModuleIdJSCException(ctx, arguments[0], exception);
}
return JSValueMakeUndefined(ctx);
}
static JSValueRef createErrorString(JSContextRef ctx, const char *msg) { static JSValueRef createErrorString(JSContextRef ctx, const char *msg) {
return JSValueMakeString(ctx, String(msg)); return JSValueMakeString(ctx, String(msg));
} }
// Native JS hooks
static JSValueRef nativeFlushQueueImmediate( static JSValueRef nativeFlushQueueImmediate(
JSContextRef ctx, JSContextRef ctx,
JSObjectRef function, JSObjectRef function,

View File

@ -2,6 +2,7 @@
#pragma once #pragma once
#include <cstdint>
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include <JavaScriptCore/JSContextRef.h> #include <JavaScriptCore/JSContextRef.h>
@ -30,6 +31,10 @@ public:
virtual void executeApplicationScript( virtual void executeApplicationScript(
const std::string& script, const std::string& script,
const std::string& sourceURL) override; const std::string& sourceURL) override;
virtual void loadApplicationUnbundle(
JSModulesUnbundle&& unbundle,
const std::string& startupCode,
const std::string& sourceURL) override;
virtual std::string flush() override; virtual std::string flush() override;
virtual std::string callFunction( virtual std::string callFunction(
const double moduleId, const double moduleId,
@ -59,10 +64,13 @@ private:
std::unordered_map<int, JSCWebWorker> m_webWorkers; std::unordered_map<int, JSCWebWorker> m_webWorkers;
std::unordered_map<int, Object> m_webWorkerJSObjs; std::unordered_map<int, Object> m_webWorkerJSObjs;
std::shared_ptr<JMessageQueueThread> m_messageQueueThread; std::shared_ptr<JMessageQueueThread> m_messageQueueThread;
JSModulesUnbundle m_unbundle;
bool m_isUnbundleInitialized = false;
int addWebWorker(const std::string& script, JSValueRef workerRef); int addWebWorker(const std::string& script, JSValueRef workerRef);
void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn); void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
void terminateWebWorker(int worker); void terminateWebWorker(int worker);
void loadModule(uint32_t moduleId);
static JSValueRef nativeStartWorker( static JSValueRef nativeStartWorker(
JSContextRef ctx, JSContextRef ctx,
@ -85,6 +93,13 @@ private:
size_t argumentCount, size_t argumentCount,
const JSValueRef arguments[], const JSValueRef arguments[],
JSValueRef *exception); JSValueRef *exception);
static JSValueRef nativeRequire(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception);
}; };
} } } }

View File

@ -41,13 +41,14 @@ JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef
FBLOGE("Got JS Exception: %s", exceptionText.c_str()); FBLOGE("Got JS Exception: %s", exceptionText.c_str());
auto line = exception.asObject().getProperty("line"); auto line = exception.asObject().getProperty("line");
std::ostringstream lineInfo; std::ostringstream locationInfo;
std::string file = String::adopt(source).str();
locationInfo << "(" << (file.length() ? file : "<unknown file>");
if (line != nullptr && line.isNumber()) { if (line != nullptr && line.isNumber()) {
lineInfo << " (line " << line.asInteger() << " in the generated bundle)"; locationInfo << ":" << line.asInteger();
} else {
lineInfo << " (no line info)";
} }
throwJSExecutionException("%s%s", exceptionText.c_str(), lineInfo.str().c_str()); locationInfo << ")";
throwJSExecutionException("%s %s", exceptionText.c_str(), locationInfo.str().c_str());
} }
return result; return result;
} }

View File

@ -8,8 +8,6 @@
#define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__) #define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__)
#define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__)
namespace facebook { namespace facebook {
namespace react { namespace react {

View File

@ -0,0 +1,94 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "JSModulesUnbundle.h"
#include <cstdint>
#include <fb/assert.h>
#include <libgen.h>
#include <memory>
#include <sstream>
#include <sys/endian.h>
#include <utility>
using magic_number_t = uint32_t;
const magic_number_t MAGIC_FILE_HEADER = 0xFB0BD1E5;
const std::string MAGIC_FILE_NAME = "UNBUNDLE";
namespace facebook {
namespace react {
using asset_ptr =
std::unique_ptr<AAsset, std::function<decltype(AAsset_close)>>;
static std::string jsModulesDir(const std::string& entryFile) {
std::string dir = dirname(entryFile.c_str());
// android's asset manager does not work with paths that start with a dot
return dir == "." ? "js-modules/" : dir + "/js-modules/";
}
static asset_ptr openAsset(
AAssetManager *manager,
const std::string& fileName,
int mode = AASSET_MODE_STREAMING) {
return asset_ptr(
AAssetManager_open(manager, fileName.c_str(), mode),
AAsset_close);
}
JSModulesUnbundle::JSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile) :
m_assetManager(assetManager),
m_moduleDirectory(jsModulesDir(entryFile)) {}
JSModulesUnbundle::JSModulesUnbundle(JSModulesUnbundle&& other) noexcept {
*this = std::move(other);
}
JSModulesUnbundle& JSModulesUnbundle::operator= (JSModulesUnbundle&& other) noexcept {
std::swap(m_assetManager, other.m_assetManager);
std::swap(m_moduleDirectory, other.m_moduleDirectory);
return *this;
}
bool JSModulesUnbundle::isUnbundle(
AAssetManager *assetManager,
const std::string& assetName) {
if (!assetManager) {
return false;
}
auto magicFileName = jsModulesDir(assetName) + MAGIC_FILE_NAME;
auto asset = openAsset(assetManager, magicFileName.c_str());
if (asset == nullptr) {
return false;
}
magic_number_t fileHeader = 0;
AAsset_read(asset.get(), &fileHeader, sizeof(fileHeader));
return fileHeader == htole32(MAGIC_FILE_HEADER);
}
JSModulesUnbundle::Module JSModulesUnbundle::getModule(uint32_t moduleId) const {
// can be nullptr for default constructor.
FBASSERTMSGF(m_assetManager != nullptr, "Unbundle has not been initialized with an asset manager");
std::ostringstream sourceUrlBuilder;
sourceUrlBuilder << moduleId << ".js";
auto sourceUrl = sourceUrlBuilder.str();
auto fileName = m_moduleDirectory + sourceUrl;
auto asset = openAsset(m_assetManager, fileName, AASSET_MODE_BUFFER);
const char *buffer = nullptr;
if (asset != nullptr) {
buffer = static_cast<const char *>(AAsset_getBuffer(asset.get()));
}
if (buffer == nullptr) {
throw ModuleNotFound("Module not found: " + sourceUrl);
}
return {sourceUrl, std::string(buffer, AAsset_getLength(asset.get()))};
}
}
}

View File

@ -0,0 +1,48 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <android/asset_manager.h>
#include <cstdint>
#include <fb/noncopyable.h>
#include <string>
#include <stdexcept>
namespace facebook {
namespace react {
class JSModulesUnbundle : noncopyable {
/**
* Represents the set of JavaScript modules that the application consists of.
* The source code of each module can be retrieved by module ID.
* This implementation reads modules as single file from the assets of an apk.
*
* The class is non-copyable because copying instances might involve copying
* several megabytes of memory.
*/
public:
class ModuleNotFound : public std::out_of_range {
using std::out_of_range::out_of_range;
};
struct Module {
std::string name;
std::string code;
};
JSModulesUnbundle() = default;
JSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile);
JSModulesUnbundle(JSModulesUnbundle&& other) noexcept;
JSModulesUnbundle& operator= (JSModulesUnbundle&& other) noexcept;
static bool isUnbundle(
AAssetManager *assetManager,
const std::string& assetName);
Module getModule(uint32_t moduleId) const;
private:
AAssetManager *m_assetManager = nullptr;
std::string m_moduleDirectory;
};
}
}

View File

@ -3,7 +3,6 @@
#include "Value.h" #include "Value.h"
#include <jni/fbjni.h> #include <jni/fbjni.h>
#include <fb/log.h>
#include "JSCHelpers.h" #include "JSCHelpers.h"

View File

@ -2,7 +2,6 @@
#include "JSLoader.h" #include "JSLoader.h"
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h> #include <android/asset_manager_jni.h>
#include <jni/Environment.h> #include <jni/Environment.h>
#include <fstream> #include <fstream>
@ -10,7 +9,6 @@
#include <streambuf> #include <streambuf>
#include <string> #include <string>
#include <fb/log.h> #include <fb/log.h>
#ifdef WITH_FBSYSTRACE #ifdef WITH_FBSYSTRACE
#include <fbsystrace.h> #include <fbsystrace.h>
using fbsystrace::FbSystraceSection; using fbsystrace::FbSystraceSection;
@ -29,19 +27,16 @@ std::string loadScriptFromAssets(std::string assetName) {
gApplicationHolderClass, gApplicationHolderClass,
gGetApplicationMethod); gGetApplicationMethod);
jobject assetManager = env->CallObjectMethod(application, gGetAssetManagerMethod); jobject assetManager = env->CallObjectMethod(application, gGetAssetManagerMethod);
return loadScriptFromAssets(env, assetManager, assetName); return loadScriptFromAssets(AAssetManager_fromJava(env, assetManager), assetName);
} }
std::string loadScriptFromAssets( std::string loadScriptFromAssets(
JNIEnv *env, AAssetManager *manager,
jobject assetManager,
std::string assetName) { std::string assetName) {
#ifdef WITH_FBSYSTRACE #ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromAssets", FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromAssets",
"assetName", assetName); "assetName", assetName);
#endif #endif
auto manager = AAssetManager_fromJava(env, assetManager);
if (manager) { if (manager) {
auto asset = AAssetManager_open( auto asset = AAssetManager_open(
manager, manager,
@ -90,7 +85,7 @@ void registerJSLoaderNatives() {
jclass applicationHolderClass = env->FindClass("com/facebook/react/common/ApplicationHolder"); jclass applicationHolderClass = env->FindClass("com/facebook/react/common/ApplicationHolder");
gApplicationHolderClass = (jclass)env->NewGlobalRef(applicationHolderClass); gApplicationHolderClass = (jclass)env->NewGlobalRef(applicationHolderClass);
gGetApplicationMethod = env->GetStaticMethodID(applicationHolderClass, "getApplication", "()Landroid/app/Application;"); gGetApplicationMethod = env->GetStaticMethodID(applicationHolderClass, "getApplication", "()Landroid/app/Application;");
jclass appClass = env->FindClass("android/app/Application"); jclass appClass = env->FindClass("android/app/Application");
gGetAssetManagerMethod = env->GetMethodID(appClass, "getAssets", "()Landroid/content/res/AssetManager;"); gGetAssetManagerMethod = env->GetMethodID(appClass, "getAssets", "()Landroid/content/res/AssetManager;");
} }

View File

@ -2,6 +2,7 @@
#pragma once #pragma once
#include <android/asset_manager.h>
#include <string> #include <string>
#include <jni.h> #include <jni.h>
@ -17,7 +18,7 @@ std::string loadScriptFromAssets(std::string assetName);
/** /**
* Helper method for loading JS script from android asset * Helper method for loading JS script from android asset
*/ */
std::string loadScriptFromAssets(JNIEnv *env, jobject assetManager, std::string assetName); std::string loadScriptFromAssets(AAssetManager *assetManager, std::string assetName);
/** /**
* Helper method for loading JS script from a file * Helper method for loading JS script from a file

View File

@ -1,5 +1,6 @@
// Copyright 2004-present Facebook. All Rights Reserved. // Copyright 2004-present Facebook. All Rights Reserved.
#include <android/asset_manager_jni.h>
#include <android/input.h> #include <android/input.h>
#include <fb/log.h> #include <fb/log.h>
#include <folly/json.h> #include <folly/json.h>
@ -13,6 +14,7 @@
#include <react/Bridge.h> #include <react/Bridge.h>
#include <react/Executor.h> #include <react/Executor.h>
#include <react/JSCExecutor.h> #include <react/JSCExecutor.h>
#include <react/JSModulesUnbundle.h>
#include "JNativeRunnable.h" #include "JNativeRunnable.h"
#include "JSLoader.h" #include "JSLoader.h"
#include "ReadableNativeArray.h" #include "ReadableNativeArray.h"
@ -643,15 +645,33 @@ static void executeApplicationScript(
} }
} }
static void loadApplicationUnbundle(
const RefPtr<Bridge>& bridge,
AAssetManager *assetManager,
const std::string& startupCode,
const std::string& startupFileName) {
try {
// Load the application unbundle and collect/dispatch any native calls that might have occured
bridge->loadApplicationUnbundle(
JSModulesUnbundle(assetManager, startupFileName),
startupCode,
startupFileName);
bridge->flush();
} catch (...) {
translatePendingCppExceptionToJavaException();
}
}
static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager, static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
jstring assetName) { jstring assetName) {
jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker"); jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
auto manager = AAssetManager_fromJava(env, assetManager);
auto bridge = extractRefPtr<Bridge>(env, obj); auto bridge = extractRefPtr<Bridge>(env, obj);
auto assetNameStr = fromJString(env, assetName); auto assetNameStr = fromJString(env, assetName);
env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_start")); env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_start"));
auto script = react::loadScriptFromAssets(env, assetManager, assetNameStr); auto script = react::loadScriptFromAssets(manager, assetNameStr);
#ifdef WITH_FBSYSTRACE #ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_" FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_"
"executeApplicationScript", "executeApplicationScript",
@ -659,7 +679,11 @@ static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
#endif #endif
env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_read")); env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_read"));
executeApplicationScript(bridge, script, assetNameStr); if (JSModulesUnbundle::isUnbundle(manager, assetNameStr)) {
loadApplicationUnbundle(bridge, manager, script, assetNameStr);
} else {
executeApplicationScript(bridge, script, assetNameStr);
}
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
return; return;
} }

View File

@ -2,6 +2,7 @@
#include "ProxyExecutor.h" #include "ProxyExecutor.h"
#include <fb/assert.h>
#include <jni/Environment.h> #include <jni/Environment.h>
#include <jni/LocalReference.h> #include <jni/LocalReference.h>
#include <jni/LocalString.h> #include <jni/LocalString.h>
@ -50,6 +51,11 @@ void ProxyExecutor::executeApplicationScript(
jni::make_jstring(sourceURL).get()); jni::make_jstring(sourceURL).get());
} }
void ProxyExecutor::loadApplicationUnbundle(JSModulesUnbundle&&, const std::string&, const std::string&) {
jni::throwNewJavaException(
"java/lang/UnsupportedOperationException",
"Loading application unbundles is not supported for proxy executors");
}
std::string ProxyExecutor::flush() { std::string ProxyExecutor::flush() {
return executeJSCallWithProxy(m_executor.get(), "flushedQueue", std::vector<folly::dynamic>()); return executeJSCallWithProxy(m_executor.get(), "flushedQueue", std::vector<folly::dynamic>());

View File

@ -32,6 +32,10 @@ public:
virtual void executeApplicationScript( virtual void executeApplicationScript(
const std::string& script, const std::string& script,
const std::string& sourceURL) override; const std::string& sourceURL) override;
virtual void loadApplicationUnbundle(
JSModulesUnbundle&& bundle,
const std::string& startupCode,
const std::string& sourceURL) override;
virtual std::string flush() override; virtual std::string flush() override;
virtual std::string callFunction( virtual std::string callFunction(
const double moduleId, const double moduleId,

View File

@ -76,7 +76,7 @@ function uInt32Buffer(n) {
function buildModuleTable(buffers) { function buildModuleTable(buffers) {
// table format: // table format:
// - table_length: uint_32 length of all table entries in bytes // - table_length: uint_32 length of all table entries in bytes + the table length itself
// - entries: entry... // - entries: entry...
// //
// entry: // entry:

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const {ErrorUtils, __nativeRequire} = global; const {ErrorUtils, nativeRequire} = global;
global.require = require; global.require = require;
global.__d = define; global.__d = define;
@ -32,7 +32,7 @@ function guardedLoadModule(moduleId, module) {
function loadModuleImplementation(moduleId, module) { function loadModuleImplementation(moduleId, module) {
if (!module) { if (!module) {
__nativeRequire(moduleId); nativeRequire(moduleId);
module = modules[moduleId]; module = modules[moduleId];
} }