Closed
47 changes: 33 additions & 14 deletions React/CxxBridge/RCTCxxBridge.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -384,7 +384,7 @@ - (void)start
dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
RCTCxxBridge *strongSelf = weakSelf;
if (sourceCode && strongSelf.loading) {
[strongSelf executeSourceCode:sourceCode sync:NO];
[strongSelf executeSourceCode:sourceCode bundleId:0 sync:NO];
}
});
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
Expand DownExpand Up@@ -880,7 +880,7 @@ - (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
[_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
}

- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
- (void)executeSourceCode:(NSData *)sourceCode bundleId:(int)bundleId sync:(BOOL)sync
{
// This will get called from whatever thread was actually executing JS.
dispatch_block_t completion = ^{
Expand All@@ -905,10 +905,10 @@ - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
};

if (sync) {
[self executeApplicationScriptSync:sourceCode url:self.bundleURL];
[self executeApplicationScriptSync:sourceCode url:self.bundleURL bundleId:bundleId];
completion();
} else {
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
[self enqueueApplicationScript:sourceCode url:self.bundleURL bundleId:bundleId onComplete:completion];
}

if (self.devSettings.isHotLoadingAvailable) {
Expand DownExpand Up@@ -1292,11 +1292,12 @@ - (void)_immediatelyCallTimer:(NSNumber *)timer

- (void)enqueueApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
onComplete:(dispatch_block_t)onComplete
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);

[self executeApplicationScript:script url:url async:YES];
[self executeApplicationScript:script url:url bundleId:bundleId async:YES];

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

Expand All@@ -1307,13 +1308,14 @@ - (void)enqueueApplicationScript:(NSData *)script
}
}

- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url
- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url bundleId:(uint32_t)bundleId
{
[self executeApplicationScript:script url:url async:NO];
[self executeApplicationScript:script url:url bundleId:bundleId async:NO];
}

- (void)executeApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
async:(BOOL)async
{
[self _tryAndHandleError:^{
Expand All@@ -1328,25 +1330,42 @@ - (void)executeApplicationScript:(NSData *)script
[self->_performanceLogger markStopForTag:RCTPLRAMBundleLoad];
[self->_performanceLogger setValue:scriptStr->size() forTag:RCTPLRAMStartupCodeSize];
if (self->_reactInstance) {
auto registry = RAMBundleRegistry::multipleBundlesRegistry(std::move(ramBundle), JSIndexedRAMBundle::buildFactory());
self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr),
sourceUrlStr.UTF8String, !async);
self->_reactInstance->loadRAMBundle(std::move(ramBundle), std::move(scriptStr),
sourceUrlStr.UTF8String, bundleId, !async);
}
} else if (self->_reactInstance) {
self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async);
} else {
std::string methodName = async ? "loadApplicationScript" : "loadApplicationScriptSync";
std::string methodName = async ? "loadBundle" : "loadBundleSync";
throw std::logic_error("Attempt to call " + methodName + ": on uninitialized bridge");
}
}];
}

- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
{
if (_reactInstance) {
_reactInstance->registerBundle(static_cast<uint32_t>(segmentId), path.UTF8String);
}
__weak RCTCxxBridge *weakSelf = self;
NSURL *pathURL = [NSURL URLWithString:path];
dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[RCTJavaScriptLoader loadBundleAtURL:pathURL onProgress:^(RCTLoadingProgress *progressData) {} onComplete:^(NSError *error, RCTSource *source) {
if (error) {
[weakSelf handleError:error];
return;
}

NSData *sourceCode = source.data;
__strong RCTCxxBridge *strongSelf = weakSelf;
if (strongSelf->_reactInstance) {
[strongSelf executeApplicationScript:sourceCode url:pathURL bundleId:segmentId async:YES];
}
dispatch_group_leave(group);

}];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

#pragma mark - Payload Processing
Expand Down
8 changes: 6 additions & 2 deletions React/CxxBridge/RCTObjcExecutor.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -74,7 +74,11 @@
std::make_unique<JSBigStdString>(folly::toJson(config)));
}

