Skip to content

Commit 8b8b85b

Browse files
cipolleschifacebook-github-bot
authored andcommitted
Fix Connect to Metro after Reload in Bridgeless mode (#43994)
Summary: Pull Request resolved: #43994 We received [this issue](#43764) from OSS where an app can't connect to Metro on reloads in the following scenario: * Start the App when metro does not run. * Observe the error screen * Start Metro * Press Reload * Observe the error message again While the desired behavior should be to connect to Metro now that this is running. The root cause of the problem is that the RCTHost is initialized with a value of the `bundleURL` that is `nil`. Upon reload, the RCTHost is **not** recreated: the instance is restarted, but with the previous `bundleURL`, which is still `nil`. The solution is to initialize the `RCTHost` with a closure that re-evaluate the `bundleURL` whenever it is invoked and to evaluate it only on `start`, to keep the initialization path light. This way, when the app is started with Metro not running, the `bundleURL` is `nil`. But when it is reloaded with Metro starting, the `bundleURL` is properly initialized. Note that the changes in this diff are not breaking as I reimplemented (and deprecated) the old initializer so that they should work in the same way. ## Changelog: [iOS][Fixed] - Let RCTHost be initialized with a function to provide the `bundleURL` so that it can connect to metro on Reload when the url changes. Reviewed By: dmytrorykun Differential Revision: D55916135 fbshipit-source-id: 6927b2154870245f28f42d26bd0209b28c9518f2
1 parent a98c54f commit 8b8b85b

File tree

6 files changed

+73
-25
lines changed

6 files changed

+73
-25
lines changed

packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,18 @@ - (Class)getModuleClassFromName:(const char *)name
248248

249249
- (RCTRootViewFactory *)createRCTRootViewFactory
250250
{
251+
__weak __typeof(self) weakSelf = self;
252+
RCTBundleURLBlock bundleUrlBlock = ^{
253+
RCTAppDelegate *strongSelf = weakSelf;
254+
return strongSelf.bundleURL;
255+
};
256+
251257
RCTRootViewFactoryConfiguration *configuration =
252-
[[RCTRootViewFactoryConfiguration alloc] initWithBundleURL:self.bundleURL
253-
newArchEnabled:self.fabricEnabled
254-
turboModuleEnabled:self.turboModuleEnabled
255-
bridgelessEnabled:self.bridgelessEnabled];
258+
[[RCTRootViewFactoryConfiguration alloc] initWithBundleURLBlock:bundleUrlBlock
259+
newArchEnabled:self.fabricEnabled
260+
turboModuleEnabled:self.turboModuleEnabled
261+
bridgelessEnabled:self.bridgelessEnabled];
256262

257-
__weak __typeof(self) weakSelf = self;
258263
configuration.createRootViewWithBridge = ^UIView *(RCTBridge *bridge, NSString *moduleName, NSDictionary *initProps)
259264
{
260265
return [weakSelf createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps];

packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ typedef UIView *_Nonnull (
2424
typedef RCTBridge *_Nonnull (
2525
^RCTCreateBridgeWithDelegateBlock)(id<RCTBridgeDelegate> delegate, NSDictionary *launchOptions);
2626
typedef NSURL *_Nullable (^RCTSourceURLForBridgeBlock)(RCTBridge *bridge);
27+
typedef NSURL *_Nullable (^RCTBundleURLBlock)(void);
2728
typedef NSArray<id<RCTBridgeModule>> *_Nonnull (^RCTExtraModulesForBridgeBlock)(RCTBridge *bridge);
2829
typedef NSDictionary<NSString *, Class> *_Nonnull (^RCTExtraLazyModuleClassesForBridge)(RCTBridge *bridge);
2930
typedef BOOL (^RCTBridgeDidNotFindModuleBlock)(RCTBridge *bridge, NSString *moduleName);
@@ -41,7 +42,7 @@ typedef BOOL (^RCTBridgeDidNotFindModuleBlock)(RCTBridge *bridge, NSString *modu
4142
@property (nonatomic, assign, readonly) BOOL turboModuleEnabled;
4243

4344
/// Return the bundle URL for the main bundle.
44-
@property (nonatomic) NSURL *bundleURL;
45+
@property (nonatomic, nonnull) RCTBundleURLBlock bundleURLBlock;
4546

4647
/**
4748
* Use this method to initialize a new instance of `RCTRootViewFactoryConfiguration` by passing a `bundleURL`
@@ -52,10 +53,15 @@ typedef BOOL (^RCTBridgeDidNotFindModuleBlock)(RCTBridge *bridge, NSString *modu
5253
* pointing to a path inside the app resources, e.g. `file://.../main.jsbundle`.
5354
*
5455
*/
56+
- (instancetype)initWithBundleURLBlock:(RCTBundleURLBlock)bundleURLBlock
57+
newArchEnabled:(BOOL)newArchEnabled
58+
turboModuleEnabled:(BOOL)turboModuleEnabled
59+
bridgelessEnabled:(BOOL)bridgelessEnabled NS_DESIGNATED_INITIALIZER;
60+
5561
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
5662
newArchEnabled:(BOOL)newArchEnabled
5763
turboModuleEnabled:(BOOL)turboModuleEnabled
58-
bridgelessEnabled:(BOOL)bridgelessEnabled;
64+
bridgelessEnabled:(BOOL)bridgelessEnabled __deprecated;
5965

6066
/**
6167
* Block that allows to override logic of creating root view instance.

packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,23 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL
5757
newArchEnabled:(BOOL)newArchEnabled
5858
turboModuleEnabled:(BOOL)turboModuleEnabled
5959
bridgelessEnabled:(BOOL)bridgelessEnabled
60+
{
61+
return [self
62+
initWithBundleURLBlock:^{
63+
return bundleURL;
64+
}
65+
newArchEnabled:newArchEnabled
66+
turboModuleEnabled:turboModuleEnabled
67+
bridgelessEnabled:bridgelessEnabled];
68+
}
69+
70+
- (instancetype)initWithBundleURLBlock:(RCTBundleURLBlock)bundleURLBlock
71+
newArchEnabled:(BOOL)newArchEnabled
72+
turboModuleEnabled:(BOOL)turboModuleEnabled
73+
bridgelessEnabled:(BOOL)bridgelessEnabled
6074
{
6175
if (self = [super init]) {
62-
_bundleURL = bundleURL;
76+
_bundleURLBlock = bundleURLBlock;
6377
_fabricEnabled = newArchEnabled;
6478
_turboModuleEnabled = turboModuleEnabled;
6579
_bridgelessEnabled = bridgelessEnabled;
@@ -214,13 +228,13 @@ - (void)createReactHostIfNeeded:(NSDictionary *)launchOptions
214228
}
215229

216230
__weak __typeof(self) weakSelf = self;
217-
_reactHost = [[RCTHost alloc] initWithBundleURL:[self bundleURL]
218-
hostDelegate:nil
219-
turboModuleManagerDelegate:_turboModuleManagerDelegate
220-
jsEngineProvider:^std::shared_ptr<facebook::react::JSRuntimeFactory>() {
221-
return [weakSelf createJSRuntimeFactory];
222-
}
223-
launchOptions:launchOptions];
231+
_reactHost = [[RCTHost alloc] initWithBundleURLProvider:self->_configuration.bundleURLBlock
232+
hostDelegate:nil
233+
turboModuleManagerDelegate:_turboModuleManagerDelegate
234+
jsEngineProvider:^std::shared_ptr<facebook::react::JSRuntimeFactory>() {
235+
return [weakSelf createJSRuntimeFactory];
236+
}
237+
launchOptions:launchOptions];
224238
[_reactHost setBundleURLProvider:^NSURL *() {
225239
return [weakSelf bundleURL];
226240
}];
@@ -276,7 +290,7 @@ - (BOOL)bridge:(RCTBridge *)bridge didNotFindModule:(NSString *)moduleName
276290

277291
- (NSURL *)bundleURL
278292
{
279-
return self->_configuration.bundleURL;
293+
return self->_configuration.bundleURLBlock();
280294
}
281295

282296
@end

packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost+Internal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
#import "RCTContextContainerHandling.h"
1111

12-
typedef NSURL * (^RCTHostBundleURLProvider)(void);
13-
1412
@interface RCTHost (Internal)
1513

1614
- (void)registerSegmentWithId:(NSNumber *)segmentId path:(NSString *)path;

packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ NS_ASSUME_NONNULL_BEGIN
2121

2222
@protocol RCTTurboModuleManagerDelegate;
2323

24+
typedef NSURL *_Nullable (^RCTHostBundleURLProvider)(void);
25+
2426
// Runtime API
2527

2628
@protocol RCTHostDelegate <NSObject>
@@ -45,11 +47,17 @@ typedef std::shared_ptr<facebook::react::JSRuntimeFactory> (^RCTHostJSEngineProv
4547

4648
@interface RCTHost : NSObject
4749

50+
- (instancetype)initWithBundleURLProvider:(RCTHostBundleURLProvider)provider
51+
hostDelegate:(id<RCTHostDelegate>)hostDelegate
52+
turboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate
53+
jsEngineProvider:(RCTHostJSEngineProvider)jsEngineProvider
54+
launchOptions:(nullable NSDictionary *)launchOptions NS_DESIGNATED_INITIALIZER;
55+
4856
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
4957
hostDelegate:(id<RCTHostDelegate>)hostDelegate
5058
turboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate
5159
jsEngineProvider:(RCTHostJSEngineProvider)jsEngineProvider
52-
launchOptions:(nullable NSDictionary *)launchOptions NS_DESIGNATED_INITIALIZER;
60+
launchOptions:(nullable NSDictionary *)launchOptions __deprecated;
5361

5462
@property (nonatomic, weak, nullable) id<RCTHostRuntimeDelegate> runtimeDelegate;
5563

packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,31 @@ + (void)initialize
7979
_RCTInitializeJSThreadConstantInternal();
8080
}
8181

82-
/**
83-
Host initialization should not be resource intensive. A host may be created before any intention of using React Native
84-
has been expressed.
85-
*/
8682
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
8783
hostDelegate:(id<RCTHostDelegate>)hostDelegate
8884
turboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate
8985
jsEngineProvider:(RCTHostJSEngineProvider)jsEngineProvider
9086
launchOptions:(nullable NSDictionary *)launchOptions
87+
{
88+
return [self
89+
initWithBundleURLProvider:^{
90+
return bundleURL;
91+
}
92+
hostDelegate:hostDelegate
93+
turboModuleManagerDelegate:turboModuleManagerDelegate
94+
jsEngineProvider:jsEngineProvider
95+
launchOptions:launchOptions];
96+
}
97+
98+
/**
99+
Host initialization should not be resource intensive. A host may be created before any intention of using React Native
100+
has been expressed.
101+
*/
102+
- (instancetype)initWithBundleURLProvider:(RCTHostBundleURLProvider)provider
103+
hostDelegate:(id<RCTHostDelegate>)hostDelegate
104+
turboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate
105+
jsEngineProvider:(RCTHostJSEngineProvider)jsEngineProvider
106+
launchOptions:(nullable NSDictionary *)launchOptions
91107
{
92108
if (self = [super init]) {
93109
_hostDelegate = hostDelegate;
@@ -99,7 +115,6 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL
99115
_launchOptions = [launchOptions copy];
100116

101117
__weak RCTHost *weakSelf = self;
102-
103118
auto bundleURLGetter = ^NSURL *()
104119
{
105120
RCTHost *strongSelf = weakSelf;
@@ -124,7 +139,6 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL
124139
return strongSelf->_bundleURLProvider();
125140
};
126141

127-
[self _setBundleURL:bundleURL];
128142
[_bundleManager setBridgelessBundleURLGetter:bundleURLGetter
129143
andSetter:bundleURLSetter
130144
andDefaultGetter:defaultBundleURLGetter];
@@ -170,6 +184,9 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL
170184

171185
- (void)start
172186
{
187+
if (_bundleURLProvider) {
188+
[self _setBundleURL:_bundleURLProvider()];
189+
}
173190
auto &inspectorFlags = jsinspector_modern::InspectorFlags::getInstance();
174191
if (inspectorFlags.getEnableModernCDPRegistry() && !_inspectorPageId.has_value()) {
175192
_inspectorTarget =

0 commit comments

Comments
 (0)