From 03e1662d51653c71ab3a715ef35babea2a295d40 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Tue, 21 Jul 2020 09:16:54 -0700 Subject: [PATCH] Fix loading from Metro in Bridgeless mode Summary: Problem Statement: A native module needs to call a function on `ReactInstance` (in this case `loadScript`). Typically, this is handled by the bridge. Current Bridgeless Solution: Create a new protocol (in this case `RCTJSScriptLoaderModule`) which lets a block be passed in TM init to forward the method call to `ReactInstance`. This is the best thing I could think of right now. Reviewed By: RSNara Differential Revision: D22512748 fbshipit-source-id: c8d9f08e73c86e7a8a95be791b6cbed4f7a67cb2 --- React/Base/RCTJSScriptLoaderModule.h | 18 +++++++++ React/CoreModules/RCTDevSplitBundleLoader.h | 3 +- React/CoreModules/RCTDevSplitBundleLoader.mm | 39 +++++++++++++++----- 3 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 React/Base/RCTJSScriptLoaderModule.h diff --git a/React/Base/RCTJSScriptLoaderModule.h b/React/Base/RCTJSScriptLoaderModule.h new file mode 100644 index 000000000000..a0ba36ed7dcc --- /dev/null +++ b/React/Base/RCTJSScriptLoaderModule.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +@class RCTSource; + +/** + * This protocol should be adopted when a turbo module needs to tell React Native to load a script. + * In bridge-less React Native, it is a replacement for [_bridge loadAndExecuteSplitBundleURL:]. + */ +@protocol RCTJSScriptLoaderModule + +@property (nonatomic, copy, nonnull) void (^loadScript)(RCTSource *source); + +@end diff --git a/React/CoreModules/RCTDevSplitBundleLoader.h b/React/CoreModules/RCTDevSplitBundleLoader.h index c32f60d9750a..52a115c12a87 100644 --- a/React/CoreModules/RCTDevSplitBundleLoader.h +++ b/React/CoreModules/RCTDevSplitBundleLoader.h @@ -6,7 +6,8 @@ */ #import +#import #import -@interface RCTDevSplitBundleLoader : NSObject +@interface RCTDevSplitBundleLoader : NSObject @end diff --git a/React/CoreModules/RCTDevSplitBundleLoader.mm b/React/CoreModules/RCTDevSplitBundleLoader.mm index 73d0c98e692d..ec524cad6bf6 100644 --- a/React/CoreModules/RCTDevSplitBundleLoader.mm +++ b/React/CoreModules/RCTDevSplitBundleLoader.mm @@ -12,6 +12,7 @@ #import #import #import +#import #import #import "CoreModulesPlugins.h" @@ -23,10 +24,11 @@ @interface RCTDevSplitBundleLoader () #if RCT_DEV_MENU -@implementation RCTDevSplitBundleLoader { -} +@implementation RCTDevSplitBundleLoader @synthesize bridge = _bridge; +@synthesize loadScript = _loadScript; +@synthesize turboModuleRegistry = _turboModuleRegistry; RCT_EXPORT_MODULE() @@ -46,13 +48,32 @@ - (void)setBridge:(RCTBridge *)bridge : (RCTPromiseRejectBlock)reject) { NSURL *sourceURL = [[RCTBundleURLProvider sharedSettings] jsBundleURLForSplitBundleRoot:bundlePath]; - [_bridge loadAndExecuteSplitBundleURL:sourceURL - onError:^(NSError *error) { - reject(@"E_BUNDLE_LOAD_ERROR", [error localizedDescription], error); - } - onComplete:^() { - resolve(@YES); - }]; + if (_bridge) { + [_bridge loadAndExecuteSplitBundleURL:sourceURL + onError:^(NSError *error) { + reject(@"E_BUNDLE_LOAD_ERROR", [error localizedDescription], error); + } + onComplete:^() { + resolve(@YES); + }]; + } else { + __weak __typeof(self) weakSelf = self; + [RCTJavaScriptLoader loadBundleAtURL:sourceURL + onProgress:^(RCTLoadingProgress *progressData) { + // TODO: Setup loading bar. + } + onComplete:^(NSError *error, RCTSource *source) { + if (error) { + reject(@"E_BUNDLE_LOAD_ERROR", [error localizedDescription], error); + return; + } + __typeof(self) strongSelf = weakSelf; + strongSelf->_loadScript(source); + RCTDevSettings *devSettings = [strongSelf->_turboModuleRegistry moduleForName:"RCTDevSettings"]; + [devSettings setupHMRClientWithAdditionalBundleURL:source.url]; + resolve(@YES); + }]; + } } - (std::shared_ptr)getTurboModule:(const ObjCTurboModule::InitParams &)params