diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm b/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm index cf48ec9cef83..6b0d8a28a6bf 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm @@ -19,6 +19,7 @@ #import #import #import +#import // Fabric #import @@ -73,7 +74,9 @@ void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled) classNames = dependencyProvider ? dependencyProvider.imageDataDecoderClassNames : @[]; } else if (protocol == @protocol(RCTURLRequestHandler)) { classNames = dependencyProvider ? dependencyProvider.URLRequestHandlerClassNames : @[]; - } + } else if (protocol == @protocol(RCTBundleConsumer)) { + classNames = dependencyProvider ? dependencyProvider.bundleConsumerClassNames : @[]; + } NSMutableArray *modules = [NSMutableArray new]; diff --git a/packages/react-native/Libraries/AppDelegate/RCTDependencyProvider.h b/packages/react-native/Libraries/AppDelegate/RCTDependencyProvider.h index ddc412b0f71b..18c9c188be33 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTDependencyProvider.h +++ b/packages/react-native/Libraries/AppDelegate/RCTDependencyProvider.h @@ -20,6 +20,8 @@ NS_ASSUME_NONNULL_BEGIN - (NSArray *)URLRequestHandlerClassNames; +- (NSArray *)bundleConsumerClassNames; + - (NSArray *)unstableModulesRequiringMainQueueSetup; - (NSDictionary> *)thirdPartyFabricComponents; diff --git a/packages/react-native/React/Base/RCTBundleConsumer.h b/packages/react-native/React/Base/RCTBundleConsumer.h new file mode 100644 index 000000000000..8f1eb972424b --- /dev/null +++ b/packages/react-native/React/Base/RCTBundleConsumer.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import + +/** + * Provides the interface needed to register a Bundle Consumer module. + */ +@protocol RCTBundleConsumer + +@property (nonatomic, strong, readwrite) NSBigStringBuffer *scriptBuffer; + +@property (nonatomic, strong, readwrite) NSString *sourceURL; + +@end diff --git a/packages/react-native/React/Base/RCTJavaScriptLoader.h b/packages/react-native/React/Base/RCTJavaScriptLoader.h index 9893e6931660..aa2753b35cad 100755 --- a/packages/react-native/React/Base/RCTJavaScriptLoader.h +++ b/packages/react-native/React/Base/RCTJavaScriptLoader.h @@ -41,12 +41,12 @@ NS_ENUM(NSInteger){ /** * URL of the source object. */ -@property (strong, nonatomic, readonly) NSURL *url; +@property (strong, nonatomic, readwrite) NSURL *url; /** * JS source (or simply the binary header in the case of a RAM bundle). */ -@property (strong, nonatomic, readonly) NSData *data; +@property (strong, nonatomic, readwrite) NSData *data; /** * Length of the entire JS bundle. Note that self.length != self.data.length in the case of certain bundle formats. For @@ -56,7 +56,7 @@ NS_ENUM(NSInteger){ * - self.data.length is the length of the bundle header, i.e. sizeof(facebook::react::BundleHeader) * - self.length is the length of the entire bundle file (header + contents) */ -@property (nonatomic, readonly) NSUInteger length; +@property (nonatomic, readwrite) NSUInteger length; /** * Returns number of files changed when building this bundle: @@ -65,7 +65,7 @@ NS_ENUM(NSInteger){ * - RCTSourceFilesChangedCountRebuiltFromScratch if the source was rebuilt from scratch by the bundler * - Otherwise, the number of files changed when incrementally rebuilding the source */ -@property (nonatomic, readonly) NSInteger filesChangedCount; +@property (nonatomic, readwrite) NSInteger filesChangedCount; @end diff --git a/packages/react-native/React/Base/RCTTurboModuleRegistry.h b/packages/react-native/React/Base/RCTTurboModuleRegistry.h index 8ad5d06af116..dcfb844512d4 100644 --- a/packages/react-native/React/Base/RCTTurboModuleRegistry.h +++ b/packages/react-native/React/Base/RCTTurboModuleRegistry.h @@ -4,6 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ +#import /** * A protocol that allows TurboModules to do lookup on other TurboModules. @@ -11,6 +12,7 @@ */ @protocol RCTTurboModuleRegistry - (id)moduleForName:(const char *)moduleName; +- (NSMutableArray> *)modulesRespondingToSelector:(SEL)selector; /** * Rationale: diff --git a/packages/react-native/React/CxxBridge/NSBigStringBuffer.h b/packages/react-native/React/CxxBridge/NSBigStringBuffer.h new file mode 100644 index 000000000000..8643c17a5ae5 --- /dev/null +++ b/packages/react-native/React/CxxBridge/NSBigStringBuffer.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#ifdef __cplusplus +#import +#import + +using namespace facebook; +using namespace facebook::react; +#endif // __cplusplus + +@interface NSBigStringBuffer : NSObject +#ifdef __cplusplus + +{ + std::shared_ptr _buffer; +} + +- (instancetype)initWithSharedPtr:(const std::shared_ptr &)buffer; +- (const std::shared_ptr &)getBuffer; +#endif // __cplusplus + +@end diff --git a/packages/react-native/React/CxxBridge/NSBigStringBuffer.mm b/packages/react-native/React/CxxBridge/NSBigStringBuffer.mm new file mode 100644 index 000000000000..20ec1a93bc7f --- /dev/null +++ b/packages/react-native/React/CxxBridge/NSBigStringBuffer.mm @@ -0,0 +1,23 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "NSBigStringBuffer.h" + +@implementation NSBigStringBuffer + +- (instancetype)initWithSharedPtr:(const std::shared_ptr&)buffer { + if (self = [super init]) { + _buffer = buffer; + } + return self; +} + +- (const std::shared_ptr&)getBuffer { + return _buffer; +} + +@end diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.kt index 28e3bc0772b5..4998d96fe16e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactPackageTurboModuleManagerDelegate.kt @@ -149,6 +149,21 @@ public abstract class ReactPackageTurboModuleManagerDelegate : TurboModuleManage return resolvedModule as TurboModule } + fun getModulesConformingToInterfaceNames(clazz: Class): List { + val moduleNames = mutableListOf() + + for (moduleProvider in moduleProviders) { + val moduleInfos = packageModuleInfos[moduleProvider]?.values ?: continue + for (moduleInfo in moduleInfos) { + val module = moduleProvider.getModule(moduleInfo.name) + if (clazz.isInstance(module)) { + moduleNames.add(moduleInfo.name) + } + } + } + return moduleNames + } + override fun unstable_isModuleRegistered(moduleName: String): Boolean { for (moduleProvider in moduleProviders) { val moduleInfo: ReactModuleInfo? = packageModuleInfos[moduleProvider]?.get(moduleName) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/BundleConsumer.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/BundleConsumer.kt new file mode 100644 index 000000000000..a9f4656e0d95 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/BundleConsumer.kt @@ -0,0 +1,15 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.bridge + +import com.facebook.react.fabric.BigStringBufferWrapper + +public interface BundleConsumer { + public fun setScriptWrapper(scriptWrapper: BigStringBufferWrapper) + public fun setSourceURL(sourceURL: String) +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/BigStringBufferWrapper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/BigStringBufferWrapper.kt new file mode 100644 index 000000000000..1d41653271aa --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/BigStringBufferWrapper.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.fabric + +import android.annotation.SuppressLint +import android.content.res.AssetManager +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStripAny + +/** TODO: Description */ +@SuppressLint("MissingNativeLoadLibrary") +@DoNotStripAny +public class BigStringBufferWrapper { + + private val mHybridData: HybridData + + public constructor(fileName: String) { + mHybridData = initHybridFromFile(fileName) + } + + public constructor(assetManager: AssetManager, assetURL: String) { + mHybridData = initHybridFromAssets(assetManager, assetURL) + } + + private external fun initHybridFromFile(fileName: String): HybridData + + private external fun initHybridFromAssets( + assetManager: AssetManager, + assetURL: String + ): HybridData +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.kt index 71ebba6e7cb5..471428fd2e13 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.kt @@ -209,6 +209,12 @@ public class TurboModuleManager( return module } + public fun getModulesConformingToInterfaceNames( + clazz: Class + ): List { + return delegate?.getModulesConformingToInterfaceNames(clazz) ?: emptyList() + } + /** * Given a ModuleHolder, and the TurboModule's moduleName, return the TurboModule instance. * diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManagerDelegate.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManagerDelegate.kt index 202e8aecb607..3584b1f84852 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManagerDelegate.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManagerDelegate.kt @@ -36,6 +36,10 @@ public abstract class TurboModuleManagerDelegate { */ public abstract fun getModule(moduleName: String): TurboModule? + public abstract fun getModulesConformingToInterfaceNames( + clazz: Class + ): List + public abstract fun unstable_isModuleRegistered(moduleName: String): Boolean /** diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.kt index 82361d898151..e8371263727c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.kt @@ -20,6 +20,7 @@ import com.facebook.react.DebugCorePackage import com.facebook.react.ReactPackage import com.facebook.react.ViewManagerOnDemandReactPackage import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.BundleConsumer import com.facebook.react.bridge.JSBundleLoader import com.facebook.react.bridge.JSBundleLoaderDelegate import com.facebook.react.bridge.JavaScriptContextHolder @@ -42,6 +43,7 @@ import com.facebook.react.common.annotations.FrameworkAPI import com.facebook.react.common.annotations.UnstableReactNativeAPI import com.facebook.react.devsupport.StackTraceHelper import com.facebook.react.devsupport.interfaces.DevSupportManager +import com.facebook.react.fabric.BigStringBufferWrapper import com.facebook.react.fabric.ComponentFactory import com.facebook.react.fabric.FabricUIManager import com.facebook.react.fabric.FabricUIManagerBinding @@ -285,6 +287,15 @@ internal class ReactInstance( } } + fun beforeLoad(scriptWrapper: BigStringBufferWrapper, sourceURL: String){ + val bundleConsumers = turboModuleManager.getModulesConformingToInterfaceNames(BundleConsumer::class.java) + for(name in bundleConsumers) { + val module = turboModuleManager.getModule(name) as BundleConsumer + module.setScriptWrapper(scriptWrapper); + module.setSourceURL(sourceURL); + } + } + fun loadJSBundle(bundleLoader: JSBundleLoader) { Systrace.beginSection(Systrace.TRACE_TAG_REACT, "ReactInstance.loadJSBundle") bundleLoader.loadScript( @@ -295,11 +306,18 @@ internal class ReactInstance( loadSynchronously: Boolean ) { context.setSourceURL(sourceURL) - loadJSBundleFromFile(fileName, sourceURL) + + val script = BigStringBufferWrapper(fileName); + + beforeLoad(script, sourceURL); + loadJSBundle(script, sourceURL) } override fun loadSplitBundleFromFile(fileName: String, sourceURL: String) { - loadJSBundleFromFile(fileName, sourceURL) + val script = BigStringBufferWrapper(fileName) + + beforeLoad(script, sourceURL); + loadJSBundle(script, sourceURL) } override fun loadScriptFromAssets( @@ -308,7 +326,12 @@ internal class ReactInstance( loadSynchronously: Boolean ) { context.setSourceURL(assetURL) - loadJSBundleFromAssets(assetManager, assetURL) + + val sourceURL = assetURL.removePrefix("assets://") + val script = BigStringBufferWrapper(assetManager, sourceURL) + + beforeLoad(script, assetURL); + loadJSBundle(script, assetURL) } override fun setSourceURLs(deviceURL: String, remoteURL: String) { @@ -420,7 +443,7 @@ internal class ReactInstance( reactHostInspectorTarget: ReactHostInspectorTarget? ): HybridData - private external fun loadJSBundleFromFile(fileName: String, sourceURL: String) + private external fun loadJSBundle(scriptWrapper: BigStringBufferWrapper, sourceURL: String) private external fun loadJSBundleFromAssets(assetManager: AssetManager, assetURL: String) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/BigStringBufferWrapper.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/BigStringBufferWrapper.cpp new file mode 100644 index 000000000000..0efb9dac6b60 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/BigStringBufferWrapper.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "BigStringBufferWrapper.h" +#include +#include + +using namespace facebook::jni; + +namespace facebook::react { +jni::local_ref +BigStringBufferWrapper::initHybridFromFile( + jni::alias_ref jThis, + std::string fileName) { + std::unique_ptr script; + RecoverableError::runRethrowingAsRecoverable( + [&fileName, &script]() { script = JSBigFileString::fromPath(fileName); }); + auto buffer = std::make_shared(std::move(script)); + return makeCxxInstance(buffer); +} + +jni::local_ref +BigStringBufferWrapper::initHybridFromAssets( + jni::alias_ref jThis, + jni::alias_ref assetManager, + const std::string& sourceURL) { + auto manager = extractAssetManager(assetManager); + auto script = loadScriptFromAssets(manager, sourceURL); + auto buffer = std::make_shared(std::move(script)); + return makeCxxInstance(buffer); +} + +BigStringBufferWrapper::BigStringBufferWrapper( + const std::shared_ptr& script) + : script_(script) {} + +const std::shared_ptr BigStringBufferWrapper::getScript() + const { + return script_; +} + +void BigStringBufferWrapper::registerNatives() { + registerHybrid( + {makeNativeMethod( + "initHybridFromFile", BigStringBufferWrapper::initHybridFromFile), + makeNativeMethod( + "initHybridFromAssets", + BigStringBufferWrapper::initHybridFromAssets)}); +} +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/BigStringBufferWrapper.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/BigStringBufferWrapper.h new file mode 100644 index 000000000000..248f99faf1e0 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/BigStringBufferWrapper.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace facebook::react { + +class BigStringBufferWrapper : public jni::HybridClass { + public: + constexpr static const char* const kJavaDescriptor = + "Lcom/facebook/react/fabric/BigStringBufferWrapper;"; + + static void registerNatives(); + + [[nodiscard]] const std::shared_ptr getScript() const; + + private: + static jni::local_ref initHybridFromFile( + jni::alias_ref jThis, + std::string fileName); + + static jni::local_ref + initHybridFromAssets( + jni::alias_ref jThis, + jni::alias_ref assetManager, + const std::string& assetURL); + + friend HybridBase; + + explicit BigStringBufferWrapper( + const std::shared_ptr& script); + + const std::shared_ptr script_; +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/OnLoad.cpp index 064aec9141b1..78a7ee320190 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/OnLoad.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/OnLoad.cpp @@ -7,6 +7,7 @@ #include +#include "BigStringBufferWrapper.h" #include "ComponentFactory.h" #include "EventBeatManager.h" #include "EventEmitterWrapper.h" @@ -22,5 +23,6 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { facebook::react::StateWrapperImpl::registerNatives(); facebook::react::ComponentFactory::registerNatives(); facebook::react::SurfaceHandlerBinding::registerNatives(); + facebook::react::BigStringBufferWrapper::registerNatives(); }); } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp index 5ffd7492ba81..5414a38d0210 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp @@ -132,24 +132,11 @@ jni::local_ref JReactInstance::initHybrid( jReactHostInspectorTarget); } -void JReactInstance::loadJSBundleFromAssets( - jni::alias_ref assetManager, - const std::string& assetURL) { - const int kAssetsLength = 9; // strlen("assets://"); - auto sourceURL = assetURL.substr(kAssetsLength); - - auto manager = extractAssetManager(assetManager); - auto script = loadScriptFromAssets(manager, sourceURL); - instance_->loadScript(std::move(script), sourceURL); -} - -void JReactInstance::loadJSBundleFromFile( - const std::string& fileName, +void JReactInstance::loadJSBundle( + jni::alias_ref scriptWrapper, const std::string& sourceURL) { - std::unique_ptr script; - RecoverableError::runRethrowingAsRecoverable( - [&fileName, &script]() { script = JSBigFileString::fromPath(fileName); }); - instance_->loadScript(std::move(script), sourceURL); + auto script = scriptWrapper->cthis()->getScript(); + instance_->loadScript(script, sourceURL); } /** @@ -219,10 +206,7 @@ void JReactInstance::registerNatives() { makeNativeMethod("initHybrid", JReactInstance::initHybrid), makeNativeMethod( "createJSTimerExecutor", JReactInstance::createJSTimerExecutor), - makeNativeMethod( - "loadJSBundleFromAssets", JReactInstance::loadJSBundleFromAssets), - makeNativeMethod( - "loadJSBundleFromFile", JReactInstance::loadJSBundleFromFile), + makeNativeMethod("loadJSBundle", JReactInstance::loadJSBundle), makeNativeMethod( "getJSCallInvokerHolder", JReactInstance::getJSCallInvokerHolder), makeNativeMethod( diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h index d6552a8a9789..ff9445980f7c 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -58,12 +59,8 @@ class JReactInstance : public jni::HybridClass { static void registerNatives(); - void loadJSBundleFromAssets( - jni::alias_ref assetManager, - const std::string& assetURL); - - void loadJSBundleFromFile( - const std::string& fileName, + void loadJSBundle( + jni::alias_ref scriptWrapper, const std::string& sourceURL); void callFunctionOnModule( diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp index 29d2910fe7aa..55b84560ee43 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp @@ -214,17 +214,16 @@ std::string simpleBasename(const std::string& path) { * preferably via the runtimeExecutor_. */ void ReactInstance::loadScript( - std::unique_ptr script, + const std::shared_ptr& script, const std::string& sourceURL, std::function&& beforeLoad, std::function&& afterLoad) { - auto buffer = std::make_shared(std::move(script)); std::string scriptName = simpleBasename(sourceURL); runtimeScheduler_->scheduleWork([this, scriptName, sourceURL, - buffer = std::move(buffer), + script, weakBufferedRuntimeExecuter = std::weak_ptr( bufferedRuntimeExecutor_), @@ -240,7 +239,7 @@ void ReactInstance::loadScript( ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str()); } - runtime.evaluateJavaScript(buffer, sourceURL); + runtime.evaluateJavaScript(script, sourceURL); /** * TODO(T183610671): We need a safe/reliable way to enable the js diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h index 51709eebcd7a..2868f9ef52c3 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h @@ -48,7 +48,7 @@ class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate { BindingsInstallFunc bindingsInstallFunc) noexcept; void loadScript( - std::unique_ptr script, + const std::shared_ptr& script, const std::string& sourceURL, std::function&& beforeLoad = nullptr, std::function&& afterLoad = nullptr); diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm index 6536363c0794..862a99f3617c 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm @@ -11,6 +11,7 @@ #import #import +#import #import #import #import @@ -19,6 +20,7 @@ #import #import #import +#import #import #import #import @@ -42,6 +44,7 @@ #import #import #import +#import #import "ObjCTimerRegistry.h" #import "RCTJSThreadManager.h" @@ -568,9 +571,17 @@ - (void)_loadScriptFromSource:(RCTSource *)source } auto script = std::make_unique(source.data); + const auto scriptBuffer = std::make_shared(std::move(script)); const auto *url = deriveSourceURL(source.url).UTF8String; - auto beforeLoad = [waitUntilModuleSetupComplete = self->_waitUntilModuleSetupComplete](jsi::Runtime &_) { + auto beforeLoad = [waitUntilModuleSetupComplete = self->_waitUntilModuleSetupComplete, turboModuleManager = self->_turboModuleManager, scriptBuffer, url](jsi::Runtime &_) { + auto bundleConsumerNames = [RCTModulesConformingToProtocolsProvider bundleConsumerClassNames]; + for (id name in bundleConsumerNames) { + id module = (id)[turboModuleManager moduleForName:[name UTF8String]]; + module.scriptBuffer = [[NSBigStringBuffer alloc] initWithSharedPtr:scriptBuffer]; + module.sourceURL = @(url); + } + if (waitUntilModuleSetupComplete) { waitUntilModuleSetupComplete(); } @@ -578,7 +589,8 @@ - (void)_loadScriptFromSource:(RCTSource *)source auto afterLoad = [](jsi::Runtime &_) { [[NSNotificationCenter defaultCenter] postNotificationName:@"RCTInstanceDidLoadBundle" object:nil]; }; - _reactInstance->loadScript(std::move(script), url, beforeLoad, afterLoad); + + _reactInstance->loadScript(scriptBuffer, url, beforeLoad, afterLoad); } - (void)_handleJSError:(const JsErrorHandler::ProcessedError &)error withRuntime:(jsi::Runtime &)runtime diff --git a/packages/react-native/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js b/packages/react-native/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js index 85e1b3e7e06f..61798ebc1e6e 100644 --- a/packages/react-native/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js +++ b/packages/react-native/scripts/codegen/generate-artifacts-executor/generateCustomURLHandlers.js @@ -33,6 +33,7 @@ function generateCustomURLHandlers( const imageURLLoaderModules = new Set /*::*/(); const imageDataDecoderModules = new Set /*::*/(); const urlRequestHandlersModules = new Set /*::*/(); + const bundleConsumerModules = new Set /*::*/(); // $FlowFixMe[missing-local-annot]] const wrapInArrayIfNecessary = value => @@ -60,6 +61,11 @@ function generateCustomURLHandlers( )?.forEach(moduleName => { urlRequestHandlersModules.add(moduleName); }); + wrapInArrayIfNecessary( + modulesConformingToProtocol.RCTBundleConsumer, + )?.forEach(moduleName => { + bundleConsumerModules.add(moduleName); + }); } // New API @@ -81,6 +87,9 @@ function generateCustomURLHandlers( if (conformsToProtocols.includes('RCTURLRequestHandler')) { urlRequestHandlersModules.add(moduleName); } + if (conformsToProtocols.includes('RCTBundleConsumer')) { + bundleConsumerModules.add(moduleName); + } } } @@ -96,11 +105,16 @@ function generateCustomURLHandlers( .map(className => `@"${className}"`) .join(',\n\t\t'); + const customBundleConsumerClasses = Array.from(bundleConsumerModules) + .map(className => `@"${className}"`) + .join(',\n\t\t'); + const template = fs.readFileSync(MODULES_PROTOCOLS_MM_TEMPLATE_PATH, 'utf8'); const finalMMFile = template .replace(/{imageURLLoaderClassNames}/, customImageURLLoaderClasses) .replace(/{imageDataDecoderClassNames}/, customImageDataDecoderClasses) - .replace(/{requestHandlersClassNames}/, customURLHandlerClasses); + .replace(/{requestHandlersClassNames}/, customURLHandlerClasses) + .replace(/{bundleConsumerClassNames}/, customBundleConsumerClasses); fs.mkdirSync(outputDir, {recursive: true}); diff --git a/packages/react-native/scripts/codegen/templates/RCTModulesConformingToProtocolsProviderH.template b/packages/react-native/scripts/codegen/templates/RCTModulesConformingToProtocolsProviderH.template index 10eb84891755..6190c8da3334 100644 --- a/packages/react-native/scripts/codegen/templates/RCTModulesConformingToProtocolsProviderH.template +++ b/packages/react-native/scripts/codegen/templates/RCTModulesConformingToProtocolsProviderH.template @@ -15,4 +15,6 @@ +(NSArray *)URLRequestHandlerClassNames; ++(NSArray *)bundleConsumerClassNames; + @end diff --git a/packages/react-native/scripts/codegen/templates/RCTModulesConformingToProtocolsProviderMM.template b/packages/react-native/scripts/codegen/templates/RCTModulesConformingToProtocolsProviderMM.template index 7a432b968ca1..1e9cf8d7fe23 100644 --- a/packages/react-native/scripts/codegen/templates/RCTModulesConformingToProtocolsProviderMM.template +++ b/packages/react-native/scripts/codegen/templates/RCTModulesConformingToProtocolsProviderMM.template @@ -51,4 +51,18 @@ return classNames; } ++(NSArray *)bundleConsumerClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + {bundleConsumerClassNames} + ]; + }); + + return classNames; +} + @end