Skip to content

Commit

Permalink
[Init] Add executor providers to RCTBridge's init method
Browse files Browse the repository at this point in the history
If you construct an RCTBridge you may want to configure the executor. However the constructor synchronously calls `setUp` and sets up the executor. Instead, let the code that constructs the bridge specify the executor and a debug executor up front. This allows for customizing the web view executor with a UIWebView of your choice, or configuring the URL of the debugger proxy that the web socket executor connects to.

Now that RCTRootView takes a bridge in one of its initializers, it is possible to create a bridge with a custom executor and then use that to set up a root view.

Fixes facebook#288
  • Loading branch information
ide committed Apr 10, 2015
1 parent 7047d6e commit accca1d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 12 deletions.
16 changes: 14 additions & 2 deletions React/Base/RCTBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@
/**
* This block can be used to instantiate modules that require additional
* init parameters, or additional configuration prior to being used.
* The bridge will call this block to instatiate the modules, and will
* The bridge will call this block to instantiate the modules, and will
* be responsible for invalidating/releasing them when the bridge is destroyed.
* For this reason, the block should always return new module instances, and
* module instances should not be shared between bridges.
*/
typedef NSArray *(^RCTBridgeModuleProviderBlock)(void);

/**
* A block that provides a new instance of an RCTJavaScript executor. The bridge
* will call this block to define the executor it uses.
*/
typedef id<RCTJavaScriptExecutor>(^RCTJavaScriptExecutorProviderBlock)(void);

/**
* This function returns the module name for a given class.
*/
Expand All @@ -46,7 +52,13 @@ extern NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
*/
- (instancetype)initWithBundlePath:(NSString *)bundlepath
moduleProvider:(RCTBridgeModuleProviderBlock)block
launchOptions:(NSDictionary *)launchOptions NS_DESIGNATED_INITIALIZER;
launchOptions:(NSDictionary *)launchOptions
executorBlock:(RCTJavaScriptExecutorProviderBlock)executorBlock
debugExecutorBlock:(RCTJavaScriptExecutorProviderBlock)debugExecutorBlock NS_DESIGNATED_INITIALIZER;

- (instancetype)initWithBundlePath:(NSString *)bundlepath
moduleProvider:(RCTBridgeModuleProviderBlock)block
launchOptions:(NSDictionary *)launchOptions;

/**
* This method is used to call functions in the JavaScript application context.
Expand Down
49 changes: 39 additions & 10 deletions React/Base/RCTBridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,6 @@ @implementation RCTModuleMethod
NSString *_methodName;
}

static Class _globalExecutorClass;

NS_INLINE NSString *RCTStringUpToFirstArgument(NSString *methodName) {
NSRange colonRange = [methodName rangeOfString:@":"];
if (colonRange.length) {
Expand Down Expand Up @@ -663,7 +661,9 @@ @implementation RCTBridge
RCTSparseArray *_modulesByID;
NSDictionary *_modulesByName;
id<RCTJavaScriptExecutor> _javaScriptExecutor;
Class _executorClass;
RCTJavaScriptExecutorProviderBlock _executorBlock;
RCTJavaScriptExecutorProviderBlock _debugExecutorBlock;
BOOL _usingDebugExecutor;
NSString *_bundlePath;
NSDictionary *_launchOptions;
RCTBridgeModuleProviderBlock _moduleProvider;
Expand All @@ -675,21 +675,53 @@ @implementation RCTBridge
- (instancetype)initWithBundlePath:(NSString *)bundlePath
moduleProvider:(RCTBridgeModuleProviderBlock)block
launchOptions:(NSDictionary *)launchOptions
executorBlock:(RCTJavaScriptExecutorProviderBlock)executorBlock
debugExecutorBlock:(RCTJavaScriptExecutorProviderBlock)debugExecutorBlock
{
if ((self = [super init])) {
_bundlePath = bundlePath;
_moduleProvider = block;
_launchOptions = launchOptions;
_executorBlock = executorBlock;
_debugExecutorBlock = debugExecutorBlock;
[self setUp];
[self bindKeys];
}

return self;
}

- (instancetype)initWithBundlePath:(NSString *)bundlePath
moduleProvider:(RCTBridgeModuleProviderBlock)block
launchOptions:(NSDictionary *)launchOptions
{
return [self initWithBundlePath:bundlePath
moduleProvider:block
launchOptions:launchOptions
executorBlock:^{ return [[RCTContextExecutor alloc] init]; }
debugExecutorBlock:^{
Class executorClass = NSClassFromString(@"RCTWebSocketExecutor");
if (!executorClass) {
RCTLogError(@"WebSocket debugger is not available. Did you forget to include RCTWebSocketExecutor?");
executorClass = [RCTContextExecutor class];
}
return [[executorClass alloc] init];
}];
}

- (void)setUp
{
Class executorClass = _executorClass ?: _globalExecutorClass ?: [RCTContextExecutor class];
_javaScriptExecutor = [[executorClass alloc] init];
if (_usingDebugExecutor) {
if (_debugExecutorBlock) {
_javaScriptExecutor = _debugExecutorBlock();
} else {
RCTLogError(@"Attempting to debug without providing a debug executor; falling back to the default executor");
_javaScriptExecutor = _executorBlock();
}
} else {
_javaScriptExecutor = _executorBlock();
}

_latestJSExecutor = _javaScriptExecutor;
_eventDispatcher = [[RCTEventDispatcher alloc] initWithBridge:self];
_shadowQueue = dispatch_queue_create("com.facebook.ReactKit.ShadowQueue", DISPATCH_QUEUE_SERIAL);
Expand Down Expand Up @@ -801,7 +833,7 @@ - (void)bindKeys
if (!strongSelf) {
return;
}
strongSelf->_executorClass = Nil;
strongSelf->_usingDebugExecutor = NO;
[strongSelf reload];
}];
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"d"
Expand All @@ -811,10 +843,7 @@ - (void)bindKeys
if (!strongSelf) {
return;
}
strongSelf->_executorClass = NSClassFromString(@"RCTWebSocketExecutor");
if (!strongSelf->_executorClass) {
RCTLogError(@"WebSocket debugger is not available. Did you forget to include RCTWebSocketExecutor?");
}
strongSelf->_usingDebugExecutor = YES;
[strongSelf reload];
}];
#endif
Expand Down

0 comments on commit accca1d

Please sign in to comment.