Skip to content

Commit

Permalink
Allow taking control of bundle loading on new arch (#46731)
Browse files Browse the repository at this point in the history
Summary:
On the old architecture you could take control of loading the bundle by implementing
```objc
- (void)loadSourceForBridge:(RCTBridge *)bridge
                 onProgress:(RCTSourceLoadProgressBlock)onProgress
                 onComplete:(RCTSourceLoadBlock)loadCallback;
```
in your `RCTBridgeDelegate`. This is not currently possible in the new architecture.

I've added this using a pretty much identical api by adding a function to both the `RCTInstanceDelegate` and `RCTHostDelegate` protocols. This will be called on the `RCTRootViewFactory`. I've added two properties to the `RCTRootViewFactoryConfiguration`, `loadSourceForHost` and `loadSourceWithProgressForHost`. If one is present, we call it, otherwise we fallback to the normal loading process

## Changelog:

[iOS] [Breaking] - Add ability to control bundle loading on the new architecture similar to `loadSourceForBridge`. Removed some properties from the `RCTRootViewFactory`.

Pull Request resolved: #46731

Test Plan: Rn-tester works as normal and it is working for our use case in expo go.

Reviewed By: blakef

Differential Revision: D63755188

Pulled By: cipolleschi

fbshipit-source-id: f1f26b2775b9e547ce7a23028665797c19bfdd9b
  • Loading branch information
alanjhughes authored and facebook-github-bot committed Oct 3, 2024
1 parent 6a09fc0 commit 7487a2c
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 64 deletions.
15 changes: 1 addition & 14 deletions packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -275,19 +275,6 @@ - (RCTRootViewFactory *)createRCTRootViewFactory
return [weakSelf sourceURLForBridge:bridge];
};

configuration.hostDidStartBlock = ^(RCTHost *_Nonnull host) {
[weakSelf hostDidStart:host];
};

configuration.hostDidReceiveJSErrorStackBlock =
^(RCTHost *_Nonnull host,
NSArray<NSDictionary<NSString *, id> *> *_Nonnull stack,
NSString *_Nonnull message,
NSUInteger exceptionId,
BOOL isFatal) {
[weakSelf host:host didReceiveJSErrorStack:stack message:message exceptionId:exceptionId isFatal:isFatal];
};

if ([self respondsToSelector:@selector(extraModulesForBridge:)]) {
configuration.extraModulesForBridge = ^NSArray<id<RCTBridgeModule>> *_Nonnull(RCTBridge *_Nonnull bridge)
{
Expand All @@ -309,7 +296,7 @@ - (RCTRootViewFactory *)createRCTRootViewFactory
};
}

return [[RCTRootViewFactory alloc] initWithConfiguration:configuration andTurboModuleManagerDelegate:self];
return [[RCTRootViewFactory alloc] initWithTurboModuleDelegate:self hostDelegate:self configuration:configuration];
}

#pragma mark - Feature Flags
Expand Down
28 changes: 5 additions & 23 deletions packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
@protocol RCTCxxBridgeDelegate;
@protocol RCTComponentViewFactoryComponentProvider;
@protocol RCTTurboModuleManagerDelegate;
@protocol RCTHostDelegate;
@class RCTBridge;
@class RCTHost;
@class RCTRootView;
Expand All @@ -30,13 +31,6 @@ typedef NSURL *_Nullable (^RCTBundleURLBlock)(void);
typedef NSArray<id<RCTBridgeModule>> *_Nonnull (^RCTExtraModulesForBridgeBlock)(RCTBridge *bridge);
typedef NSDictionary<NSString *, Class> *_Nonnull (^RCTExtraLazyModuleClassesForBridge)(RCTBridge *bridge);
typedef BOOL (^RCTBridgeDidNotFindModuleBlock)(RCTBridge *bridge, NSString *moduleName);
typedef void (^RCTHostDidStartBlock)(RCTHost *host);
typedef void (^RCTHostDidReceiveJSErrorStackBlock)(
RCTHost *host,
NSArray<NSDictionary<NSString *, id> *> *stack,
NSString *message,
NSUInteger exceptionId,
BOOL isFatal);

