-
Notifications
You must be signed in to change notification settings - Fork 118
feat(react-native-host): extend RNXHostConfig with optional host hooks (1/3) #4144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,12 @@ | |
| #import <React/RCTBridgeDelegate.h> | ||
| #import <React/RCTLog.h> | ||
|
|
||
| #ifdef __cplusplus | ||
| #include <jsi/jsi.h> | ||
| #endif | ||
|
|
||
| @class ReactNativeHost; | ||
|
|
||
| NS_ASSUME_NONNULL_BEGIN | ||
|
|
||
| /// Configuration object for ``ReactNativeHost``. | ||
|
|
@@ -30,6 +36,20 @@ NS_ASSUME_NONNULL_BEGIN | |
| /// Handles a fatal error. | ||
| - (void)onFatalError:(NSError *)error; | ||
|
|
||
| /// Called after the JS instance has finished loading. ``error`` is ``nil`` | ||
| /// on success. | ||
| - (void)host:(ReactNativeHost *)host didLoadInstanceWithError:(nullable NSError *)error | ||
| __attribute__((__swift_name__("host(_:didLoadInstanceWithError:)"))); | ||
|
|
||
| /// Called when the instance is about to be unloaded. | ||
| - (void)hostWillUnloadInstance:(ReactNativeHost *)host; | ||
|
|
||
| #ifdef __cplusplus | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this allowed? Won't we end up with two definitions of this protocol? |
||
| /// Called after host bindings install but before the user JS bundle loads. | ||
| /// Use to evaluate pre-user JS on the runtime. Bridgeless mode only. | ||
| - (void)host:(ReactNativeHost *)host didInitializeRuntime:(facebook::jsi::Runtime &)runtime; | ||
| #endif // __cplusplus | ||
|
|
||
| // MARK: - RCTBridgeDelegate deprecated details (for backwards compatibility) [>=0.84] | ||
|
|
||
| - (NSURL *__nullable)sourceURLForBridge:(RCTBridge *)bridge; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,41 @@ @interface ReactNativeHost () <RCTComponentViewFactoryComponentProvider> | |
| @end | ||
| #endif // USE_CODEGEN_PROVIDER | ||
|
|
||
| #if USE_BRIDGELESS | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this block be in a private header instead? |
||
|
|
||
| // Forwards host:didInitializeRuntime: from RCTHost to the consumer's RNXHostConfig. | ||
| @interface _RNXForwardingRCTHostDelegate : NSObject <RCTHostDelegate> | ||
| - (instancetype)initWithHost:(ReactNativeHost *)host config:(id<RNXHostConfig>)config; | ||
| @end | ||
|
|
||
| @implementation _RNXForwardingRCTHostDelegate { | ||
| __weak ReactNativeHost *_host; | ||
| __weak id<RNXHostConfig> _config; | ||
| } | ||
|
|
||
| - (instancetype)initWithHost:(ReactNativeHost *)host config:(id<RNXHostConfig>)config | ||
| { | ||
| if (self = [super init]) { | ||
| _host = host; | ||
| _config = config; | ||
| } | ||
| return self; | ||
| } | ||
|
|
||
| - (void)host:(RCTHost *)host didInitializeRuntime:(facebook::jsi::Runtime &)runtime | ||
| { | ||
| id<RNXHostConfig> config = _config; | ||
| ReactNativeHost *forwardedHost = _host; | ||
| if (forwardedHost != nil && | ||
| [config respondsToSelector:@selector(host:didInitializeRuntime:)]) { | ||
| [config host:forwardedHost didInitializeRuntime:runtime]; | ||
| } | ||
| } | ||
|
|
||
| @end | ||
|
|
||
| #endif // USE_BRIDGELESS | ||
|
|
||
| @implementation ReactNativeHost { | ||
| __weak id<RNXHostConfig> _config; | ||
| NSDictionary *_launchOptions; | ||
|
|
@@ -44,6 +79,9 @@ @implementation ReactNativeHost { | |
| RCTHost *_reactHost; | ||
| NSLock *_isShuttingDown; | ||
| RNXHostReleaser *_hostReleaser; | ||
| #if USE_BRIDGELESS | ||
| _RNXForwardingRCTHostDelegate *_hostDelegateProxy; | ||
| #endif // USE_BRIDGELESS | ||
| #ifdef USE_REACT_NATIVE_CONFIG | ||
| std::shared_ptr<ReactNativeConfig> _reactNativeConfig; | ||
| #endif // USE_REACT_NATIVE_CONFIG | ||
|
|
@@ -99,11 +137,63 @@ - (instancetype)initWithConfig:(id<RNXHostConfig>)config launchOptions:(NSDictio | |
| }); | ||
| } | ||
|
|
||
| if ([config respondsToSelector:@selector(host:didLoadInstanceWithError:)]) { | ||
| [[NSNotificationCenter defaultCenter] | ||
| addObserver:self | ||
| selector:@selector(_rnxInstanceDidLoad:) | ||
| name:RCTJavaScriptDidLoadNotification | ||
| object:nil]; | ||
| [[NSNotificationCenter defaultCenter] | ||
| addObserver:self | ||
| selector:@selector(_rnxInstanceDidFailToLoad:) | ||
| name:RCTJavaScriptDidFailToLoadNotification | ||
| object:nil]; | ||
| } | ||
| if ([config respondsToSelector:@selector(hostWillUnloadInstance:)]) { | ||
| [[NSNotificationCenter defaultCenter] | ||
| addObserver:self | ||
| selector:@selector(_rnxInstanceWillUnload:) | ||
| name:RCTBridgeWillBeInvalidatedNotification | ||
| object:nil]; | ||
| } | ||
|
Comment on lines
+140
to
+158
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't all of this be contained within |
||
|
|
||
| [self initializeReactHost]; | ||
| } | ||
| return self; | ||
| } | ||
|
|
||
| - (void)dealloc | ||
| { | ||
| [[NSNotificationCenter defaultCenter] removeObserver:self]; | ||
| } | ||
|
|
||
| - (void)_rnxInstanceDidLoad:(NSNotification *)__unused notification | ||
| { | ||
| id<RNXHostConfig> config = _config; | ||
| if ([config respondsToSelector:@selector(host:didLoadInstanceWithError:)]) { | ||
| [config host:self didLoadInstanceWithError:nil]; | ||
| } | ||
| } | ||
|
|
||
| - (void)_rnxInstanceDidFailToLoad:(NSNotification *)notification | ||
| { | ||
| id<RNXHostConfig> config = _config; | ||
| if ([config respondsToSelector:@selector(host:didLoadInstanceWithError:)]) { | ||
| NSError *error = notification.userInfo[@"error"]; | ||
| [config host:self didLoadInstanceWithError:error ?: [NSError errorWithDomain:@"ReactNativeHost" | ||
| code:0 | ||
| userInfo:nil]]; | ||
| } | ||
| } | ||
|
|
||
| - (void)_rnxInstanceWillUnload:(NSNotification *)__unused notification | ||
| { | ||
| id<RNXHostConfig> config = _config; | ||
| if ([config respondsToSelector:@selector(hostWillUnloadInstance:)]) { | ||
| [config hostWillUnloadInstance:self]; | ||
| } | ||
| } | ||
|
|
||
| - (RCTBridge *)bridge | ||
| { | ||
| if (self.isBridgelessEnabled) { | ||
|
|
@@ -303,6 +393,10 @@ - (void)initializeReactHost | |
| #endif | ||
| }; | ||
|
|
||
| // Retained as an ivar because RCTHost stores host delegates weakly. | ||
| _hostDelegateProxy = [[_RNXForwardingRCTHostDelegate alloc] initWithHost:self | ||
| config:_config]; | ||
|
|
||
| __weak __typeof(self) weakSelf = self; | ||
| if ([RCTHost instancesRespondToSelector:@selector | ||
| (initWithBundleURLProvider: | ||
|
|
@@ -312,13 +406,13 @@ - (void)initializeReactHost | |
| initWithBundleURLProvider:^{ | ||
| return [weakSelf sourceURLForBridge:nil]; | ||
| } | ||
| hostDelegate:nil | ||
| hostDelegate:_hostDelegateProxy | ||
| turboModuleManagerDelegate:_turboModuleAdapter | ||
| jsEngineProvider:jsEngineProvider | ||
| launchOptions:_launchOptions]; | ||
| } else { | ||
| _reactHost = [[RCTHost alloc] initWithBundleURL:[self sourceURLForBridge:nil] | ||
| hostDelegate:nil | ||
| hostDelegate:_hostDelegateProxy | ||
| turboModuleManagerDelegate:_turboModuleAdapter | ||
| jsEngineProvider:jsEngineProvider]; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little iffy with the optional error parameter.. the signature makes it feel like there is always an error despite the comment. Alternative is to also expose
failedtoLoadInstanceWithError. Thoughts?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be
- (void)didLoadInstanceWithHost:(ReactNativeHost *)host error: (nullable NSError **)error, where the user passes a ref to an NSError if they're interested.