mirror of
https://github.com/status-im/react-native.git
synced 2025-03-03 10:50:35 +00:00
[ReactNative] Add RCTBridgeDelegate
Summary: Add a new bridge delegate protocol to allow a more flexible bridge configuration. For now it just support the pre-existent configurations + providing the JavaScript source to the bridge, that should allow pre-loading sources.
This commit is contained in:
parent
068f396c9b
commit
127f7095dc
@ -14,49 +14,23 @@
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTJavaScriptLoader.h"
|
||||
#import "RCTRootView.h"
|
||||
|
||||
@interface AppDelegate() <RCTBridgeDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(__unused UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
NSURL *jsCodeLocation;
|
||||
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self
|
||||
launchOptions:launchOptions];
|
||||
|
||||
/**
|
||||
* Loading JavaScript code - uncomment the one you want.
|
||||
*
|
||||
* OPTION 1
|
||||
* Load from development server. Start the server from the repository root:
|
||||
*
|
||||
* $ npm start
|
||||
*
|
||||
* To run on device, change `localhost` to the IP address of your computer
|
||||
* (you can get this by typing `ifconfig` into the terminal and selecting the
|
||||
* `inet` value under `en0:`) and make sure your computer and iOS device are
|
||||
* on the same Wi-Fi network.
|
||||
*/
|
||||
|
||||
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/UIExplorer/UIExplorerApp.ios.includeRequire.runModule.bundle?dev=true"];
|
||||
|
||||
/**
|
||||
* OPTION 2
|
||||
* Load from pre-bundled file on disk. To re-generate the static bundle, `cd`
|
||||
* to your Xcode project folder and run
|
||||
*
|
||||
* $ curl 'http://localhost:8081/Examples/UIExplorer/UIExplorerApp.ios.includeRequire.runModule.bundle' -o main.jsbundle
|
||||
*
|
||||
* then add the `main.jsbundle` file to your project and uncomment this line:
|
||||
*/
|
||||
|
||||
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
|
||||
#if RUNNING_ON_CI
|
||||
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
#endif
|
||||
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
|
||||
moduleName:@"UIExplorerApp"
|
||||
launchOptions:launchOptions];
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
||||
moduleName:@"UIExplorerApp"];
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
UIViewController *rootViewController = [[UIViewController alloc] init];
|
||||
@ -66,4 +40,50 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSURL *)sourceURLForBridge:(__unused RCTBridge *)bridge
|
||||
{
|
||||
NSURL *sourceURL;
|
||||
|
||||
/**
|
||||
* Loading JavaScript code - uncomment the one you want.
|
||||
*
|
||||
* OPTION 1
|
||||
* Load from development server. Start the server from the repository root:
|
||||
*
|
||||
* $ npm start
|
||||
*
|
||||
* To run on device, change `localhost` to the IP address of your computer
|
||||
* (you can get this by typing `ifconfig` into the terminal and selecting the
|
||||
* `inet` value under `en0:`) and make sure your computer and iOS device are
|
||||
* on the same Wi-Fi network.
|
||||
*/
|
||||
|
||||
sourceURL = [NSURL URLWithString:@"http://localhost:8081/Examples/UIExplorer/UIExplorerApp.ios.includeRequire.runModule.bundle?dev=true"];
|
||||
|
||||
/**
|
||||
* OPTION 2
|
||||
* Load from pre-bundled file on disk. To re-generate the static bundle, `cd`
|
||||
* to your Xcode project folder and run
|
||||
*
|
||||
* $ curl 'http://localhost:8081/Examples/UIExplorer/UIExplorerApp.ios.includeRequire.runModule.bundle' -o main.jsbundle
|
||||
*
|
||||
* then add the `main.jsbundle` file to your project and uncomment this line:
|
||||
*/
|
||||
|
||||
// sourceURL = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
|
||||
#if RUNNING_ON_CI
|
||||
sourceURL = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||
#endif
|
||||
|
||||
return sourceURL;
|
||||
}
|
||||
|
||||
- (void)loadSourceForBridge:(RCTBridge *)bridge
|
||||
withBlock:(RCTSourceLoadBlock)loadCallback
|
||||
{
|
||||
[RCTJavaScriptLoader loadBundleAtURL:[self sourceURLForBridge:bridge]
|
||||
onComplete:loadCallback];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -149,7 +149,11 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
- (void)executeApplicationScript:(NSString *)script sourceURL:(NSURL *)URL onComplete:(RCTJavaScriptCompleteBlock)onComplete
|
||||
{
|
||||
NSDictionary *message = @{@"method": @"executeApplicationScript", @"url": [URL absoluteString], @"inject": _injectedObjects};
|
||||
NSDictionary *message = @{
|
||||
@"method": @"executeApplicationScript",
|
||||
@"url": RCTNullIfNil([URL absoluteString]),
|
||||
@"inject": _injectedObjects,
|
||||
};
|
||||
[self sendMessage:message waitForReply:^(NSError *error, NSDictionary *reply) {
|
||||
onComplete(error);
|
||||
}];
|
||||
|
@ -156,6 +156,11 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
|
||||
_parentBridge.bundleURL = bundleURL;
|
||||
}
|
||||
|
||||
- (id<RCTBridgeDelegate>)delegate
|
||||
{
|
||||
return _parentBridge.delegate;
|
||||
}
|
||||
|
||||
- (BOOL)isLoading
|
||||
{
|
||||
return _loading;
|
||||
@ -172,7 +177,17 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
|
||||
|
||||
// Register passed-in module instances
|
||||
NSMutableDictionary *preregisteredModules = [[NSMutableDictionary alloc] init];
|
||||
for (id<RCTBridgeModule> module in self.moduleProvider ? self.moduleProvider() : nil) {
|
||||
|
||||
NSArray *extraModules = nil;
|
||||
if (self.delegate) {
|
||||
if ([self.delegate respondsToSelector:@selector(extraModulesForBridge:)]) {
|
||||
extraModules = [self.delegate extraModulesForBridge:_parentBridge];
|
||||
}
|
||||
} else if (self.moduleProvider) {
|
||||
extraModules = self.moduleProvider();
|
||||
}
|
||||
|
||||
for (id<RCTBridgeModule> module in extraModules) {
|
||||
preregisteredModules[RCTBridgeModuleNameForClass([module class])] = module;
|
||||
}
|
||||
|
||||
@ -261,7 +276,6 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
|
||||
}
|
||||
}];
|
||||
|
||||
NSURL *bundleURL = _parentBridge.bundleURL;
|
||||
if (_javaScriptExecutor == nil) {
|
||||
|
||||
/**
|
||||
@ -270,24 +284,15 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
|
||||
*/
|
||||
_loading = NO;
|
||||
|
||||
} else if (!bundleURL) {
|
||||
|
||||
// Allow testing without a script
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_loading = NO;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
|
||||
object:_parentBridge
|
||||
userInfo:@{ @"bridge": self }];
|
||||
});
|
||||
} else {
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptWillStartLoadingNotification
|
||||
object:self
|
||||
userInfo:@{ @"bridge": self }];
|
||||
RCTProfileBeginEvent();
|
||||
RCTPerformanceLoggerStart(RCTPLScriptDownload);
|
||||
RCTJavaScriptLoader *loader = [[RCTJavaScriptLoader alloc] initWithBridge:self];
|
||||
[loader loadBundleAtURL:bundleURL onComplete:^(NSError *error, NSString *script) {
|
||||
RCTProfileBeginEvent();
|
||||
NSURL *sourceURL = self.delegate ? [self.delegate sourceURLForBridge:_parentBridge] : self.bundleURL;
|
||||
void (^loadCallback)(NSError *, NSString *) = ^(NSError *error, NSString *script) {
|
||||
RCTPerformanceLoggerEnd(RCTPLScriptDownload);
|
||||
RCTProfileEndEvent(@"JavaScript download", @"init,download", @[]);
|
||||
|
||||
@ -306,7 +311,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
|
||||
});
|
||||
|
||||
RCTSourceCode *sourceCodeModule = self.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])];
|
||||
sourceCodeModule.scriptURL = bundleURL;
|
||||
sourceCodeModule.scriptURL = sourceURL;
|
||||
sourceCodeModule.scriptText = script;
|
||||
if (error) {
|
||||
|
||||
@ -326,7 +331,7 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
|
||||
|
||||
} else {
|
||||
|
||||
[self enqueueApplicationScript:script url:bundleURL onComplete:^(NSError *loadError) {
|
||||
[self enqueueApplicationScript:script url:sourceURL onComplete:^(NSError *loadError) {
|
||||
|
||||
if (loadError) {
|
||||
[[RCTRedBox sharedInstance] showError:loadError];
|
||||
@ -345,7 +350,22 @@ RCT_NOT_IMPLEMENTED(-initWithBundleURL:(__unused NSURL *)bundleURL
|
||||
userInfo:@{ @"bridge": self }];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:withBlock:)]) {
|
||||
[self.delegate loadSourceForBridge:_parentBridge withBlock:loadCallback];
|
||||
} else if (sourceURL) {
|
||||
[RCTJavaScriptLoader loadBundleAtURL:sourceURL
|
||||
onComplete:loadCallback];
|
||||
} else {
|
||||
// Allow testing without a script
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_loading = NO;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
|
||||
object:_parentBridge
|
||||
userInfo:@{ @"bridge": self }];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTBridgeDelegate.h"
|
||||
#import "RCTBridgeModule.h"
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTFrameUpdate.h"
|
||||
@ -70,7 +71,22 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
|
||||
*/
|
||||
@interface RCTBridge : NSObject <RCTInvalidating>
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new bridge with a custom RCTBridgeDelegate.
|
||||
*
|
||||
* All the interaction with the JavaScript context should be done using the bridge
|
||||
* instance of the RCTBridgeModules. Modules will be automatically instantiated
|
||||
* using the default contructor, but you can optionally pass in an array of
|
||||
* pre-initialized module instances if they require additional init parameters
|
||||
* or configuration.
|
||||
*/
|
||||
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate
|
||||
launchOptions:(NSDictionary *)launchOptions NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use initWithDelegate:launchOptions: instead
|
||||
*
|
||||
* The designated initializer. This creates a new bridge on top of the specified
|
||||
* executor. The bridge should then be used for all subsequent communication
|
||||
* with the JavaScript code running in the executor. Modules will be automatically
|
||||
@ -100,8 +116,17 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
|
||||
*/
|
||||
@property (nonatomic, strong) NSURL *bundleURL;
|
||||
|
||||
/**
|
||||
* The class of the executor currently being used *or* to be used after the next
|
||||
* reload.
|
||||
*/
|
||||
@property (nonatomic, strong) Class executorClass;
|
||||
|
||||
/**
|
||||
* The delegate provided during the bridge initialization
|
||||
*/
|
||||
@property (nonatomic, weak, readonly) id<RCTBridgeDelegate> delegate;
|
||||
|
||||
/**
|
||||
* The event dispatcher is a wrapper around -enqueueJSCall:args: that provides a
|
||||
* higher-level interface for sending UI events such as touches and text input.
|
||||
|
@ -137,6 +137,22 @@ dispatch_queue_t RCTJSThread;
|
||||
});
|
||||
}
|
||||
|
||||
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate
|
||||
launchOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
RCTAssertMainThread();
|
||||
|
||||
if ((self = [super init])) {
|
||||
RCTPerformanceLoggerStart(RCTPLTTI);
|
||||
|
||||
_delegate = delegate;
|
||||
_launchOptions = [launchOptions copy];
|
||||
[self setUp];
|
||||
[self bindKeys];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
|
||||
moduleProvider:(RCTBridgeModuleProviderBlock)block
|
||||
launchOptions:(NSDictionary *)launchOptions
|
||||
|
23
React/Base/RCTBridgeDelegate.h
Normal file
23
React/Base/RCTBridgeDelegate.h
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
typedef void (^RCTSourceLoadBlock)(NSError *error, NSString *source);
|
||||
|
||||
@class RCTBridge;
|
||||
|
||||
@protocol RCTBridgeDelegate <NSObject>
|
||||
|
||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge;
|
||||
|
||||
@optional
|
||||
|
||||
- (NSArray *)extraModulesForBridge:(RCTBridge *)bridge;
|
||||
- (void)loadSourceForBridge:(RCTBridge *)bridge withBlock:(RCTSourceLoadBlock)loadCallback;
|
||||
|
||||
@end
|
@ -9,7 +9,7 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTJavaScriptExecutor.h"
|
||||
#import "RCTBridgeDelegate.h"
|
||||
|
||||
@class RCTBridge;
|
||||
|
||||
@ -20,8 +20,6 @@
|
||||
*/
|
||||
@interface RCTJavaScriptLoader : NSObject
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)loadBundleAtURL:(NSURL *)moduleURL onComplete:(void (^)(NSError *, NSString *))onComplete;
|
||||
+ (void)loadBundleAtURL:(NSURL *)moduleURL onComplete:(RCTSourceLoadBlock)onComplete;
|
||||
|
||||
@end
|
||||
|
@ -15,23 +15,10 @@
|
||||
#import "RCTUtils.h"
|
||||
|
||||
@implementation RCTJavaScriptLoader
|
||||
{
|
||||
__weak RCTBridge *_bridge;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||
{
|
||||
RCTAssert(bridge, @"bridge parameter is required");
|
||||
|
||||
if ((self = [super init])) {
|
||||
_bridge = bridge;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(-init)
|
||||
|
||||
- (void)loadBundleAtURL:(NSURL *)scriptURL onComplete:(void (^)(NSError *, NSString *))onComplete
|
||||
+ (void)loadBundleAtURL:(NSURL *)scriptURL onComplete:(RCTSourceLoadBlock)onComplete
|
||||
{
|
||||
// Sanitize the script URL
|
||||
scriptURL = [RCTConvert NSURL:scriptURL.absoluteString];
|
||||
|
@ -197,6 +197,7 @@
|
||||
14435CE41AAC4AE100FC20F4 /* RCTMapManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapManager.m; sourceTree = "<group>"; };
|
||||
146459241B06C49500B389AA /* RCTFPSGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFPSGraph.h; sourceTree = "<group>"; };
|
||||
146459251B06C49500B389AA /* RCTFPSGraph.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFPSGraph.m; sourceTree = "<group>"; };
|
||||
1482F9E61B55B927000ADFF3 /* RCTBridgeDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeDelegate.h; sourceTree = "<group>"; };
|
||||
14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModuleMethod.h; sourceTree = "<group>"; };
|
||||
14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleMethod.m; sourceTree = "<group>"; };
|
||||
14C2CA721B3AC64300E6CBB2 /* RCTModuleData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModuleData.h; sourceTree = "<group>"; };
|
||||
@ -482,6 +483,7 @@
|
||||
1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */,
|
||||
83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */,
|
||||
83CBBA501A601E3B00E9B192 /* RCTUtils.m */,
|
||||
1482F9E61B55B927000ADFF3 /* RCTBridgeDelegate.h */,
|
||||
);
|
||||
path = Base;
|
||||
sourceTree = "<group>";
|
||||
|
Loading…
x
Reference in New Issue
Block a user