void loadApplicationScript(
void initializeRuntime() {
// We do nothing here since initialization is done in the constructor
}

void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override {
RCTProfileBeginFlowEvent();
Expand All@@ -97,7 +101,7 @@ void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

void registerBundle(uint32_t __unused bundleId, const std::string __unused &bundlePath) override {
void registerBundle(uint32_t __unused bundleId, std::unique_ptr<JSModulesUnbundle> __unused) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -230,26 +230,26 @@ public void registerSegment(int segmentId, String path) {

@Override
public void loadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
jniLoadScriptFromAssets(assetManager, assetURL, bundleId, loadSynchronously);
}

@Override
public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
public void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
jniLoadScriptFromFile(fileName, sourceURL, bundleId, loadSynchronously);
}

private native void jniSetSourceURL(String sourceURL);

private native void jniRegisterSegment(int segmentId, String path);

private native void jniLoadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously);
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

private native void jniLoadScriptFromFile(
String fileName, String sourceURL, boolean loadSynchronously);
String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

@Override
public void runJSBundle() {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ public static JSBundleLoader createAssetLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, 0, loadSynchronously);
return assetUrl;
}
};
Expand All@@ -45,7 +45,7 @@ public static JSBundleLoader createFileLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
delegate.loadScriptFromFile(fileName, assetUrl, 0, loadSynchronously);
return fileName;
}
};
Expand All@@ -64,7 +64,7 @@ public static JSBundleLoader createCachedBundleFromNetworkLoader(
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, 0, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,19 +19,21 @@ public interface JSBundleLoaderDelegate {
*
* @param assetManager
* @param assetURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
void loadScriptFromAssets(AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

/**
* Load a JS bundle from the filesystem. See {@link JSBundleLoader#createFileLoader(String)} and
* {@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}
*
* @param fileName
* @param sourceURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

/**
* This API is used in situations where the JS bundle is being executed not on the device, but on
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ public ProxyExecutorException(Throwable cause) {
* @param sourceURL url or file location from which script content was loaded
*/
@DoNotStrip
void loadApplicationScript(String sourceURL) throws ProxyExecutorException;
void loadBundle(String sourceURL) throws ProxyExecutorException;

/**
* Execute javascript method within js context
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,7 +81,7 @@ public void prepareJSRuntime(JSDebuggerCallback callback) {
}
}

public void loadApplicationScript(
public void loadBundle(
String sourceURL, HashMap<String, String> injectedObjects, JSDebuggerCallback callback) {
int requestID = mRequestID.getAndIncrement();
mCallbacks.put(requestID, callback);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -153,10 +153,10 @@ public void close() {
}

@Override
public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
public void loadBundle(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
Assertions.assertNotNull(mWebSocketClient)
.loadApplicationScript(sourceURL, mInjectedObjects, callback);
.loadBundle(sourceURL, mInjectedObjects, callback);
try {
callback.get();
} catch (Throwable cause) {
Expand All@@ -178,7 +178,7 @@ public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyE

@Override
public void setGlobalVariable(String propertyName, String jsonEncodedValue) {
// Store and use in the next loadApplicationScript() call.
// Store and use in the next loadBundle() call.
mInjectedObjects.put(propertyName, jsonEncodedValue);
}
}
9 changes: 5 additions & 4 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,6 +208,7 @@ void CatalystInstanceImpl::jniRegisterSegment(
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
int bundleId,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
Expand All@@ -216,12 +217,11 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
auto script = loadScriptFromAssets(manager, sourceURL);
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
instance_->loadRAMBundle(
std::move(registry), std::move(script), sourceURL, loadSynchronously);
std::move(bundle), std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
return;
} else if (Instance::isIndexedRAMBundle(&script)) {
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
instance_->loadRAMBundleFromString(std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
instance_->loadScriptFromString(
std::move(script), sourceURL, loadSynchronously);
Expand All@@ -231,9 +231,10 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
void CatalystInstanceImpl::jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
int bundleId,
bool loadSynchronously) {
if (Instance::isIndexedRAMBundle(fileName.c_str())) {
instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
instance_->loadRAMBundleFromFile(fileName, sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
std::unique_ptr<const JSBigFileString> script;
RecoverableError::runRethrowingAsRecoverable<std::system_error>(
Expand Down
17 changes: 8 additions & 9 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,15 +77,14 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
*
*/
void jniRegisterSegment(int segmentId, const std::string &path);

void jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
bool loadSynchronously);
void jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
bool loadSynchronously);
void jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
int bundleId,
bool loadSynchronously);
void jniLoadScriptFromFile(const std::string& fileName,
const std::string& sourceURL,
int bundleId,
bool loadSynchronously);
void jniCallJSFunction(
std::string module,
std::string method,
Expand Down
17 changes: 10 additions & 7 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,9 +53,7 @@ ProxyExecutor::~ProxyExecutor() {
m_executor.reset();
}

void ProxyExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {
void ProxyExecutor::initializeRuntime() {
folly::dynamic nativeModuleConfig = folly::dynamic::array;

{
Expand All@@ -76,14 +74,19 @@ void ProxyExecutor::loadApplicationScript(
"__fbBatchedBridgeConfig",
std::make_unique<JSBigStdString>(folly::toJson(config)));
}
}

void ProxyExecutor::loadBundle(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {

static auto loadApplicationScript =
static auto loadBundle =
jni::findClassStatic(EXECUTOR_BASECLASS)
->getMethod<void(jstring)>("loadApplicationScript");
->getMethod<void(jstring)>("loadBundle");

// The proxy ignores the script data passed in.

loadApplicationScript(m_executor.get(), jni::make_jstring(sourceURL).get());
loadBundle(m_executor.get(), jni::make_jstring(sourceURL).get());
// We can get pending calls here to native but the queue will be drained when
// we launch the application.
}
Expand All@@ -96,7 +99,7 @@ void ProxyExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) {

void ProxyExecutor::registerBundle(
uint32_t bundleId,
const std::string &bundlePath) {
std::unique_ptr<JSModulesUnbundle> bundle) {
jni::throwNewJavaException(
"java/lang/UnsupportedOperationException",
"Loading application RAM bundles is not supported for proxy executors");
Expand Down
5 changes: 3 additions & 2 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,12 +37,13 @@ class ProxyExecutor : public JSExecutor {
jni::global_ref<jobject> &&executorInstance,
std::shared_ptr<ExecutorDelegate> delegate);
virtual ~ProxyExecutor() override;
virtual void loadApplicationScript(
virtual void initializeRuntime() override;
virtual void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override;
virtual void setBundleRegistry(
std::unique_ptr<RAMBundleRegistry> bundle) override;
virtual void registerBundle(uint32_t bundleId, const std::string &bundlePath)
virtual void registerBundle(uint32_t bundleId, std::unique_ptr<JSModulesUnbundle> bundle)
override;
virtual void callFunction(
const std::string &moduleId,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ public void test_prepareJSRuntime_ShouldSendCorrectMessage() throws Exception {
}

@Test
public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Exception {
public void test_loadBundle_ShouldSendCorrectMessage() throws Exception {
final JSDebuggerWebSocketClient.JSDebuggerCallback cb =
PowerMockito.mock(JSDebuggerWebSocketClient.JSDebuggerCallback.class);

Expand All@@ -49,7 +49,7 @@ public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Excepti
injectedObjects.put("key1", "value1");
injectedObjects.put("key2", "value2");

client.loadApplicationScript("http://localhost:8080/index.js", injectedObjects, cb);
client.loadBundle("http://localhost:8080/index.js", injectedObjects, cb);
PowerMockito.verifyPrivate(client)
.invoke(
"sendMessage",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Closed
47 changes: 33 additions & 14 deletions React/CxxBridge/RCTCxxBridge.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -384,7 +384,7 @@ - (void)start
dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
RCTCxxBridge *strongSelf = weakSelf;
if (sourceCode && strongSelf.loading) {
[strongSelf executeSourceCode:sourceCode sync:NO];
[strongSelf executeSourceCode:sourceCode bundleId:0 sync:NO];
}
});
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
Expand DownExpand Up@@ -880,7 +880,7 @@ - (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
[_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
}

- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
- (void)executeSourceCode:(NSData *)sourceCode bundleId:(int)bundleId sync:(BOOL)sync
{
// This will get called from whatever thread was actually executing JS.
dispatch_block_t completion = ^{
Expand All@@ -905,10 +905,10 @@ - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
};

if (sync) {
[self executeApplicationScriptSync:sourceCode url:self.bundleURL];
[self executeApplicationScriptSync:sourceCode url:self.bundleURL bundleId:bundleId];
completion();
} else {
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
[self enqueueApplicationScript:sourceCode url:self.bundleURL bundleId:bundleId onComplete:completion];
}

if (self.devSettings.isHotLoadingAvailable) {
Expand DownExpand Up@@ -1292,11 +1292,12 @@ - (void)_immediatelyCallTimer:(NSNumber *)timer

- (void)enqueueApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
onComplete:(dispatch_block_t)onComplete
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);

[self executeApplicationScript:script url:url async:YES];
[self executeApplicationScript:script url:url bundleId:bundleId async:YES];

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

Expand All@@ -1307,13 +1308,14 @@ - (void)enqueueApplicationScript:(NSData *)script
}
}

- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url
- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url bundleId:(uint32_t)bundleId
{
[self executeApplicationScript:script url:url async:NO];
[self executeApplicationScript:script url:url bundleId:bundleId async:NO];
}

- (void)executeApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
async:(BOOL)async
{
[self _tryAndHandleError:^{
Expand All@@ -1328,25 +1330,42 @@ - (void)executeApplicationScript:(NSData *)script
[self->_performanceLogger markStopForTag:RCTPLRAMBundleLoad];
[self->_performanceLogger setValue:scriptStr->size() forTag:RCTPLRAMStartupCodeSize];
if (self->_reactInstance) {
auto registry = RAMBundleRegistry::multipleBundlesRegistry(std::move(ramBundle), JSIndexedRAMBundle::buildFactory());
self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr),
sourceUrlStr.UTF8String, !async);
self->_reactInstance->loadRAMBundle(std::move(ramBundle), std::move(scriptStr),
sourceUrlStr.UTF8String, bundleId, !async);
}
} else if (self->_reactInstance) {
self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async);
} else {
std::string methodName = async ? "loadApplicationScript" : "loadApplicationScriptSync";
std::string methodName = async ? "loadBundle" : "loadBundleSync";
throw std::logic_error("Attempt to call " + methodName + ": on uninitialized bridge");
}
}];
}

- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
{
if (_reactInstance) {
_reactInstance->registerBundle(static_cast<uint32_t>(segmentId), path.UTF8String);
}
__weak RCTCxxBridge *weakSelf = self;
NSURL *pathURL = [NSURL URLWithString:path];
dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[RCTJavaScriptLoader loadBundleAtURL:pathURL onProgress:^(RCTLoadingProgress *progressData) {} onComplete:^(NSError *error, RCTSource *source) {
if (error) {
[weakSelf handleError:error];
return;
}

NSData *sourceCode = source.data;
__strong RCTCxxBridge *strongSelf = weakSelf;
if (strongSelf->_reactInstance) {
[strongSelf executeApplicationScript:sourceCode url:pathURL bundleId:segmentId async:YES];
}
dispatch_group_leave(group);

}];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

#pragma mark - Payload Processing
Expand Down
8 changes: 6 additions & 2 deletions React/CxxBridge/RCTObjcExecutor.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -74,7 +74,11 @@
std::make_unique<JSBigStdString>(folly::toJson(config)));
}

void loadApplicationScript(
void initializeRuntime() {
// We do nothing here since initialization is done in the constructor
}

void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override {
RCTProfileBeginFlowEvent();
Expand All@@ -97,7 +101,7 @@ void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

void registerBundle(uint32_t __unused bundleId, const std::string __unused &bundlePath) override {
void registerBundle(uint32_t __unused bundleId, std::unique_ptr<JSModulesUnbundle> __unused) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -230,26 +230,26 @@ public void registerSegment(int segmentId, String path) {

@Override
public void loadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
jniLoadScriptFromAssets(assetManager, assetURL, bundleId, loadSynchronously);
}

@Override
public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
public void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
jniLoadScriptFromFile(fileName, sourceURL, bundleId, loadSynchronously);
}

private native void jniSetSourceURL(String sourceURL);

private native void jniRegisterSegment(int segmentId, String path);

private native void jniLoadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously);
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

private native void jniLoadScriptFromFile(
String fileName, String sourceURL, boolean loadSynchronously);
String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

@Override
public void runJSBundle() {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ public static JSBundleLoader createAssetLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, 0, loadSynchronously);
return assetUrl;
}
};
Expand All@@ -45,7 +45,7 @@ public static JSBundleLoader createFileLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
delegate.loadScriptFromFile(fileName, assetUrl, 0, loadSynchronously);
return fileName;
}
};
Expand All@@ -64,7 +64,7 @@ public static JSBundleLoader createCachedBundleFromNetworkLoader(
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, 0, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,19 +19,21 @@ public interface JSBundleLoaderDelegate {
*
* @param assetManager
* @param assetURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
void loadScriptFromAssets(AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

/**
* Load a JS bundle from the filesystem. See {@link JSBundleLoader#createFileLoader(String)} and
* {@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}
*
* @param fileName
* @param sourceURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

/**
* This API is used in situations where the JS bundle is being executed not on the device, but on
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ public ProxyExecutorException(Throwable cause) {
* @param sourceURL url or file location from which script content was loaded
*/
@DoNotStrip
void loadApplicationScript(String sourceURL) throws ProxyExecutorException;
void loadBundle(String sourceURL) throws ProxyExecutorException;

/**
* Execute javascript method within js context
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,7 +81,7 @@ public void prepareJSRuntime(JSDebuggerCallback callback) {
}
}

public void loadApplicationScript(
public void loadBundle(
String sourceURL, HashMap<String, String> injectedObjects, JSDebuggerCallback callback) {
int requestID = mRequestID.getAndIncrement();
mCallbacks.put(requestID, callback);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -153,10 +153,10 @@ public void close() {
}

@Override
public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
public void loadBundle(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
Assertions.assertNotNull(mWebSocketClient)
.loadApplicationScript(sourceURL, mInjectedObjects, callback);
.loadBundle(sourceURL, mInjectedObjects, callback);
try {
callback.get();
} catch (Throwable cause) {
Expand All@@ -178,7 +178,7 @@ public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyE

@Override
public void setGlobalVariable(String propertyName, String jsonEncodedValue) {
// Store and use in the next loadApplicationScript() call.
// Store and use in the next loadBundle() call.
mInjectedObjects.put(propertyName, jsonEncodedValue);
}
}
9 changes: 5 additions & 4 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,6 +208,7 @@ void CatalystInstanceImpl::jniRegisterSegment(
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
int bundleId,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
Expand All@@ -216,12 +217,11 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
auto script = loadScriptFromAssets(manager, sourceURL);
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
instance_->loadRAMBundle(
std::move(registry), std::move(script), sourceURL, loadSynchronously);
std::move(bundle), std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
return;
} else if (Instance::isIndexedRAMBundle(&script)) {
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
instance_->loadRAMBundleFromString(std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
instance_->loadScriptFromString(
std::move(script), sourceURL, loadSynchronously);
Expand All@@ -231,9 +231,10 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
void CatalystInstanceImpl::jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
int bundleId,
bool loadSynchronously) {
if (Instance::isIndexedRAMBundle(fileName.c_str())) {
instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
instance_->loadRAMBundleFromFile(fileName, sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
std::unique_ptr<const JSBigFileString> script;
RecoverableError::runRethrowingAsRecoverable<std::system_error>(
Expand Down
17 changes: 8 additions & 9 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,15 +77,14 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
*
*/
void jniRegisterSegment(int segmentId, const std::string &path);

void jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
bool loadSynchronously);
void jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
bool loadSynchronously);
void jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
int bundleId,
bool loadSynchronously);
void jniLoadScriptFromFile(const std::string& fileName,
const std::string& sourceURL,
int bundleId,
bool loadSynchronously);
void jniCallJSFunction(
std::string module,
std::string method,
Expand Down
17 changes: 10 additions & 7 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,9 +53,7 @@ ProxyExecutor::~ProxyExecutor() {
m_executor.reset();
}

void ProxyExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {
void ProxyExecutor::initializeRuntime() {
folly::dynamic nativeModuleConfig = folly::dynamic::array;

{
Expand All@@ -76,14 +74,19 @@ void ProxyExecutor::loadApplicationScript(
"__fbBatchedBridgeConfig",
std::make_unique<JSBigStdString>(folly::toJson(config)));
}
}

void ProxyExecutor::loadBundle(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {

static auto loadApplicationScript =
static auto loadBundle =
jni::findClassStatic(EXECUTOR_BASECLASS)
->getMethod<void(jstring)>("loadApplicationScript");
->getMethod<void(jstring)>("loadBundle");

// The proxy ignores the script data passed in.

loadApplicationScript(m_executor.get(), jni::make_jstring(sourceURL).get());
loadBundle(m_executor.get(), jni::make_jstring(sourceURL).get());
// We can get pending calls here to native but the queue will be drained when
// we launch the application.
}
Expand All@@ -96,7 +99,7 @@ void ProxyExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) {

void ProxyExecutor::registerBundle(
uint32_t bundleId,
const std::string &bundlePath) {
std::unique_ptr<JSModulesUnbundle> bundle) {
jni::throwNewJavaException(
"java/lang/UnsupportedOperationException",
"Loading application RAM bundles is not supported for proxy executors");
Expand Down
5 changes: 3 additions & 2 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,12 +37,13 @@ class ProxyExecutor : public JSExecutor {
jni::global_ref<jobject> &&executorInstance,
std::shared_ptr<ExecutorDelegate> delegate);
virtual ~ProxyExecutor() override;
virtual void loadApplicationScript(
virtual void initializeRuntime() override;
virtual void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override;
virtual void setBundleRegistry(
std::unique_ptr<RAMBundleRegistry> bundle) override;
virtual void registerBundle(uint32_t bundleId, const std::string &bundlePath)
virtual void registerBundle(uint32_t bundleId, std::unique_ptr<JSModulesUnbundle> bundle)
override;
virtual void callFunction(
const std::string &moduleId,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ public void test_prepareJSRuntime_ShouldSendCorrectMessage() throws Exception {
}

@Test
public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Exception {
public void test_loadBundle_ShouldSendCorrectMessage() throws Exception {
final JSDebuggerWebSocketClient.JSDebuggerCallback cb =
PowerMockito.mock(JSDebuggerWebSocketClient.JSDebuggerCallback.class);

Expand All@@ -49,7 +49,7 @@ public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Excepti
injectedObjects.put("key1", "value1");
injectedObjects.put("key2", "value2");

client.loadApplicationScript("http://localhost:8080/index.js", injectedObjects, cb);
client.loadBundle("http://localhost:8080/index.js", injectedObjects, cb);
PowerMockito.verifyPrivate(client)
.invoke(
"sendMessage",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
47 changes: 33 additions & 14 deletions React/CxxBridge/RCTCxxBridge.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -384,7 +384,7 @@ - (void)start
dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
RCTCxxBridge *strongSelf = weakSelf;
if (sourceCode && strongSelf.loading) {
[strongSelf executeSourceCode:sourceCode sync:NO];
[strongSelf executeSourceCode:sourceCode bundleId:0 sync:NO];
}
});
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
Expand DownExpand Up@@ -880,7 +880,7 @@ - (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
[_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
}

- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
- (void)executeSourceCode:(NSData *)sourceCode bundleId:(int)bundleId sync:(BOOL)sync
{
// This will get called from whatever thread was actually executing JS.
dispatch_block_t completion = ^{
Expand All@@ -905,10 +905,10 @@ - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
};

if (sync) {
[self executeApplicationScriptSync:sourceCode url:self.bundleURL];
[self executeApplicationScriptSync:sourceCode url:self.bundleURL bundleId:bundleId];
completion();
} else {
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
[self enqueueApplicationScript:sourceCode url:self.bundleURL bundleId:bundleId onComplete:completion];
}

if (self.devSettings.isHotLoadingAvailable) {
Expand DownExpand Up@@ -1292,11 +1292,12 @@ - (void)_immediatelyCallTimer:(NSNumber *)timer

- (void)enqueueApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
onComplete:(dispatch_block_t)onComplete
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);

[self executeApplicationScript:script url:url async:YES];
[self executeApplicationScript:script url:url bundleId:bundleId async:YES];

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

Expand All@@ -1307,13 +1308,14 @@ - (void)enqueueApplicationScript:(NSData *)script
}
}

- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url
- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url bundleId:(uint32_t)bundleId
{
[self executeApplicationScript:script url:url async:NO];
[self executeApplicationScript:script url:url bundleId:bundleId async:NO];
}

- (void)executeApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
async:(BOOL)async
{
[self _tryAndHandleError:^{
Expand All@@ -1328,25 +1330,42 @@ - (void)executeApplicationScript:(NSData *)script
[self->_performanceLogger markStopForTag:RCTPLRAMBundleLoad];
[self->_performanceLogger setValue:scriptStr->size() forTag:RCTPLRAMStartupCodeSize];
if (self->_reactInstance) {
auto registry = RAMBundleRegistry::multipleBundlesRegistry(std::move(ramBundle), JSIndexedRAMBundle::buildFactory());
self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr),
sourceUrlStr.UTF8String, !async);
self->_reactInstance->loadRAMBundle(std::move(ramBundle), std::move(scriptStr),
sourceUrlStr.UTF8String, bundleId, !async);
}
} else if (self->_reactInstance) {
self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async);
} else {
std::string methodName = async ? "loadApplicationScript" : "loadApplicationScriptSync";
std::string methodName = async ? "loadBundle" : "loadBundleSync";
throw std::logic_error("Attempt to call " + methodName + ": on uninitialized bridge");
}
}];
}

- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
{
if (_reactInstance) {
_reactInstance->registerBundle(static_cast<uint32_t>(segmentId), path.UTF8String);
}
__weak RCTCxxBridge *weakSelf = self;
NSURL *pathURL = [NSURL URLWithString:path];
dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[RCTJavaScriptLoader loadBundleAtURL:pathURL onProgress:^(RCTLoadingProgress *progressData) {} onComplete:^(NSError *error, RCTSource *source) {
if (error) {
[weakSelf handleError:error];
return;
}

NSData *sourceCode = source.data;
__strong RCTCxxBridge *strongSelf = weakSelf;
if (strongSelf->_reactInstance) {
[strongSelf executeApplicationScript:sourceCode url:pathURL bundleId:segmentId async:YES];
}
dispatch_group_leave(group);

}];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

#pragma mark - Payload Processing
Expand Down
8 changes: 6 additions & 2 deletions React/CxxBridge/RCTObjcExecutor.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -74,7 +74,11 @@
std::make_unique<JSBigStdString>(folly::toJson(config)));
}

void loadApplicationScript(
void initializeRuntime() {
// We do nothing here since initialization is done in the constructor
}

void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override {
RCTProfileBeginFlowEvent();
Expand All@@ -97,7 +101,7 @@ void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

void registerBundle(uint32_t __unused bundleId, const std::string __unused &bundlePath) override {
void registerBundle(uint32_t __unused bundleId, std::unique_ptr<JSModulesUnbundle> __unused) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -230,26 +230,26 @@ public void registerSegment(int segmentId, String path) {

@Override
public void loadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
jniLoadScriptFromAssets(assetManager, assetURL, bundleId, loadSynchronously);
}

@Override
public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
public void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
jniLoadScriptFromFile(fileName, sourceURL, bundleId, loadSynchronously);
}

private native void jniSetSourceURL(String sourceURL);

private native void jniRegisterSegment(int segmentId, String path);

private native void jniLoadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously);
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

private native void jniLoadScriptFromFile(
String fileName, String sourceURL, boolean loadSynchronously);
String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

@Override
public void runJSBundle() {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ public static JSBundleLoader createAssetLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, 0, loadSynchronously);
return assetUrl;
}
};
Expand All@@ -45,7 +45,7 @@ public static JSBundleLoader createFileLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
delegate.loadScriptFromFile(fileName, assetUrl, 0, loadSynchronously);
return fileName;
}
};
Expand All@@ -64,7 +64,7 @@ public static JSBundleLoader createCachedBundleFromNetworkLoader(
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, 0, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,19 +19,21 @@ public interface JSBundleLoaderDelegate {
*
* @param assetManager
* @param assetURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
void loadScriptFromAssets(AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

/**
* Load a JS bundle from the filesystem. See {@link JSBundleLoader#createFileLoader(String)} and
* {@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}
*
* @param fileName
* @param sourceURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

/**
* This API is used in situations where the JS bundle is being executed not on the device, but on
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ public ProxyExecutorException(Throwable cause) {
* @param sourceURL url or file location from which script content was loaded
*/
@DoNotStrip
void loadApplicationScript(String sourceURL) throws ProxyExecutorException;
void loadBundle(String sourceURL) throws ProxyExecutorException;

/**
* Execute javascript method within js context
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,7 +81,7 @@ public void prepareJSRuntime(JSDebuggerCallback callback) {
}
}

public void loadApplicationScript(
public void loadBundle(
String sourceURL, HashMap<String, String> injectedObjects, JSDebuggerCallback callback) {
int requestID = mRequestID.getAndIncrement();
mCallbacks.put(requestID, callback);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -153,10 +153,10 @@ public void close() {
}

@Override
public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
public void loadBundle(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
Assertions.assertNotNull(mWebSocketClient)
.loadApplicationScript(sourceURL, mInjectedObjects, callback);
.loadBundle(sourceURL, mInjectedObjects, callback);
try {
callback.get();
} catch (Throwable cause) {
Expand All@@ -178,7 +178,7 @@ public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyE

@Override
public void setGlobalVariable(String propertyName, String jsonEncodedValue) {
// Store and use in the next loadApplicationScript() call.
// Store and use in the next loadBundle() call.
mInjectedObjects.put(propertyName, jsonEncodedValue);
}
}
9 changes: 5 additions & 4 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,6 +208,7 @@ void CatalystInstanceImpl::jniRegisterSegment(
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
int bundleId,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
Expand All@@ -216,12 +217,11 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
auto script = loadScriptFromAssets(manager, sourceURL);
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
instance_->loadRAMBundle(
std::move(registry), std::move(script), sourceURL, loadSynchronously);
std::move(bundle), std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
return;
} else if (Instance::isIndexedRAMBundle(&script)) {
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
instance_->loadRAMBundleFromString(std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
instance_->loadScriptFromString(
std::move(script), sourceURL, loadSynchronously);
Expand All@@ -231,9 +231,10 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
void CatalystInstanceImpl::jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
int bundleId,
bool loadSynchronously) {
if (Instance::isIndexedRAMBundle(fileName.c_str())) {
instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
instance_->loadRAMBundleFromFile(fileName, sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
std::unique_ptr<const JSBigFileString> script;
RecoverableError::runRethrowingAsRecoverable<std::system_error>(
Expand Down
17 changes: 8 additions & 9 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,15 +77,14 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
*
*/
void jniRegisterSegment(int segmentId, const std::string &path);

void jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
bool loadSynchronously);
void jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
bool loadSynchronously);
void jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
int bundleId,
bool loadSynchronously);
void jniLoadScriptFromFile(const std::string& fileName,
const std::string& sourceURL,
int bundleId,
bool loadSynchronously);
void jniCallJSFunction(
std::string module,
std::string method,
Expand Down
17 changes: 10 additions & 7 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,9 +53,7 @@ ProxyExecutor::~ProxyExecutor() {
m_executor.reset();
}

void ProxyExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {
void ProxyExecutor::initializeRuntime() {
folly::dynamic nativeModuleConfig = folly::dynamic::array;

{
Expand All@@ -76,14 +74,19 @@ void ProxyExecutor::loadApplicationScript(
"__fbBatchedBridgeConfig",
std::make_unique<JSBigStdString>(folly::toJson(config)));
}
}

void ProxyExecutor::loadBundle(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {

static auto loadApplicationScript =
static auto loadBundle =
jni::findClassStatic(EXECUTOR_BASECLASS)
->getMethod<void(jstring)>("loadApplicationScript");
->getMethod<void(jstring)>("loadBundle");

// The proxy ignores the script data passed in.

loadApplicationScript(m_executor.get(), jni::make_jstring(sourceURL).get());
loadBundle(m_executor.get(), jni::make_jstring(sourceURL).get());
// We can get pending calls here to native but the queue will be drained when
// we launch the application.
}
Expand All@@ -96,7 +99,7 @@ void ProxyExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) {

void ProxyExecutor::registerBundle(
uint32_t bundleId,
const std::string &bundlePath) {
std::unique_ptr<JSModulesUnbundle> bundle) {
jni::throwNewJavaException(
"java/lang/UnsupportedOperationException",
"Loading application RAM bundles is not supported for proxy executors");
Expand Down
5 changes: 3 additions & 2 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,12 +37,13 @@ class ProxyExecutor : public JSExecutor {
jni::global_ref<jobject> &&executorInstance,
std::shared_ptr<ExecutorDelegate> delegate);
virtual ~ProxyExecutor() override;
virtual void loadApplicationScript(
virtual void initializeRuntime() override;
virtual void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override;
virtual void setBundleRegistry(
std::unique_ptr<RAMBundleRegistry> bundle) override;
virtual void registerBundle(uint32_t bundleId, const std::string &bundlePath)
virtual void registerBundle(uint32_t bundleId, std::unique_ptr<JSModulesUnbundle> bundle)
override;
virtual void callFunction(
const std::string &moduleId,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ public void test_prepareJSRuntime_ShouldSendCorrectMessage() throws Exception {
}

@Test
public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Exception {
public void test_loadBundle_ShouldSendCorrectMessage() throws Exception {
final JSDebuggerWebSocketClient.JSDebuggerCallback cb =
PowerMockito.mock(JSDebuggerWebSocketClient.JSDebuggerCallback.class);

Expand All@@ -49,7 +49,7 @@ public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Excepti
injectedObjects.put("key1", "value1");
injectedObjects.put("key2", "value2");

client.loadApplicationScript("http://localhost:8080/index.js", injectedObjects, cb);
client.loadBundle("http://localhost:8080/index.js", injectedObjects, cb);
PowerMockito.verifyPrivate(client)
.invoke(
"sendMessage",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
47 changes: 33 additions & 14 deletions React/CxxBridge/RCTCxxBridge.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -384,7 +384,7 @@ - (void)start
dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
RCTCxxBridge *strongSelf = weakSelf;
if (sourceCode && strongSelf.loading) {
[strongSelf executeSourceCode:sourceCode sync:NO];
[strongSelf executeSourceCode:sourceCode bundleId:0 sync:NO];
}
});
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
Expand DownExpand Up@@ -880,7 +880,7 @@ - (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
[_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
}

- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
- (void)executeSourceCode:(NSData *)sourceCode bundleId:(int)bundleId sync:(BOOL)sync
{
// This will get called from whatever thread was actually executing JS.
dispatch_block_t completion = ^{
Expand All@@ -905,10 +905,10 @@ - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
};

if (sync) {
[self executeApplicationScriptSync:sourceCode url:self.bundleURL];
[self executeApplicationScriptSync:sourceCode url:self.bundleURL bundleId:bundleId];
completion();
} else {
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
[self enqueueApplicationScript:sourceCode url:self.bundleURL bundleId:bundleId onComplete:completion];
}

if (self.devSettings.isHotLoadingAvailable) {
Expand DownExpand Up@@ -1292,11 +1292,12 @@ - (void)_immediatelyCallTimer:(NSNumber *)timer

- (void)enqueueApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
onComplete:(dispatch_block_t)onComplete
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);

[self executeApplicationScript:script url:url async:YES];
[self executeApplicationScript:script url:url bundleId:bundleId async:YES];

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

Expand All@@ -1307,13 +1308,14 @@ - (void)enqueueApplicationScript:(NSData *)script
}
}

- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url
- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url bundleId:(uint32_t)bundleId
{
[self executeApplicationScript:script url:url async:NO];
[self executeApplicationScript:script url:url bundleId:bundleId async:NO];
}

- (void)executeApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
async:(BOOL)async
{
[self _tryAndHandleError:^{
Expand All@@ -1328,25 +1330,42 @@ - (void)executeApplicationScript:(NSData *)script
[self->_performanceLogger markStopForTag:RCTPLRAMBundleLoad];
[self->_performanceLogger setValue:scriptStr->size() forTag:RCTPLRAMStartupCodeSize];
if (self->_reactInstance) {
auto registry = RAMBundleRegistry::multipleBundlesRegistry(std::move(ramBundle), JSIndexedRAMBundle::buildFactory());
self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr),
sourceUrlStr.UTF8String, !async);
self->_reactInstance->loadRAMBundle(std::move(ramBundle), std::move(scriptStr),
sourceUrlStr.UTF8String, bundleId, !async);
}
} else if (self->_reactInstance) {
self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async);
} else {
std::string methodName = async ? "loadApplicationScript" : "loadApplicationScriptSync";
std::string methodName = async ? "loadBundle" : "loadBundleSync";
throw std::logic_error("Attempt to call " + methodName + ": on uninitialized bridge");
}
}];
}

- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
{
if (_reactInstance) {
_reactInstance->registerBundle(static_cast<uint32_t>(segmentId), path.UTF8String);
}
__weak RCTCxxBridge *weakSelf = self;
NSURL *pathURL = [NSURL URLWithString:path];
dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[RCTJavaScriptLoader loadBundleAtURL:pathURL onProgress:^(RCTLoadingProgress *progressData) {} onComplete:^(NSError *error, RCTSource *source) {
if (error) {
[weakSelf handleError:error];
return;
}

NSData *sourceCode = source.data;
__strong RCTCxxBridge *strongSelf = weakSelf;
if (strongSelf->_reactInstance) {
[strongSelf executeApplicationScript:sourceCode url:pathURL bundleId:segmentId async:YES];
}
dispatch_group_leave(group);

}];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

#pragma mark - Payload Processing
Expand Down
8 changes: 6 additions & 2 deletions React/CxxBridge/RCTObjcExecutor.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -74,7 +74,11 @@
std::make_unique<JSBigStdString>(folly::toJson(config)));
}

void loadApplicationScript(
void initializeRuntime() {
// We do nothing here since initialization is done in the constructor
}

void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override {
RCTProfileBeginFlowEvent();
Expand All@@ -97,7 +101,7 @@ void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

void registerBundle(uint32_t __unused bundleId, const std::string __unused &bundlePath) override {
void registerBundle(uint32_t __unused bundleId, std::unique_ptr<JSModulesUnbundle> __unused) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -230,26 +230,26 @@ public void registerSegment(int segmentId, String path) {

@Override
public void loadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
jniLoadScriptFromAssets(assetManager, assetURL, bundleId, loadSynchronously);
}

@Override
public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
public void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
jniLoadScriptFromFile(fileName, sourceURL, bundleId, loadSynchronously);
}

private native void jniSetSourceURL(String sourceURL);

private native void jniRegisterSegment(int segmentId, String path);

private native void jniLoadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously);
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

private native void jniLoadScriptFromFile(
String fileName, String sourceURL, boolean loadSynchronously);
String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

@Override
public void runJSBundle() {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ public static JSBundleLoader createAssetLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, 0, loadSynchronously);
return assetUrl;
}
};
Expand All@@ -45,7 +45,7 @@ public static JSBundleLoader createFileLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
delegate.loadScriptFromFile(fileName, assetUrl, 0, loadSynchronously);
return fileName;
}
};
Expand All@@ -64,7 +64,7 @@ public static JSBundleLoader createCachedBundleFromNetworkLoader(
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, 0, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,19 +19,21 @@ public interface JSBundleLoaderDelegate {
*
* @param assetManager
* @param assetURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
void loadScriptFromAssets(AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

/**
* Load a JS bundle from the filesystem. See {@link JSBundleLoader#createFileLoader(String)} and
* {@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}
*
* @param fileName
* @param sourceURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

/**
* This API is used in situations where the JS bundle is being executed not on the device, but on
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ public ProxyExecutorException(Throwable cause) {
* @param sourceURL url or file location from which script content was loaded
*/
@DoNotStrip
void loadApplicationScript(String sourceURL) throws ProxyExecutorException;
void loadBundle(String sourceURL) throws ProxyExecutorException;

/**
* Execute javascript method within js context
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,7 +81,7 @@ public void prepareJSRuntime(JSDebuggerCallback callback) {
}
}

public void loadApplicationScript(
public void loadBundle(
String sourceURL, HashMap<String, String> injectedObjects, JSDebuggerCallback callback) {
int requestID = mRequestID.getAndIncrement();
mCallbacks.put(requestID, callback);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -153,10 +153,10 @@ public void close() {
}

@Override
public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
public void loadBundle(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
Assertions.assertNotNull(mWebSocketClient)
.loadApplicationScript(sourceURL, mInjectedObjects, callback);
.loadBundle(sourceURL, mInjectedObjects, callback);
try {
callback.get();
} catch (Throwable cause) {
Expand All@@ -178,7 +178,7 @@ public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyE

@Override
public void setGlobalVariable(String propertyName, String jsonEncodedValue) {
// Store and use in the next loadApplicationScript() call.
// Store and use in the next loadBundle() call.
mInjectedObjects.put(propertyName, jsonEncodedValue);
}
}
9 changes: 5 additions & 4 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,6 +208,7 @@ void CatalystInstanceImpl::jniRegisterSegment(
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
int bundleId,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
Expand All@@ -216,12 +217,11 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
auto script = loadScriptFromAssets(manager, sourceURL);
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
instance_->loadRAMBundle(
std::move(registry), std::move(script), sourceURL, loadSynchronously);
std::move(bundle), std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
return;
} else if (Instance::isIndexedRAMBundle(&script)) {
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
instance_->loadRAMBundleFromString(std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
instance_->loadScriptFromString(
std::move(script), sourceURL, loadSynchronously);
Expand All@@ -231,9 +231,10 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
void CatalystInstanceImpl::jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
int bundleId,
bool loadSynchronously) {
if (Instance::isIndexedRAMBundle(fileName.c_str())) {
instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
instance_->loadRAMBundleFromFile(fileName, sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
std::unique_ptr<const JSBigFileString> script;
RecoverableError::runRethrowingAsRecoverable<std::system_error>(
Expand Down
17 changes: 8 additions & 9 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,15 +77,14 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
*
*/
void jniRegisterSegment(int segmentId, const std::string &path);

void jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
bool loadSynchronously);
void jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
bool loadSynchronously);
void jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
int bundleId,
bool loadSynchronously);
void jniLoadScriptFromFile(const std::string& fileName,
const std::string& sourceURL,
int bundleId,
bool loadSynchronously);
void jniCallJSFunction(
std::string module,
std::string method,
Expand Down
17 changes: 10 additions & 7 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,9 +53,7 @@ ProxyExecutor::~ProxyExecutor() {
m_executor.reset();
}

void ProxyExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {
void ProxyExecutor::initializeRuntime() {
folly::dynamic nativeModuleConfig = folly::dynamic::array;

{
Expand All@@ -76,14 +74,19 @@ void ProxyExecutor::loadApplicationScript(
"__fbBatchedBridgeConfig",
std::make_unique<JSBigStdString>(folly::toJson(config)));
}
}

void ProxyExecutor::loadBundle(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {

static auto loadApplicationScript =
static auto loadBundle =
jni::findClassStatic(EXECUTOR_BASECLASS)
->getMethod<void(jstring)>("loadApplicationScript");
->getMethod<void(jstring)>("loadBundle");

// The proxy ignores the script data passed in.

loadApplicationScript(m_executor.get(), jni::make_jstring(sourceURL).get());
loadBundle(m_executor.get(), jni::make_jstring(sourceURL).get());
// We can get pending calls here to native but the queue will be drained when
// we launch the application.
}
Expand All@@ -96,7 +99,7 @@ void ProxyExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) {

void ProxyExecutor::registerBundle(
uint32_t bundleId,
const std::string &bundlePath) {
std::unique_ptr<JSModulesUnbundle> bundle) {
jni::throwNewJavaException(
"java/lang/UnsupportedOperationException",
"Loading application RAM bundles is not supported for proxy executors");
Expand Down
5 changes: 3 additions & 2 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,12 +37,13 @@ class ProxyExecutor : public JSExecutor {
jni::global_ref<jobject> &&executorInstance,
std::shared_ptr<ExecutorDelegate> delegate);
virtual ~ProxyExecutor() override;
virtual void loadApplicationScript(
virtual void initializeRuntime() override;
virtual void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override;
virtual void setBundleRegistry(
std::unique_ptr<RAMBundleRegistry> bundle) override;
virtual void registerBundle(uint32_t bundleId, const std::string &bundlePath)
virtual void registerBundle(uint32_t bundleId, std::unique_ptr<JSModulesUnbundle> bundle)
override;
virtual void callFunction(
const std::string &moduleId,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ public void test_prepareJSRuntime_ShouldSendCorrectMessage() throws Exception {
}

@Test
public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Exception {
public void test_loadBundle_ShouldSendCorrectMessage() throws Exception {
final JSDebuggerWebSocketClient.JSDebuggerCallback cb =
PowerMockito.mock(JSDebuggerWebSocketClient.JSDebuggerCallback.class);

Expand All@@ -49,7 +49,7 @@ public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Excepti
injectedObjects.put("key1", "value1");
injectedObjects.put("key2", "value2");

client.loadApplicationScript("http://localhost:8080/index.js", injectedObjects, cb);
client.loadBundle("http://localhost:8080/index.js", injectedObjects, cb);
PowerMockito.verifyPrivate(client)
.invoke(
"sendMessage",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Closed
47 changes: 33 additions & 14 deletions React/CxxBridge/RCTCxxBridge.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -384,7 +384,7 @@ - (void)start
dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
RCTCxxBridge *strongSelf = weakSelf;
if (sourceCode && strongSelf.loading) {
[strongSelf executeSourceCode:sourceCode sync:NO];
[strongSelf executeSourceCode:sourceCode bundleId:0 sync:NO];
}
});
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
Expand DownExpand Up@@ -880,7 +880,7 @@ - (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
[_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
}

- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
- (void)executeSourceCode:(NSData *)sourceCode bundleId:(int)bundleId sync:(BOOL)sync
{
// This will get called from whatever thread was actually executing JS.
dispatch_block_t completion = ^{
Expand All@@ -905,10 +905,10 @@ - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
};

if (sync) {
[self executeApplicationScriptSync:sourceCode url:self.bundleURL];
[self executeApplicationScriptSync:sourceCode url:self.bundleURL bundleId:bundleId];
completion();
} else {
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
[self enqueueApplicationScript:sourceCode url:self.bundleURL bundleId:bundleId onComplete:completion];
}

if (self.devSettings.isHotLoadingAvailable) {
Expand DownExpand Up@@ -1292,11 +1292,12 @@ - (void)_immediatelyCallTimer:(NSNumber *)timer

- (void)enqueueApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
onComplete:(dispatch_block_t)onComplete
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);

[self executeApplicationScript:script url:url async:YES];
[self executeApplicationScript:script url:url bundleId:bundleId async:YES];

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

Expand All@@ -1307,13 +1308,14 @@ - (void)enqueueApplicationScript:(NSData *)script
}
}

- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url
- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url bundleId:(uint32_t)bundleId
{
[self executeApplicationScript:script url:url async:NO];
[self executeApplicationScript:script url:url bundleId:bundleId async:NO];
}

- (void)executeApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
async:(BOOL)async
{
[self _tryAndHandleError:^{
Expand All@@ -1328,25 +1330,42 @@ - (void)executeApplicationScript:(NSData *)script
[self->_performanceLogger markStopForTag:RCTPLRAMBundleLoad];
[self->_performanceLogger setValue:scriptStr->size() forTag:RCTPLRAMStartupCodeSize];
if (self->_reactInstance) {
auto registry = RAMBundleRegistry::multipleBundlesRegistry(std::move(ramBundle), JSIndexedRAMBundle::buildFactory());
self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr),
sourceUrlStr.UTF8String, !async);
self->_reactInstance->loadRAMBundle(std::move(ramBundle), std::move(scriptStr),
sourceUrlStr.UTF8String, bundleId, !async);
}
} else if (self->_reactInstance) {
self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async);
} else {
std::string methodName = async ? "loadApplicationScript" : "loadApplicationScriptSync";
std::string methodName = async ? "loadBundle" : "loadBundleSync";
throw std::logic_error("Attempt to call " + methodName + ": on uninitialized bridge");
}
}];
}

- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
{
if (_reactInstance) {
_reactInstance->registerBundle(static_cast<uint32_t>(segmentId), path.UTF8String);
}
__weak RCTCxxBridge *weakSelf = self;
NSURL *pathURL = [NSURL URLWithString:path];
dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[RCTJavaScriptLoader loadBundleAtURL:pathURL onProgress:^(RCTLoadingProgress *progressData) {} onComplete:^(NSError *error, RCTSource *source) {
if (error) {
[weakSelf handleError:error];
return;
}

NSData *sourceCode = source.data;
__strong RCTCxxBridge *strongSelf = weakSelf;
if (strongSelf->_reactInstance) {
[strongSelf executeApplicationScript:sourceCode url:pathURL bundleId:segmentId async:YES];
}
dispatch_group_leave(group);

}];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

#pragma mark - Payload Processing
Expand Down
8 changes: 6 additions & 2 deletions React/CxxBridge/RCTObjcExecutor.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -74,7 +74,11 @@
std::make_unique<JSBigStdString>(folly::toJson(config)));
}

void loadApplicationScript(
void initializeRuntime() {
// We do nothing here since initialization is done in the constructor
}

void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override {
RCTProfileBeginFlowEvent();
Expand All@@ -97,7 +101,7 @@ void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

void registerBundle(uint32_t __unused bundleId, const std::string __unused &bundlePath) override {
void registerBundle(uint32_t __unused bundleId, std::unique_ptr<JSModulesUnbundle> __unused) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -230,26 +230,26 @@ public void registerSegment(int segmentId, String path) {

@Override
public void loadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
jniLoadScriptFromAssets(assetManager, assetURL, bundleId, loadSynchronously);
}

@Override
public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
public void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
jniLoadScriptFromFile(fileName, sourceURL, bundleId, loadSynchronously);
}

private native void jniSetSourceURL(String sourceURL);

private native void jniRegisterSegment(int segmentId, String path);

private native void jniLoadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously);
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

private native void jniLoadScriptFromFile(
String fileName, String sourceURL, boolean loadSynchronously);
String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

@Override
public void runJSBundle() {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ public static JSBundleLoader createAssetLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, 0, loadSynchronously);
return assetUrl;
}
};
Expand All@@ -45,7 +45,7 @@ public static JSBundleLoader createFileLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
delegate.loadScriptFromFile(fileName, assetUrl, 0, loadSynchronously);
return fileName;
}
};
Expand All@@ -64,7 +64,7 @@ public static JSBundleLoader createCachedBundleFromNetworkLoader(
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, 0, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,19 +19,21 @@ public interface JSBundleLoaderDelegate {
*
* @param assetManager
* @param assetURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
void loadScriptFromAssets(AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

/**
* Load a JS bundle from the filesystem. See {@link JSBundleLoader#createFileLoader(String)} and
* {@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}
*
* @param fileName
* @param sourceURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

/**
* This API is used in situations where the JS bundle is being executed not on the device, but on
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ public ProxyExecutorException(Throwable cause) {
* @param sourceURL url or file location from which script content was loaded
*/
@DoNotStrip
void loadApplicationScript(String sourceURL) throws ProxyExecutorException;
void loadBundle(String sourceURL) throws ProxyExecutorException;

/**
* Execute javascript method within js context
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,7 +81,7 @@ public void prepareJSRuntime(JSDebuggerCallback callback) {
}
}

public void loadApplicationScript(
public void loadBundle(
String sourceURL, HashMap<String, String> injectedObjects, JSDebuggerCallback callback) {
int requestID = mRequestID.getAndIncrement();
mCallbacks.put(requestID, callback);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -153,10 +153,10 @@ public void close() {
}

@Override
public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
public void loadBundle(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
Assertions.assertNotNull(mWebSocketClient)
.loadApplicationScript(sourceURL, mInjectedObjects, callback);
.loadBundle(sourceURL, mInjectedObjects, callback);
try {
callback.get();
} catch (Throwable cause) {
Expand All@@ -178,7 +178,7 @@ public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyE

@Override
public void setGlobalVariable(String propertyName, String jsonEncodedValue) {
// Store and use in the next loadApplicationScript() call.
// Store and use in the next loadBundle() call.
mInjectedObjects.put(propertyName, jsonEncodedValue);
}
}
9 changes: 5 additions & 4 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,6 +208,7 @@ void CatalystInstanceImpl::jniRegisterSegment(
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
int bundleId,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
Expand All@@ -216,12 +217,11 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
auto script = loadScriptFromAssets(manager, sourceURL);
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
instance_->loadRAMBundle(
std::move(registry), std::move(script), sourceURL, loadSynchronously);
std::move(bundle), std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
return;
} else if (Instance::isIndexedRAMBundle(&script)) {
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
instance_->loadRAMBundleFromString(std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
instance_->loadScriptFromString(
std::move(script), sourceURL, loadSynchronously);
Expand All@@ -231,9 +231,10 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
void CatalystInstanceImpl::jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
int bundleId,
bool loadSynchronously) {
if (Instance::isIndexedRAMBundle(fileName.c_str())) {
instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
instance_->loadRAMBundleFromFile(fileName, sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
std::unique_ptr<const JSBigFileString> script;
RecoverableError::runRethrowingAsRecoverable<std::system_error>(
Expand Down
17 changes: 8 additions & 9 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,15 +77,14 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
*
*/
void jniRegisterSegment(int segmentId, const std::string &path);

void jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
bool loadSynchronously);
void jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
bool loadSynchronously);
void jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
int bundleId,
bool loadSynchronously);
void jniLoadScriptFromFile(const std::string& fileName,
const std::string& sourceURL,
int bundleId,
bool loadSynchronously);
void jniCallJSFunction(
std::string module,
std::string method,
Expand Down
17 changes: 10 additions & 7 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,9 +53,7 @@ ProxyExecutor::~ProxyExecutor() {
m_executor.reset();
}

void ProxyExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {
void ProxyExecutor::initializeRuntime() {
folly::dynamic nativeModuleConfig = folly::dynamic::array;

{
Expand All@@ -76,14 +74,19 @@ void ProxyExecutor::loadApplicationScript(
"__fbBatchedBridgeConfig",
std::make_unique<JSBigStdString>(folly::toJson(config)));
}
}

void ProxyExecutor::loadBundle(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {

static auto loadApplicationScript =
static auto loadBundle =
jni::findClassStatic(EXECUTOR_BASECLASS)
->getMethod<void(jstring)>("loadApplicationScript");
->getMethod<void(jstring)>("loadBundle");

// The proxy ignores the script data passed in.

loadApplicationScript(m_executor.get(), jni::make_jstring(sourceURL).get());
loadBundle(m_executor.get(), jni::make_jstring(sourceURL).get());
// We can get pending calls here to native but the queue will be drained when
// we launch the application.
}
Expand All@@ -96,7 +99,7 @@ void ProxyExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) {

void ProxyExecutor::registerBundle(
uint32_t bundleId,
const std::string &bundlePath) {
std::unique_ptr<JSModulesUnbundle> bundle) {
jni::throwNewJavaException(
"java/lang/UnsupportedOperationException",
"Loading application RAM bundles is not supported for proxy executors");
Expand Down
5 changes: 3 additions & 2 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,12 +37,13 @@ class ProxyExecutor : public JSExecutor {
jni::global_ref<jobject> &&executorInstance,
std::shared_ptr<ExecutorDelegate> delegate);
virtual ~ProxyExecutor() override;
virtual void loadApplicationScript(
virtual void initializeRuntime() override;
virtual void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override;
virtual void setBundleRegistry(
std::unique_ptr<RAMBundleRegistry> bundle) override;
virtual void registerBundle(uint32_t bundleId, const std::string &bundlePath)
virtual void registerBundle(uint32_t bundleId, std::unique_ptr<JSModulesUnbundle> bundle)
override;
virtual void callFunction(
const std::string &moduleId,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ public void test_prepareJSRuntime_ShouldSendCorrectMessage() throws Exception {
}

@Test
public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Exception {
public void test_loadBundle_ShouldSendCorrectMessage() throws Exception {
final JSDebuggerWebSocketClient.JSDebuggerCallback cb =
PowerMockito.mock(JSDebuggerWebSocketClient.JSDebuggerCallback.class);

Expand All@@ -49,7 +49,7 @@ public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Excepti
injectedObjects.put("key1", "value1");
injectedObjects.put("key2", "value2");

client.loadApplicationScript("http://localhost:8080/index.js", injectedObjects, cb);
client.loadBundle("http://localhost:8080/index.js", injectedObjects, cb);
PowerMockito.verifyPrivate(client)
.invoke(
"sendMessage",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
47 changes: 33 additions & 14 deletions React/CxxBridge/RCTCxxBridge.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -384,7 +384,7 @@ - (void)start
dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
RCTCxxBridge *strongSelf = weakSelf;
if (sourceCode && strongSelf.loading) {
[strongSelf executeSourceCode:sourceCode sync:NO];
[strongSelf executeSourceCode:sourceCode bundleId:0 sync:NO];
}
});
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
Expand DownExpand Up@@ -880,7 +880,7 @@ - (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
[_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
}

- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
- (void)executeSourceCode:(NSData *)sourceCode bundleId:(int)bundleId sync:(BOOL)sync
{
// This will get called from whatever thread was actually executing JS.
dispatch_block_t completion = ^{
Expand All@@ -905,10 +905,10 @@ - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
};

if (sync) {
[self executeApplicationScriptSync:sourceCode url:self.bundleURL];
[self executeApplicationScriptSync:sourceCode url:self.bundleURL bundleId:bundleId];
completion();
} else {
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
[self enqueueApplicationScript:sourceCode url:self.bundleURL bundleId:bundleId onComplete:completion];
}

if (self.devSettings.isHotLoadingAvailable) {
Expand DownExpand Up@@ -1292,11 +1292,12 @@ - (void)_immediatelyCallTimer:(NSNumber *)timer

- (void)enqueueApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
onComplete:(dispatch_block_t)onComplete
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);

[self executeApplicationScript:script url:url async:YES];
[self executeApplicationScript:script url:url bundleId:bundleId async:YES];

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

Expand All@@ -1307,13 +1308,14 @@ - (void)enqueueApplicationScript:(NSData *)script
}
}

- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url
- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url bundleId:(uint32_t)bundleId
{
[self executeApplicationScript:script url:url async:NO];
[self executeApplicationScript:script url:url bundleId:bundleId async:NO];
}

- (void)executeApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
async:(BOOL)async
{
[self _tryAndHandleError:^{
Expand All@@ -1328,25 +1330,42 @@ - (void)executeApplicationScript:(NSData *)script
[self->_performanceLogger markStopForTag:RCTPLRAMBundleLoad];
[self->_performanceLogger setValue:scriptStr->size() forTag:RCTPLRAMStartupCodeSize];
if (self->_reactInstance) {
auto registry = RAMBundleRegistry::multipleBundlesRegistry(std::move(ramBundle), JSIndexedRAMBundle::buildFactory());
self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr),
sourceUrlStr.UTF8String, !async);
self->_reactInstance->loadRAMBundle(std::move(ramBundle), std::move(scriptStr),
sourceUrlStr.UTF8String, bundleId, !async);
}
} else if (self->_reactInstance) {
self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async);
} else {
std::string methodName = async ? "loadApplicationScript" : "loadApplicationScriptSync";
std::string methodName = async ? "loadBundle" : "loadBundleSync";
throw std::logic_error("Attempt to call " + methodName + ": on uninitialized bridge");
}
}];
}

- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
{
if (_reactInstance) {
_reactInstance->registerBundle(static_cast<uint32_t>(segmentId), path.UTF8String);
}
__weak RCTCxxBridge *weakSelf = self;
NSURL *pathURL = [NSURL URLWithString:path];
dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[RCTJavaScriptLoader loadBundleAtURL:pathURL onProgress:^(RCTLoadingProgress *progressData) {} onComplete:^(NSError *error, RCTSource *source) {
if (error) {
[weakSelf handleError:error];
return;
}

NSData *sourceCode = source.data;
__strong RCTCxxBridge *strongSelf = weakSelf;
if (strongSelf->_reactInstance) {
[strongSelf executeApplicationScript:sourceCode url:pathURL bundleId:segmentId async:YES];
}
dispatch_group_leave(group);

}];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

#pragma mark - Payload Processing
Expand Down
8 changes: 6 additions & 2 deletions React/CxxBridge/RCTObjcExecutor.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -74,7 +74,11 @@
std::make_unique<JSBigStdString>(folly::toJson(config)));
}

void loadApplicationScript(
void initializeRuntime() {
// We do nothing here since initialization is done in the constructor
}

void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override {
RCTProfileBeginFlowEvent();
Expand All@@ -97,7 +101,7 @@ void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

void registerBundle(uint32_t __unused bundleId, const std::string __unused &bundlePath) override {
void registerBundle(uint32_t __unused bundleId, std::unique_ptr<JSModulesUnbundle> __unused) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -230,26 +230,26 @@ public void registerSegment(int segmentId, String path) {

@Override
public void loadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
jniLoadScriptFromAssets(assetManager, assetURL, bundleId, loadSynchronously);
}

@Override
public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
public void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
jniLoadScriptFromFile(fileName, sourceURL, bundleId, loadSynchronously);
}

private native void jniSetSourceURL(String sourceURL);

private native void jniRegisterSegment(int segmentId, String path);

private native void jniLoadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously);
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

private native void jniLoadScriptFromFile(
String fileName, String sourceURL, boolean loadSynchronously);
String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

@Override
public void runJSBundle() {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ public static JSBundleLoader createAssetLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, 0, loadSynchronously);
return assetUrl;
}
};
Expand All@@ -45,7 +45,7 @@ public static JSBundleLoader createFileLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
delegate.loadScriptFromFile(fileName, assetUrl, 0, loadSynchronously);
return fileName;
}
};
Expand All@@ -64,7 +64,7 @@ public static JSBundleLoader createCachedBundleFromNetworkLoader(
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, 0, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,19 +19,21 @@ public interface JSBundleLoaderDelegate {
*
* @param assetManager
* @param assetURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
void loadScriptFromAssets(AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

/**
* Load a JS bundle from the filesystem. See {@link JSBundleLoader#createFileLoader(String)} and
* {@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}
*
* @param fileName
* @param sourceURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

/**
* This API is used in situations where the JS bundle is being executed not on the device, but on
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ public ProxyExecutorException(Throwable cause) {
* @param sourceURL url or file location from which script content was loaded
*/
@DoNotStrip
void loadApplicationScript(String sourceURL) throws ProxyExecutorException;
void loadBundle(String sourceURL) throws ProxyExecutorException;

/**
* Execute javascript method within js context
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,7 +81,7 @@ public void prepareJSRuntime(JSDebuggerCallback callback) {
}
}

public void loadApplicationScript(
public void loadBundle(
String sourceURL, HashMap<String, String> injectedObjects, JSDebuggerCallback callback) {
int requestID = mRequestID.getAndIncrement();
mCallbacks.put(requestID, callback);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -153,10 +153,10 @@ public void close() {
}

@Override
public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
public void loadBundle(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
Assertions.assertNotNull(mWebSocketClient)
.loadApplicationScript(sourceURL, mInjectedObjects, callback);
.loadBundle(sourceURL, mInjectedObjects, callback);
try {
callback.get();
} catch (Throwable cause) {
Expand All@@ -178,7 +178,7 @@ public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyE

@Override
public void setGlobalVariable(String propertyName, String jsonEncodedValue) {
// Store and use in the next loadApplicationScript() call.
// Store and use in the next loadBundle() call.
mInjectedObjects.put(propertyName, jsonEncodedValue);
}
}
9 changes: 5 additions & 4 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,6 +208,7 @@ void CatalystInstanceImpl::jniRegisterSegment(
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
int bundleId,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
Expand All@@ -216,12 +217,11 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
auto script = loadScriptFromAssets(manager, sourceURL);
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
instance_->loadRAMBundle(
std::move(registry), std::move(script), sourceURL, loadSynchronously);
std::move(bundle), std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
return;
} else if (Instance::isIndexedRAMBundle(&script)) {
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
instance_->loadRAMBundleFromString(std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
instance_->loadScriptFromString(
std::move(script), sourceURL, loadSynchronously);
Expand All@@ -231,9 +231,10 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
void CatalystInstanceImpl::jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
int bundleId,
bool loadSynchronously) {
if (Instance::isIndexedRAMBundle(fileName.c_str())) {
instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
instance_->loadRAMBundleFromFile(fileName, sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
std::unique_ptr<const JSBigFileString> script;
RecoverableError::runRethrowingAsRecoverable<std::system_error>(
Expand Down
17 changes: 8 additions & 9 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,15 +77,14 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
*
*/
void jniRegisterSegment(int segmentId, const std::string &path);

void jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
bool loadSynchronously);
void jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
bool loadSynchronously);
void jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
int bundleId,
bool loadSynchronously);
void jniLoadScriptFromFile(const std::string& fileName,
const std::string& sourceURL,
int bundleId,
bool loadSynchronously);
void jniCallJSFunction(
std::string module,
std::string method,
Expand Down
17 changes: 10 additions & 7 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,9 +53,7 @@ ProxyExecutor::~ProxyExecutor() {
m_executor.reset();
}

void ProxyExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {
void ProxyExecutor::initializeRuntime() {
folly::dynamic nativeModuleConfig = folly::dynamic::array;

{
Expand All@@ -76,14 +74,19 @@ void ProxyExecutor::loadApplicationScript(
"__fbBatchedBridgeConfig",
std::make_unique<JSBigStdString>(folly::toJson(config)));
}
}

void ProxyExecutor::loadBundle(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {

static auto loadApplicationScript =
static auto loadBundle =
jni::findClassStatic(EXECUTOR_BASECLASS)
->getMethod<void(jstring)>("loadApplicationScript");
->getMethod<void(jstring)>("loadBundle");

// The proxy ignores the script data passed in.

loadApplicationScript(m_executor.get(), jni::make_jstring(sourceURL).get());
loadBundle(m_executor.get(), jni::make_jstring(sourceURL).get());
// We can get pending calls here to native but the queue will be drained when
// we launch the application.
}
Expand All@@ -96,7 +99,7 @@ void ProxyExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) {

void ProxyExecutor::registerBundle(
uint32_t bundleId,
const std::string &bundlePath) {
std::unique_ptr<JSModulesUnbundle> bundle) {
jni::throwNewJavaException(
"java/lang/UnsupportedOperationException",
"Loading application RAM bundles is not supported for proxy executors");
Expand Down
5 changes: 3 additions & 2 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,12 +37,13 @@ class ProxyExecutor : public JSExecutor {
jni::global_ref<jobject> &&executorInstance,
std::shared_ptr<ExecutorDelegate> delegate);
virtual ~ProxyExecutor() override;
virtual void loadApplicationScript(
virtual void initializeRuntime() override;
virtual void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override;
virtual void setBundleRegistry(
std::unique_ptr<RAMBundleRegistry> bundle) override;
virtual void registerBundle(uint32_t bundleId, const std::string &bundlePath)
virtual void registerBundle(uint32_t bundleId, std::unique_ptr<JSModulesUnbundle> bundle)
override;
virtual void callFunction(
const std::string &moduleId,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ public void test_prepareJSRuntime_ShouldSendCorrectMessage() throws Exception {
}

@Test
public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Exception {
public void test_loadBundle_ShouldSendCorrectMessage() throws Exception {
final JSDebuggerWebSocketClient.JSDebuggerCallback cb =
PowerMockito.mock(JSDebuggerWebSocketClient.JSDebuggerCallback.class);

Expand All@@ -49,7 +49,7 @@ public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Excepti
injectedObjects.put("key1", "value1");
injectedObjects.put("key2", "value2");

client.loadApplicationScript("http://localhost:8080/index.js", injectedObjects, cb);
client.loadBundle("http://localhost:8080/index.js", injectedObjects, cb);
PowerMockito.verifyPrivate(client)
.invoke(
"sendMessage",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
47 changes: 33 additions & 14 deletions React/CxxBridge/RCTCxxBridge.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -384,7 +384,7 @@ - (void)start
dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
RCTCxxBridge *strongSelf = weakSelf;
if (sourceCode && strongSelf.loading) {
[strongSelf executeSourceCode:sourceCode sync:NO];
[strongSelf executeSourceCode:sourceCode bundleId:0 sync:NO];
}
});
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
Expand DownExpand Up@@ -880,7 +880,7 @@ - (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
[_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
}

- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
- (void)executeSourceCode:(NSData *)sourceCode bundleId:(int)bundleId sync:(BOOL)sync
{
// This will get called from whatever thread was actually executing JS.
dispatch_block_t completion = ^{
Expand All@@ -905,10 +905,10 @@ - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
};

if (sync) {
[self executeApplicationScriptSync:sourceCode url:self.bundleURL];
[self executeApplicationScriptSync:sourceCode url:self.bundleURL bundleId:bundleId];
completion();
} else {
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
[self enqueueApplicationScript:sourceCode url:self.bundleURL bundleId:bundleId onComplete:completion];
}

if (self.devSettings.isHotLoadingAvailable) {
Expand DownExpand Up@@ -1292,11 +1292,12 @@ - (void)_immediatelyCallTimer:(NSNumber *)timer

- (void)enqueueApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
onComplete:(dispatch_block_t)onComplete
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);

[self executeApplicationScript:script url:url async:YES];
[self executeApplicationScript:script url:url bundleId:bundleId async:YES];

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

Expand All@@ -1307,13 +1308,14 @@ - (void)enqueueApplicationScript:(NSData *)script
}
}

- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url
- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url bundleId:(uint32_t)bundleId
{
[self executeApplicationScript:script url:url async:NO];
[self executeApplicationScript:script url:url bundleId:bundleId async:NO];
}

- (void)executeApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
async:(BOOL)async
{
[self _tryAndHandleError:^{
Expand All@@ -1328,25 +1330,42 @@ - (void)executeApplicationScript:(NSData *)script
[self->_performanceLogger markStopForTag:RCTPLRAMBundleLoad];
[self->_performanceLogger setValue:scriptStr->size() forTag:RCTPLRAMStartupCodeSize];
if (self->_reactInstance) {
auto registry = RAMBundleRegistry::multipleBundlesRegistry(std::move(ramBundle), JSIndexedRAMBundle::buildFactory());
self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr),
sourceUrlStr.UTF8String, !async);
self->_reactInstance->loadRAMBundle(std::move(ramBundle), std::move(scriptStr),
sourceUrlStr.UTF8String, bundleId, !async);
}
} else if (self->_reactInstance) {
self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async);
} else {
std::string methodName = async ? "loadApplicationScript" : "loadApplicationScriptSync";
std::string methodName = async ? "loadBundle" : "loadBundleSync";
throw std::logic_error("Attempt to call " + methodName + ": on uninitialized bridge");
}
}];
}

- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
{
if (_reactInstance) {
_reactInstance->registerBundle(static_cast<uint32_t>(segmentId), path.UTF8String);
}
__weak RCTCxxBridge *weakSelf = self;
NSURL *pathURL = [NSURL URLWithString:path];
dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[RCTJavaScriptLoader loadBundleAtURL:pathURL onProgress:^(RCTLoadingProgress *progressData) {} onComplete:^(NSError *error, RCTSource *source) {
if (error) {
[weakSelf handleError:error];
return;
}

NSData *sourceCode = source.data;
__strong RCTCxxBridge *strongSelf = weakSelf;
if (strongSelf->_reactInstance) {
[strongSelf executeApplicationScript:sourceCode url:pathURL bundleId:segmentId async:YES];
}
dispatch_group_leave(group);

}];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

#pragma mark - Payload Processing
Expand Down
8 changes: 6 additions & 2 deletions React/CxxBridge/RCTObjcExecutor.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -74,7 +74,11 @@
std::make_unique<JSBigStdString>(folly::toJson(config)));
}

void loadApplicationScript(
void initializeRuntime() {
// We do nothing here since initialization is done in the constructor
}

void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override {
RCTProfileBeginFlowEvent();
Expand All@@ -97,7 +101,7 @@ void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

void registerBundle(uint32_t __unused bundleId, const std::string __unused &bundlePath) override {
void registerBundle(uint32_t __unused bundleId, std::unique_ptr<JSModulesUnbundle> __unused) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -230,26 +230,26 @@ public void registerSegment(int segmentId, String path) {

@Override
public void loadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
jniLoadScriptFromAssets(assetManager, assetURL, bundleId, loadSynchronously);
}

@Override
public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
public void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
jniLoadScriptFromFile(fileName, sourceURL, bundleId, loadSynchronously);
}

private native void jniSetSourceURL(String sourceURL);

private native void jniRegisterSegment(int segmentId, String path);

private native void jniLoadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously);
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

private native void jniLoadScriptFromFile(
String fileName, String sourceURL, boolean loadSynchronously);
String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

@Override
public void runJSBundle() {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ public static JSBundleLoader createAssetLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, 0, loadSynchronously);
return assetUrl;
}
};
Expand All@@ -45,7 +45,7 @@ public static JSBundleLoader createFileLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
delegate.loadScriptFromFile(fileName, assetUrl, 0, loadSynchronously);
return fileName;
}
};
Expand All@@ -64,7 +64,7 @@ public static JSBundleLoader createCachedBundleFromNetworkLoader(
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, 0, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,19 +19,21 @@ public interface JSBundleLoaderDelegate {
*
* @param assetManager
* @param assetURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
void loadScriptFromAssets(AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

/**
* Load a JS bundle from the filesystem. See {@link JSBundleLoader#createFileLoader(String)} and
* {@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}
*
* @param fileName
* @param sourceURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

/**
* This API is used in situations where the JS bundle is being executed not on the device, but on
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ public ProxyExecutorException(Throwable cause) {
* @param sourceURL url or file location from which script content was loaded
*/
@DoNotStrip
void loadApplicationScript(String sourceURL) throws ProxyExecutorException;
void loadBundle(String sourceURL) throws ProxyExecutorException;

/**
* Execute javascript method within js context
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,7 +81,7 @@ public void prepareJSRuntime(JSDebuggerCallback callback) {
}
}

public void loadApplicationScript(
public void loadBundle(
String sourceURL, HashMap<String, String> injectedObjects, JSDebuggerCallback callback) {
int requestID = mRequestID.getAndIncrement();
mCallbacks.put(requestID, callback);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -153,10 +153,10 @@ public void close() {
}

@Override
public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
public void loadBundle(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
Assertions.assertNotNull(mWebSocketClient)
.loadApplicationScript(sourceURL, mInjectedObjects, callback);
.loadBundle(sourceURL, mInjectedObjects, callback);
try {
callback.get();
} catch (Throwable cause) {
Expand All@@ -178,7 +178,7 @@ public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyE

@Override
public void setGlobalVariable(String propertyName, String jsonEncodedValue) {
// Store and use in the next loadApplicationScript() call.
// Store and use in the next loadBundle() call.
mInjectedObjects.put(propertyName, jsonEncodedValue);
}
}
9 changes: 5 additions & 4 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,6 +208,7 @@ void CatalystInstanceImpl::jniRegisterSegment(
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
int bundleId,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
Expand All@@ -216,12 +217,11 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
auto script = loadScriptFromAssets(manager, sourceURL);
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
instance_->loadRAMBundle(
std::move(registry), std::move(script), sourceURL, loadSynchronously);
std::move(bundle), std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
return;
} else if (Instance::isIndexedRAMBundle(&script)) {
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
instance_->loadRAMBundleFromString(std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
instance_->loadScriptFromString(
std::move(script), sourceURL, loadSynchronously);
Expand All@@ -231,9 +231,10 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
void CatalystInstanceImpl::jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
int bundleId,
bool loadSynchronously) {
if (Instance::isIndexedRAMBundle(fileName.c_str())) {
instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
instance_->loadRAMBundleFromFile(fileName, sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
std::unique_ptr<const JSBigFileString> script;
RecoverableError::runRethrowingAsRecoverable<std::system_error>(
Expand Down
17 changes: 8 additions & 9 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,15 +77,14 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
*
*/
void jniRegisterSegment(int segmentId, const std::string &path);

void jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
bool loadSynchronously);
void jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
bool loadSynchronously);
void jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
int bundleId,
bool loadSynchronously);
void jniLoadScriptFromFile(const std::string& fileName,
const std::string& sourceURL,
int bundleId,
bool loadSynchronously);
void jniCallJSFunction(
std::string module,
std::string method,
Expand Down
17 changes: 10 additions & 7 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,9 +53,7 @@ ProxyExecutor::~ProxyExecutor() {
m_executor.reset();
}

void ProxyExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {
void ProxyExecutor::initializeRuntime() {
folly::dynamic nativeModuleConfig = folly::dynamic::array;

{
Expand All@@ -76,14 +74,19 @@ void ProxyExecutor::loadApplicationScript(
"__fbBatchedBridgeConfig",
std::make_unique<JSBigStdString>(folly::toJson(config)));
}
}

void ProxyExecutor::loadBundle(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {

static auto loadApplicationScript =
static auto loadBundle =
jni::findClassStatic(EXECUTOR_BASECLASS)
->getMethod<void(jstring)>("loadApplicationScript");
->getMethod<void(jstring)>("loadBundle");

// The proxy ignores the script data passed in.

loadApplicationScript(m_executor.get(), jni::make_jstring(sourceURL).get());
loadBundle(m_executor.get(), jni::make_jstring(sourceURL).get());
// We can get pending calls here to native but the queue will be drained when
// we launch the application.
}
Expand All@@ -96,7 +99,7 @@ void ProxyExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) {

void ProxyExecutor::registerBundle(
uint32_t bundleId,
const std::string &bundlePath) {
std::unique_ptr<JSModulesUnbundle> bundle) {
jni::throwNewJavaException(
"java/lang/UnsupportedOperationException",
"Loading application RAM bundles is not supported for proxy executors");
Expand Down
5 changes: 3 additions & 2 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,12 +37,13 @@ class ProxyExecutor : public JSExecutor {
jni::global_ref<jobject> &&executorInstance,
std::shared_ptr<ExecutorDelegate> delegate);
virtual ~ProxyExecutor() override;
virtual void loadApplicationScript(
virtual void initializeRuntime() override;
virtual void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override;
virtual void setBundleRegistry(
std::unique_ptr<RAMBundleRegistry> bundle) override;
virtual void registerBundle(uint32_t bundleId, const std::string &bundlePath)
virtual void registerBundle(uint32_t bundleId, std::unique_ptr<JSModulesUnbundle> bundle)
override;
virtual void callFunction(
const std::string &moduleId,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ public void test_prepareJSRuntime_ShouldSendCorrectMessage() throws Exception {
}

@Test
public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Exception {
public void test_loadBundle_ShouldSendCorrectMessage() throws Exception {
final JSDebuggerWebSocketClient.JSDebuggerCallback cb =
PowerMockito.mock(JSDebuggerWebSocketClient.JSDebuggerCallback.class);

Expand All@@ -49,7 +49,7 @@ public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Excepti
injectedObjects.put("key1", "value1");
injectedObjects.put("key2", "value2");

client.loadApplicationScript("http://localhost:8080/index.js", injectedObjects, cb);
client.loadBundle("http://localhost:8080/index.js", injectedObjects, cb);
PowerMockito.verifyPrivate(client)
.invoke(
"sendMessage",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Closed
47 changes: 33 additions & 14 deletions React/CxxBridge/RCTCxxBridge.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -384,7 +384,7 @@ - (void)start
dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
RCTCxxBridge *strongSelf = weakSelf;
if (sourceCode && strongSelf.loading) {
[strongSelf executeSourceCode:sourceCode sync:NO];
[strongSelf executeSourceCode:sourceCode bundleId:0 sync:NO];
}
});
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
Expand DownExpand Up@@ -880,7 +880,7 @@ - (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
[_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
}

- (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
- (void)executeSourceCode:(NSData *)sourceCode bundleId:(int)bundleId sync:(BOOL)sync
{
// This will get called from whatever thread was actually executing JS.
dispatch_block_t completion = ^{
Expand All@@ -905,10 +905,10 @@ - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
};

if (sync) {
[self executeApplicationScriptSync:sourceCode url:self.bundleURL];
[self executeApplicationScriptSync:sourceCode url:self.bundleURL bundleId:bundleId];
completion();
} else {
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
[self enqueueApplicationScript:sourceCode url:self.bundleURL bundleId:bundleId onComplete:completion];
}

if (self.devSettings.isHotLoadingAvailable) {
Expand DownExpand Up@@ -1292,11 +1292,12 @@ - (void)_immediatelyCallTimer:(NSNumber *)timer

- (void)enqueueApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
onComplete:(dispatch_block_t)onComplete
{
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);

[self executeApplicationScript:script url:url async:YES];
[self executeApplicationScript:script url:url bundleId:bundleId async:YES];

RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");

Expand All@@ -1307,13 +1308,14 @@ - (void)enqueueApplicationScript:(NSData *)script
}
}

- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url
- (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url bundleId:(uint32_t)bundleId
{
[self executeApplicationScript:script url:url async:NO];
[self executeApplicationScript:script url:url bundleId:bundleId async:NO];
}

- (void)executeApplicationScript:(NSData *)script
url:(NSURL *)url
bundleId:(uint32_t)bundleId
async:(BOOL)async
{
[self _tryAndHandleError:^{
Expand All@@ -1328,25 +1330,42 @@ - (void)executeApplicationScript:(NSData *)script
[self->_performanceLogger markStopForTag:RCTPLRAMBundleLoad];
[self->_performanceLogger setValue:scriptStr->size() forTag:RCTPLRAMStartupCodeSize];
if (self->_reactInstance) {
auto registry = RAMBundleRegistry::multipleBundlesRegistry(std::move(ramBundle), JSIndexedRAMBundle::buildFactory());
self->_reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr),
sourceUrlStr.UTF8String, !async);
self->_reactInstance->loadRAMBundle(std::move(ramBundle), std::move(scriptStr),
sourceUrlStr.UTF8String, bundleId, !async);
}
} else if (self->_reactInstance) {
self->_reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script),
sourceUrlStr.UTF8String, !async);
} else {
std::string methodName = async ? "loadApplicationScript" : "loadApplicationScriptSync";
std::string methodName = async ? "loadBundle" : "loadBundleSync";
throw std::logic_error("Attempt to call " + methodName + ": on uninitialized bridge");
}
}];
}

- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
{
if (_reactInstance) {
_reactInstance->registerBundle(static_cast<uint32_t>(segmentId), path.UTF8String);
}
__weak RCTCxxBridge *weakSelf = self;
NSURL *pathURL = [NSURL URLWithString:path];
dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[RCTJavaScriptLoader loadBundleAtURL:pathURL onProgress:^(RCTLoadingProgress *progressData) {} onComplete:^(NSError *error, RCTSource *source) {
if (error) {
[weakSelf handleError:error];
return;
}

NSData *sourceCode = source.data;
__strong RCTCxxBridge *strongSelf = weakSelf;
if (strongSelf->_reactInstance) {
[strongSelf executeApplicationScript:sourceCode url:pathURL bundleId:segmentId async:YES];
}
dispatch_group_leave(group);

}];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

#pragma mark - Payload Processing
Expand Down
8 changes: 6 additions & 2 deletions React/CxxBridge/RCTObjcExecutor.mm
Original file line numberDiff line numberDiff line change
Expand Up@@ -74,7 +74,11 @@
std::make_unique<JSBigStdString>(folly::toJson(config)));
}

void loadApplicationScript(
void initializeRuntime() {
// We do nothing here since initialization is done in the constructor
}

void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override {
RCTProfileBeginFlowEvent();
Expand All@@ -97,7 +101,7 @@ void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

void registerBundle(uint32_t __unused bundleId, const std::string __unused &bundlePath) override {
void registerBundle(uint32_t __unused bundleId, std::unique_ptr<JSModulesUnbundle> __unused) override {
RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor");
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -230,26 +230,26 @@ public void registerSegment(int segmentId, String path) {

@Override
public void loadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously) {
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously) {
mSourceURL = assetURL;
jniLoadScriptFromAssets(assetManager, assetURL, loadSynchronously);
jniLoadScriptFromAssets(assetManager, assetURL, bundleId, loadSynchronously);
}

@Override
public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {
public void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously) {
mSourceURL = sourceURL;
jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously);
jniLoadScriptFromFile(fileName, sourceURL, bundleId, loadSynchronously);
}

private native void jniSetSourceURL(String sourceURL);

private native void jniRegisterSegment(int segmentId, String path);

private native void jniLoadScriptFromAssets(
AssetManager assetManager, String assetURL, boolean loadSynchronously);
AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

private native void jniLoadScriptFromFile(
String fileName, String sourceURL, boolean loadSynchronously);
String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

@Override
public void runJSBundle() {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ public static JSBundleLoader createAssetLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
delegate.loadScriptFromAssets(context.getAssets(), assetUrl, 0, loadSynchronously);
return assetUrl;
}
};
Expand All@@ -45,7 +45,7 @@ public static JSBundleLoader createFileLoader(
return new JSBundleLoader() {
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
delegate.loadScriptFromFile(fileName, assetUrl, loadSynchronously);
delegate.loadScriptFromFile(fileName, assetUrl, 0, loadSynchronously);
return fileName;
}
};
Expand All@@ -64,7 +64,7 @@ public static JSBundleLoader createCachedBundleFromNetworkLoader(
@Override
public String loadScript(JSBundleLoaderDelegate delegate) {
try {
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false);
delegate.loadScriptFromFile(cachedFileLocation, sourceURL, 0, false);
return sourceURL;
} catch (Exception e) {
throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,19 +19,21 @@ public interface JSBundleLoaderDelegate {
*
* @param assetManager
* @param assetURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
void loadScriptFromAssets(AssetManager assetManager, String assetURL, int bundleId, boolean loadSynchronously);

/**
* Load a JS bundle from the filesystem. See {@link JSBundleLoader#createFileLoader(String)} and
* {@link JSBundleLoader#createCachedBundleFromNetworkLoader(String, String)}
*
* @param fileName
* @param sourceURL
* @param bundleId
* @param loadSynchronously
*/
void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
void loadScriptFromFile(String fileName, String sourceURL, int bundleId, boolean loadSynchronously);

/**
* This API is used in situations where the JS bundle is being executed not on the device, but on
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ public ProxyExecutorException(Throwable cause) {
* @param sourceURL url or file location from which script content was loaded
*/
@DoNotStrip
void loadApplicationScript(String sourceURL) throws ProxyExecutorException;
void loadBundle(String sourceURL) throws ProxyExecutorException;

/**
* Execute javascript method within js context
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -81,7 +81,7 @@ public void prepareJSRuntime(JSDebuggerCallback callback) {
}
}

public void loadApplicationScript(
public void loadBundle(
String sourceURL, HashMap<String, String> injectedObjects, JSDebuggerCallback callback) {
int requestID = mRequestID.getAndIncrement();
mCallbacks.put(requestID, callback);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -153,10 +153,10 @@ public void close() {
}

@Override
public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
public void loadBundle(String sourceURL) throws JavaJSExecutor.ProxyExecutorException {
JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
Assertions.assertNotNull(mWebSocketClient)
.loadApplicationScript(sourceURL, mInjectedObjects, callback);
.loadBundle(sourceURL, mInjectedObjects, callback);
try {
callback.get();
} catch (Throwable cause) {
Expand All@@ -178,7 +178,7 @@ public void loadApplicationScript(String sourceURL) throws JavaJSExecutor.ProxyE

@Override
public void setGlobalVariable(String propertyName, String jsonEncodedValue) {
// Store and use in the next loadApplicationScript() call.
// Store and use in the next loadBundle() call.
mInjectedObjects.put(propertyName, jsonEncodedValue);
}
}
9 changes: 5 additions & 4 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,6 +208,7 @@ void CatalystInstanceImpl::jniRegisterSegment(
void CatalystInstanceImpl::jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
int bundleId,
bool loadSynchronously) {
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
Expand All@@ -216,12 +217,11 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
auto script = loadScriptFromAssets(manager, sourceURL);
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL);
auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
instance_->loadRAMBundle(
std::move(registry), std::move(script), sourceURL, loadSynchronously);
std::move(bundle), std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
return;
} else if (Instance::isIndexedRAMBundle(&script)) {
instance_->loadRAMBundleFromString(std::move(script), sourceURL);
instance_->loadRAMBundleFromString(std::move(script), sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
instance_->loadScriptFromString(
std::move(script), sourceURL, loadSynchronously);
Expand All@@ -231,9 +231,10 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
void CatalystInstanceImpl::jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
int bundleId,
bool loadSynchronously) {
if (Instance::isIndexedRAMBundle(fileName.c_str())) {
instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
instance_->loadRAMBundleFromFile(fileName, sourceURL, (uint32_t)bundleId, loadSynchronously);
} else {
std::unique_ptr<const JSBigFileString> script;
RecoverableError::runRethrowingAsRecoverable<std::system_error>(
Expand Down
17 changes: 8 additions & 9 deletions ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,15 +77,14 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
*
*/
void jniRegisterSegment(int segmentId, const std::string &path);

void jniLoadScriptFromAssets(
jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string &assetURL,
bool loadSynchronously);
void jniLoadScriptFromFile(
const std::string &fileName,
const std::string &sourceURL,
bool loadSynchronously);
void jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,
const std::string& assetURL,
int bundleId,
bool loadSynchronously);
void jniLoadScriptFromFile(const std::string& fileName,
const std::string& sourceURL,
int bundleId,
bool loadSynchronously);
void jniCallJSFunction(
std::string module,
std::string method,
Expand Down
17 changes: 10 additions & 7 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,9 +53,7 @@ ProxyExecutor::~ProxyExecutor() {
m_executor.reset();
}

void ProxyExecutor::loadApplicationScript(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {
void ProxyExecutor::initializeRuntime() {
folly::dynamic nativeModuleConfig = folly::dynamic::array;

{
Expand All@@ -76,14 +74,19 @@ void ProxyExecutor::loadApplicationScript(
"__fbBatchedBridgeConfig",
std::make_unique<JSBigStdString>(folly::toJson(config)));
}
}

void ProxyExecutor::loadBundle(
std::unique_ptr<const JSBigString>,
std::string sourceURL) {

static auto loadApplicationScript =
static auto loadBundle =
jni::findClassStatic(EXECUTOR_BASECLASS)
->getMethod<void(jstring)>("loadApplicationScript");
->getMethod<void(jstring)>("loadBundle");

// The proxy ignores the script data passed in.

loadApplicationScript(m_executor.get(), jni::make_jstring(sourceURL).get());
loadBundle(m_executor.get(), jni::make_jstring(sourceURL).get());
// We can get pending calls here to native but the queue will be drained when
// we launch the application.
}
Expand All@@ -96,7 +99,7 @@ void ProxyExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) {

void ProxyExecutor::registerBundle(
uint32_t bundleId,
const std::string &bundlePath) {
std::unique_ptr<JSModulesUnbundle> bundle) {
jni::throwNewJavaException(
"java/lang/UnsupportedOperationException",
"Loading application RAM bundles is not supported for proxy executors");
Expand Down
5 changes: 3 additions & 2 deletions ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,12 +37,13 @@ class ProxyExecutor : public JSExecutor {
jni::global_ref<jobject> &&executorInstance,
std::shared_ptr<ExecutorDelegate> delegate);
virtual ~ProxyExecutor() override;
virtual void loadApplicationScript(
virtual void initializeRuntime() override;
virtual void loadBundle(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) override;
virtual void setBundleRegistry(
std::unique_ptr<RAMBundleRegistry> bundle) override;
virtual void registerBundle(uint32_t bundleId, const std::string &bundlePath)
virtual void registerBundle(uint32_t bundleId, std::unique_ptr<JSModulesUnbundle> bundle)
override;
virtual void callFunction(
const std::string &moduleId,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ public void test_prepareJSRuntime_ShouldSendCorrectMessage() throws Exception {
}

@Test
public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Exception {
public void test_loadBundle_ShouldSendCorrectMessage() throws Exception {
final JSDebuggerWebSocketClient.JSDebuggerCallback cb =
PowerMockito.mock(JSDebuggerWebSocketClient.JSDebuggerCallback.class);

Expand All@@ -49,7 +49,7 @@ public void test_loadApplicationScript_ShouldSendCorrectMessage() throws Excepti
injectedObjects.put("key1", "value1");
injectedObjects.put("key2", "value2");

client.loadApplicationScript("http://localhost:8080/index.js", injectedObjects, cb);
client.loadBundle("http://localhost:8080/index.js", injectedObjects, cb);
PowerMockito.verifyPrivate(client)
.invoke(
"sendMessage",
Expand Down
Loading