#pragma mark - RCTRootViewFactory Configuration
@interface RCTRootViewFactoryConfiguration : NSObject
Expand Down Expand Up @@ -147,22 +141,6 @@ typedef void (^RCTHostDidReceiveJSErrorStackBlock)(
*/
@property (nonatomic, nullable) RCTBridgeDidNotFindModuleBlock bridgeDidNotFindModule;

/**
* Called when `RCTHost` started.
* @parameter: host - The started `RCTHost`.
*/
@property (nonatomic, nullable) RCTHostDidStartBlock hostDidStartBlock;

/**
* Called when `RCTHost` received JS error.
* @parameter: host - `RCTHost` which received js error.
* @parameter: stack - JS error stack.
* @parameter: message - Error message.
* @parameter: exceptionId - Exception ID.
* @parameter: isFatal - YES if JS error is fatal.
*/
@property (nonatomic, nullable) RCTHostDidReceiveJSErrorStackBlock hostDidReceiveJSErrorStackBlock;

@end

#pragma mark - RCTRootViewFactory
Expand All @@ -187,6 +165,10 @@ typedef void (^RCTHostDidReceiveJSErrorStackBlock)(

- (instancetype)initWithConfiguration:(RCTRootViewFactoryConfiguration *)configuration;

- (instancetype)initWithTurboModuleDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate
hostDelegate:(id<RCTHostDelegate>)hostdelegate
configuration:(RCTRootViewFactoryConfiguration *)configuration;

/**
* This method can be used to create new RCTRootViews on demand.
*
Expand Down
44 changes: 19 additions & 25 deletions packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ - (instancetype)initWithBundleURLBlock:(RCTBundleURLBlock)bundleURLBlock

@end

@interface RCTRootViewFactory () <RCTContextContainerHandling, RCTHostDelegate> {
@interface RCTRootViewFactory () <RCTContextContainerHandling> {
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
Expand All @@ -95,15 +95,18 @@ @interface RCTRootViewFactory () <RCTCxxBridgeDelegate> {
@end

@implementation RCTRootViewFactory {
RCTRootViewFactoryConfiguration *_configuration;
__weak id<RCTTurboModuleManagerDelegate> _turboModuleManagerDelegate;
__weak id<RCTHostDelegate> _hostDelegate;
RCTRootViewFactoryConfiguration *_configuration;
}

- (instancetype)initWithConfiguration:(RCTRootViewFactoryConfiguration *)configuration
andTurboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate
- (instancetype)initWithTurboModuleDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate
hostDelegate:(id<RCTHostDelegate>)hostdelegate
configuration:(RCTRootViewFactoryConfiguration *)configuration
{
if (self = [super init]) {
_configuration = configuration;
_hostDelegate = hostdelegate;
_contextContainer = std::make_shared<const facebook::react::ContextContainer>();
_reactNativeConfig = std::make_shared<const facebook::react::EmptyReactNativeConfig>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
Expand All @@ -112,6 +115,17 @@ - (instancetype)initWithConfiguration:(RCTRootViewFactoryConfiguration *)configu
return self;
}

- (instancetype)initWithConfiguration:(RCTRootViewFactoryConfiguration *)configuration
andTurboModuleManagerDelegate:(id<RCTTurboModuleManagerDelegate>)turboModuleManagerDelegate
{
id<RCTHostDelegate> hostDelegate = [turboModuleManagerDelegate conformsToProtocol:@protocol(RCTHostDelegate)]
? (id<RCTHostDelegate>)turboModuleManagerDelegate
: nil;
return [self initWithTurboModuleDelegate:turboModuleManagerDelegate
hostDelegate:hostDelegate
configuration:configuration];
}

- (instancetype)initWithConfiguration:(RCTRootViewFactoryConfiguration *)configuration
{
return [self initWithConfiguration:configuration andTurboModuleManagerDelegate:nil];
Expand Down Expand Up @@ -188,26 +202,6 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
return rootView;
}

#pragma mark - RCTHostDelegate

- (void)hostDidStart:(RCTHost *)host
{
if (self->_configuration.hostDidStartBlock) {
self->_configuration.hostDidStartBlock(host);
}
}

- (void)host:(RCTHost *)host
didReceiveJSErrorStack:(NSArray<NSDictionary<NSString *, id> *> *)stack
message:(NSString *)message
exceptionId:(NSUInteger)exceptionId
isFatal:(BOOL)isFatal
{
if (self->_configuration.hostDidReceiveJSErrorStackBlock) {
self->_configuration.hostDidReceiveJSErrorStackBlock(host, stack, message, exceptionId, isFatal);
}
}

#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
Expand Down Expand Up @@ -266,7 +260,7 @@ - (RCTHost *)createReactHost:(NSDictionary *)launchOptions
__weak __typeof(self) weakSelf = self;
RCTHost *reactHost =
[[RCTHost alloc] initWithBundleURLProvider:self->_configuration.bundleURLBlock
hostDelegate:self
hostDelegate:_hostDelegate
turboModuleManagerDelegate:_turboModuleManagerDelegate
jsEngineProvider:^std::shared_ptr<facebook::react::JSRuntimeFactory>() {
return [weakSelf createJSRuntimeFactory];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ typedef NSURL *_Nullable (^RCTHostBundleURLProvider)(void);

- (void)hostDidStart:(RCTHost *)host;

@optional
- (void)loadBundleAtURL:(NSURL *)sourceURL
onProgress:(RCTSourceLoadProgressBlock)onProgress
onComplete:(RCTSourceLoadBlock)loadCallback;

@end

@protocol RCTHostRuntimeDelegate <NSObject>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,17 @@ - (void)instance:(RCTInstance *)instance didInitializeRuntime:(facebook::jsi::Ru
[self.runtimeDelegate host:self didInitializeRuntime:runtime];
}

- (void)loadBundleAtURL:(NSURL *)sourceURL
onProgress:(RCTSourceLoadProgressBlock)onProgress
onComplete:(RCTSourceLoadBlock)loadCallback
{
if ([_hostDelegate respondsToSelector:@selector(loadBundleAtURL:onProgress:onComplete:)]) {
[_hostDelegate loadBundleAtURL:sourceURL onProgress:onProgress onComplete:loadCallback];
} else {
[RCTJavaScriptLoader loadBundleAtURL:sourceURL onProgress:onProgress onComplete:loadCallback];
}
}

#pragma mark - RCTContextContainerHandling

- (void)didCreateContextContainer:(std::shared_ptr<facebook::react::ContextContainer>)contextContainer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#import <UIKit/UIKit.h>

#import <React/RCTDefines.h>
#import <React/RCTJavaScriptLoader.h>
#import <jsinspector-modern/ReactCdp.h>
#import <react/runtime/JSRuntimeFactory.h>
#import <react/runtime/ReactInstance.h>
Expand Down Expand Up @@ -44,6 +45,10 @@ RCT_EXTERN void RCTInstanceSetRuntimeDiagnosticFlags(NSString *_Nullable flags);

- (void)instance:(RCTInstance *)instance didInitializeRuntime:(facebook::jsi::Runtime &)runtime;

- (void)loadBundleAtURL:(NSURL *)sourceURL
onProgress:(RCTSourceLoadProgressBlock)onProgress
onComplete:(RCTSourceLoadBlock)loadCallback;

@end

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#import <React/RCTDisplayLink.h>
#import <React/RCTEventDispatcherProtocol.h>
#import <React/RCTFollyConvert.h>
#import <React/RCTJavaScriptLoader.h>
#import <React/RCTLog.h>
#import <React/RCTLogBox.h>
#import <React/RCTModuleData.h>
Expand Down Expand Up @@ -416,7 +415,7 @@ - (void)_loadJSBundle:(NSURL *)sourceURL
#endif

__weak __typeof(self) weakSelf = self;
[RCTJavaScriptLoader loadBundleAtURL:sourceURL
[_delegate loadBundleAtURL:sourceURL
onProgress:^(RCTLoadingProgress *progressData) {
__typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
Expand Down

0 comments on commit 7487a2c

Please sign in to comment.