Cleanup
This commit is contained in:
parent
699a9c3e0c
commit
26fd24dc50
|
@ -21,7 +21,7 @@
|
||||||
@interface RCTTestRunner : NSObject
|
@interface RCTTestRunner : NSObject
|
||||||
|
|
||||||
@property (nonatomic, assign) BOOL recordMode;
|
@property (nonatomic, assign) BOOL recordMode;
|
||||||
@property (nonatomic, copy) NSString *script;
|
@property (nonatomic, strong) NSURL *scriptURL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a runner. It's recommended that you use the initRunnerForApp macro instead of calling this directly.
|
* Initialize a runner. It's recommended that you use the initRunnerForApp macro instead of calling this directly.
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
* @param initialProps props that are passed into the component when rendered.
|
* @param initialProps props that are passed into the component when rendered.
|
||||||
* @param expectErrorRegex A regex that must match the error thrown. If no error is thrown, the test fails.
|
* @param expectErrorRegex A regex that must match the error thrown. If no error is thrown, the test fails.
|
||||||
*/
|
*/
|
||||||
- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSRegularExpression *)expectErrorRegex;
|
- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSString *)expectErrorRegex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as runTest:, but allows for passing initialProps for providing mock data or requesting different behaviors, and
|
* Same as runTest:, but allows for passing initialProps for providing mock data or requesting different behaviors, and
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
sanitizedAppName = [sanitizedAppName stringByReplacingOccurrencesOfString:@"\\" withString:@"-"];
|
sanitizedAppName = [sanitizedAppName stringByReplacingOccurrencesOfString:@"\\" withString:@"-"];
|
||||||
_snapshotController = [[FBSnapshotTestController alloc] initWithTestName:sanitizedAppName];
|
_snapshotController = [[FBSnapshotTestController alloc] initWithTestName:sanitizedAppName];
|
||||||
_snapshotController.referenceImagesDirectory = referenceDir;
|
_snapshotController.referenceImagesDirectory = referenceDir;
|
||||||
_script = [NSString stringWithFormat:@"http://localhost:8081/%@.includeRequire.runModule.bundle?dev=true", app];
|
_scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.includeRequire.runModule.bundle?dev=true", app]];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -49,10 +49,10 @@
|
||||||
[self runTest:test module:moduleName initialProps:nil expectErrorBlock:nil];
|
[self runTest:test module:moduleName initialProps:nil expectErrorBlock:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSRegularExpression *)errorRegex
|
- (void)runTest:(SEL)test module:(NSString *)moduleName initialProps:(NSDictionary *)initialProps expectErrorRegex:(NSString *)errorRegex
|
||||||
{
|
{
|
||||||
[self runTest:test module:moduleName initialProps:initialProps expectErrorBlock:^BOOL(NSString *error){
|
[self runTest:test module:moduleName initialProps:initialProps expectErrorBlock:^BOOL(NSString *error){
|
||||||
return [errorRegex numberOfMatchesInString:error options:0 range:NSMakeRange(0, [error length])] > 0;
|
return [error rangeOfString:errorRegex options:NSRegularExpressionSearch].location != NSNotFound;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,11 +66,12 @@
|
||||||
|
|
||||||
RCTTestModule *testModule = [[RCTTestModule alloc] initWithSnapshotController:_snapshotController view:nil];
|
RCTTestModule *testModule = [[RCTTestModule alloc] initWithSnapshotController:_snapshotController view:nil];
|
||||||
testModule.testSelector = test;
|
testModule.testSelector = test;
|
||||||
RCTBridge *bridge = [[RCTBridge alloc] initWithBundlePath:_script
|
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_scriptURL
|
||||||
moduleProvider:^(){
|
moduleProvider:^(){
|
||||||
return @[testModule];
|
return @[testModule];
|
||||||
}
|
}
|
||||||
launchOptions:nil];
|
launchOptions:nil];
|
||||||
|
|
||||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
||||||
moduleName:moduleName];
|
moduleName:moduleName];
|
||||||
testModule.view = rootView;
|
testModule.view = rootView;
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
|
|
||||||
@interface RCTWebSocketExecutor : NSObject <RCTJavaScriptExecutor>
|
@interface RCTWebSocketExecutor : NSObject <RCTJavaScriptExecutor>
|
||||||
|
|
||||||
- (instancetype)initWithURL:(NSURL *)url;
|
- (instancetype)initWithURL:(NSURL *)URL;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#import "RCTWebSocketExecutor.h"
|
#import "RCTWebSocketExecutor.h"
|
||||||
|
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
|
#import "RCTSparseArray.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
#import "SRWebSocket.h"
|
#import "SRWebSocket.h"
|
||||||
|
|
||||||
|
@ -18,10 +19,11 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
|
||||||
@interface RCTWebSocketExecutor () <SRWebSocketDelegate>
|
@interface RCTWebSocketExecutor () <SRWebSocketDelegate>
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation RCTWebSocketExecutor {
|
@implementation RCTWebSocketExecutor
|
||||||
|
{
|
||||||
SRWebSocket *_socket;
|
SRWebSocket *_socket;
|
||||||
NSOperationQueue *_jsQueue;
|
dispatch_queue_t _jsQueue;
|
||||||
NSMutableDictionary *_callbacks;
|
RCTSparseArray *_callbacks;
|
||||||
dispatch_semaphore_t _socketOpenSemaphore;
|
dispatch_semaphore_t _socketOpenSemaphore;
|
||||||
NSMutableDictionary *_injectedObjects;
|
NSMutableDictionary *_injectedObjects;
|
||||||
}
|
}
|
||||||
|
@ -31,23 +33,24 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
|
||||||
return [self initWithURL:[NSURL URLWithString:@"http://localhost:8081/debugger-proxy"]];
|
return [self initWithURL:[NSURL URLWithString:@"http://localhost:8081/debugger-proxy"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithURL:(NSURL *)url
|
- (instancetype)initWithURL:(NSURL *)URL
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
_jsQueue = [[NSOperationQueue alloc] init];
|
|
||||||
_jsQueue.maxConcurrentOperationCount = 1;
|
_jsQueue = dispatch_queue_create("com.facebook.React.WebSocketExecutor", DISPATCH_QUEUE_SERIAL);
|
||||||
_socket = [[SRWebSocket alloc] initWithURL:url];
|
_socket = [[SRWebSocket alloc] initWithURL:URL];
|
||||||
_socket.delegate = self;
|
_socket.delegate = self;
|
||||||
_callbacks = [NSMutableDictionary dictionary];
|
_callbacks = [[RCTSparseArray alloc] init];
|
||||||
_injectedObjects = [NSMutableDictionary dictionary];
|
_injectedObjects = [[NSMutableDictionary alloc] init];
|
||||||
[_socket setDelegateOperationQueue:_jsQueue];
|
[_socket setDelegateDispatchQueue:_jsQueue];
|
||||||
|
|
||||||
|
NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-chrome-devtools" relativeToURL:URL];
|
||||||
NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-chrome-devtools" relativeToURL:url];
|
|
||||||
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil];
|
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil];
|
||||||
|
|
||||||
if (![self connectToProxy]) {
|
if (![self connectToProxy]) {
|
||||||
RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If you are running on the device check if you have the right IP address on `RCTWebSocketExecutor.m` file.", url);
|
RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If \
|
||||||
|
you are running on the device, check if you have the right IP \
|
||||||
|
address in `RCTWebSocketExecutor.m`.", URL);
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -91,8 +94,8 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
|
||||||
{
|
{
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
NSDictionary *reply = RCTJSONParse(message, &error);
|
NSDictionary *reply = RCTJSONParse(message, &error);
|
||||||
NSUInteger messageID = [reply[@"replyID"] integerValue];
|
NSNumber *messageID = reply[@"replyID"];
|
||||||
WSMessageCallback callback = [_callbacks objectForKey:@(messageID)];
|
WSMessageCallback callback = _callbacks[messageID];
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(error, reply);
|
callback(error, reply);
|
||||||
}
|
}
|
||||||
|
@ -108,16 +111,11 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
|
||||||
RCTLogError(@"WebSocket connection failed with error %@", error);
|
RCTLogError(@"WebSocket connection failed with error %@", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)sendMessage:(NSDictionary *)message waitForReply:(WSMessageCallback)callback
|
- (void)sendMessage:(NSDictionary *)message waitForReply:(WSMessageCallback)callback
|
||||||
{
|
{
|
||||||
static NSUInteger lastID = 10000;
|
static NSUInteger lastID = 10000;
|
||||||
|
|
||||||
[_jsQueue addOperationWithBlock:^{
|
dispatch_async(_jsQueue, ^{
|
||||||
if (!self.valid) {
|
if (!self.valid) {
|
||||||
NSError *error = [NSError errorWithDomain:@"WS" code:1 userInfo:@{
|
NSError *error = [NSError errorWithDomain:@"WS" code:1 userInfo:@{
|
||||||
NSLocalizedDescriptionKey: @"socket closed"
|
NSLocalizedDescriptionKey: @"socket closed"
|
||||||
|
@ -126,19 +124,17 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSUInteger expectedID = lastID++;
|
NSNumber *expectedID = @(lastID++);
|
||||||
|
_callbacks[expectedID] = [callback copy];
|
||||||
_callbacks[@(expectedID)] = [callback copy];
|
|
||||||
|
|
||||||
NSMutableDictionary *messageWithID = [message mutableCopy];
|
NSMutableDictionary *messageWithID = [message mutableCopy];
|
||||||
messageWithID[@"id"] = @(expectedID);
|
messageWithID[@"id"] = expectedID;
|
||||||
[_socket send:RCTJSONStringify(messageWithID, NULL)];
|
[_socket send:RCTJSONStringify(messageWithID, NULL)];
|
||||||
}];
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)executeApplicationScript:(NSString *)script sourceURL:(NSURL *)url onComplete:(RCTJavaScriptCompleteBlock)onComplete
|
- (void)executeApplicationScript:(NSString *)script sourceURL:(NSURL *)URL onComplete:(RCTJavaScriptCompleteBlock)onComplete
|
||||||
{
|
{
|
||||||
NSDictionary *message = @{@"method": NSStringFromSelector(_cmd), @"url": [url absoluteString], @"inject": _injectedObjects};
|
NSDictionary *message = @{@"method": NSStringFromSelector(_cmd), @"url": [URL absoluteString], @"inject": _injectedObjects};
|
||||||
[self sendMessage:message waitForReply:^(NSError *error, NSDictionary *reply) {
|
[self sendMessage:message waitForReply:^(NSError *error, NSDictionary *reply) {
|
||||||
onComplete(error);
|
onComplete(error);
|
||||||
}];
|
}];
|
||||||
|
@ -147,7 +143,12 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
|
||||||
- (void)executeJSCall:(NSString *)name method:(NSString *)method arguments:(NSArray *)arguments callback:(RCTJavaScriptCallback)onComplete
|
- (void)executeJSCall:(NSString *)name method:(NSString *)method arguments:(NSArray *)arguments callback:(RCTJavaScriptCallback)onComplete
|
||||||
{
|
{
|
||||||
RCTAssert(onComplete != nil, @"callback was missing for exec JS call");
|
RCTAssert(onComplete != nil, @"callback was missing for exec JS call");
|
||||||
NSDictionary *message = @{@"method": NSStringFromSelector(_cmd), @"moduleName": name, @"moduleMethod": method, @"arguments": arguments};
|
NSDictionary *message = @{
|
||||||
|
@"method": NSStringFromSelector(_cmd),
|
||||||
|
@"moduleName": name,
|
||||||
|
@"moduleMethod": method,
|
||||||
|
@"arguments": arguments
|
||||||
|
};
|
||||||
[self sendMessage:message waitForReply:^(NSError *socketError, NSDictionary *reply) {
|
[self sendMessage:message waitForReply:^(NSError *socketError, NSDictionary *reply) {
|
||||||
if (socketError) {
|
if (socketError) {
|
||||||
onComplete(nil, socketError);
|
onComplete(nil, socketError);
|
||||||
|
@ -162,15 +163,14 @@ typedef void (^WSMessageCallback)(NSError *error, NSDictionary *reply);
|
||||||
|
|
||||||
- (void)injectJSONText:(NSString *)script asGlobalObjectNamed:(NSString *)objectName callback:(RCTJavaScriptCompleteBlock)onComplete
|
- (void)injectJSONText:(NSString *)script asGlobalObjectNamed:(NSString *)objectName callback:(RCTJavaScriptCompleteBlock)onComplete
|
||||||
{
|
{
|
||||||
[_jsQueue addOperationWithBlock:^{
|
dispatch_async(_jsQueue, ^{
|
||||||
[_injectedObjects setObject:script forKey:objectName];
|
_injectedObjects[objectName] = script;
|
||||||
onComplete(nil);
|
onComplete(nil);
|
||||||
}];
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)invalidate
|
- (void)invalidate
|
||||||
{
|
{
|
||||||
[_jsQueue cancelAllOperations];
|
|
||||||
_socket.delegate = nil;
|
_socket.delegate = nil;
|
||||||
[_socket closeWithCode:1000 reason:@"Invalidated"];
|
[_socket closeWithCode:1000 reason:@"Invalidated"];
|
||||||
_socket = nil;
|
_socket = nil;
|
||||||
|
|
|
@ -9,35 +9,73 @@
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#define RCTErrorDomain @"RCTErrorDomain"
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#define RCTAssert(condition, message, ...) _RCTAssert((condition) != 0, message, ##__VA_ARGS__)
|
/**
|
||||||
#define RCTCAssert(condition, message, ...) _RCTCAssert((condition) != 0, message, ##__VA_ARGS__)
|
* By default, only raise an NSAssertion in debug mode
|
||||||
|
* (custom assert functions will still be called).
|
||||||
|
*/
|
||||||
|
#ifndef RCT_ASSERT
|
||||||
|
#if DEBUG
|
||||||
|
#define RCT_ASSERT 1
|
||||||
|
#else
|
||||||
|
#define RCT_ASSERT 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void (^RCTAssertFunction)(BOOL condition, NSString *message, ...);
|
/**
|
||||||
|
* The default error domain to be used for React errors.
|
||||||
|
*/
|
||||||
|
extern NSString *const RCTErrorDomain;
|
||||||
|
|
||||||
extern RCTAssertFunction RCTInjectedAssertFunction;
|
/**
|
||||||
extern RCTAssertFunction RCTInjectedCAssertFunction;
|
* A block signature to be used for custom assertion handling.
|
||||||
|
*/
|
||||||
|
typedef void (^RCTAssertFunction)(
|
||||||
|
BOOL condition,
|
||||||
|
NSString *fileName,
|
||||||
|
NSNumber *lineNumber,
|
||||||
|
NSString *function,
|
||||||
|
NSString *message
|
||||||
|
);
|
||||||
|
|
||||||
void RCTInjectAssertFunctions(RCTAssertFunction assertFunction, RCTAssertFunction cAssertFunction);
|
/**
|
||||||
|
* Private logging function - ignore this.
|
||||||
|
*/
|
||||||
|
void _RCTAssertFormat(BOOL, const char *, int, const char *, NSString *, ...) NS_FORMAT_FUNCTION(5,6);
|
||||||
|
|
||||||
#define _RCTAssert(condition, message, ...) \
|
/**
|
||||||
do { \
|
* This is the main assert macro that you should use.
|
||||||
if (RCTInjectedAssertFunction) { \
|
*/
|
||||||
RCTInjectedAssertFunction(condition, message, ##__VA_ARGS__); \
|
#define RCTAssert(condition, ...) do { BOOL pass = ((condition) != 0); \
|
||||||
} else { \
|
if (RCT_ASSERT && !pass) { [[NSAssertionHandler currentHandler] handleFailureInFunction:@(__func__) \
|
||||||
NSAssert(condition, message, ##__VA_ARGS__); \
|
file:@(__FILE__) lineNumber:__LINE__ description:__VA_ARGS__]; } \
|
||||||
} \
|
_RCTAssertFormat(pass, __FILE__, __LINE__, __func__, __VA_ARGS__); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
#define _RCTCAssert(condition, message, ...) \
|
/**
|
||||||
do { \
|
* Convenience macro for asserting that we're running on main thread.
|
||||||
if (RCTInjectedCAssertFunction) { \
|
*/
|
||||||
RCTInjectedCAssertFunction(condition, message, ##__VA_ARGS__); \
|
#define RCTAssertMainThread() RCTAssert([NSThread isMainThread], \
|
||||||
} else { \
|
@"This function must be called on the main thread");
|
||||||
NSCAssert(condition, message, ##__VA_ARGS__); \
|
|
||||||
} \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define RCTAssertMainThread() RCTAssert([NSThread isMainThread], @"This method must be called on the main thread");
|
/**
|
||||||
#define RCTCAssertMainThread() RCTCAssert([NSThread isMainThread], @"This function must be called on the main thread");
|
* These methods get and set the current assert function called by the RCTAssert
|
||||||
|
* macros. You can use these to replace the standard behavior with custom log
|
||||||
|
* functionality.
|
||||||
|
*/
|
||||||
|
void RCTSetAssertFunction(RCTAssertFunction assertFunction);
|
||||||
|
RCTAssertFunction RCTGetAssertFunction(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This appends additional code to the existing assert function, without
|
||||||
|
* replacing the existing functionality. Useful if you just want to forward
|
||||||
|
* assert info to an extra service without changing the default behavior.
|
||||||
|
*/
|
||||||
|
void RCTAddAssertFunction(RCTAssertFunction assertFunction);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -9,11 +9,54 @@
|
||||||
|
|
||||||
#import "RCTAssert.h"
|
#import "RCTAssert.h"
|
||||||
|
|
||||||
RCTAssertFunction RCTInjectedAssertFunction = nil;
|
NSString *const RCTErrorDomain = @"RCTErrorDomain";
|
||||||
RCTAssertFunction RCTInjectedCAssertFunction = nil;
|
|
||||||
|
|
||||||
void RCTInjectAssertFunctions(RCTAssertFunction assertFunction, RCTAssertFunction cAssertFunction)
|
RCTAssertFunction RCTCurrentAssertFunction = nil;
|
||||||
|
|
||||||
|
void _RCTAssertFormat(
|
||||||
|
BOOL condition,
|
||||||
|
const char *fileName,
|
||||||
|
int lineNumber,
|
||||||
|
const char *function,
|
||||||
|
NSString *format, ...)
|
||||||
{
|
{
|
||||||
RCTInjectedAssertFunction = assertFunction;
|
if (RCTCurrentAssertFunction) {
|
||||||
RCTInjectedCAssertFunction = cAssertFunction;
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
RCTCurrentAssertFunction(
|
||||||
|
condition, @(fileName), @(lineNumber), @(function), message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCTSetAssertFunction(RCTAssertFunction assertFunction)
|
||||||
|
{
|
||||||
|
RCTCurrentAssertFunction = assertFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCTAssertFunction RCTGetAssertFunction(void)
|
||||||
|
{
|
||||||
|
return RCTCurrentAssertFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCTAddAssertFunction(RCTAssertFunction assertFunction)
|
||||||
|
{
|
||||||
|
RCTAssertFunction existing = RCTCurrentAssertFunction;
|
||||||
|
if (existing) {
|
||||||
|
RCTCurrentAssertFunction = ^(BOOL condition,
|
||||||
|
NSString *fileName,
|
||||||
|
NSNumber *lineNumber,
|
||||||
|
NSString *function,
|
||||||
|
NSString *message) {
|
||||||
|
|
||||||
|
existing(condition, fileName, lineNumber, function, message);
|
||||||
|
assertFunction(condition, fileName, lineNumber, function, message);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
RCTCurrentAssertFunction = assertFunction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,16 @@
|
||||||
@class RCTBridge;
|
@class RCTBridge;
|
||||||
@class RCTEventDispatcher;
|
@class RCTEventDispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This notification triggers a reload of all bridges currently running.
|
||||||
|
*/
|
||||||
|
extern NSString *const RCTReloadNotification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This notification fires when the bridge has finished loading.
|
||||||
|
*/
|
||||||
|
extern NSString *const RCTJavaScriptDidLoadNotification;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This block can be used to instantiate modules that require additional
|
* This block can be used to instantiate modules that require additional
|
||||||
* init parameters, or additional configuration prior to being used.
|
* init parameters, or additional configuration prior to being used.
|
||||||
|
@ -44,9 +54,9 @@ extern NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
|
||||||
* array of pre-initialized module instances if they require additional init
|
* array of pre-initialized module instances if they require additional init
|
||||||
* parameters or configuration.
|
* parameters or configuration.
|
||||||
*/
|
*/
|
||||||
- (instancetype)initWithBundlePath:(NSString *)bundlepath
|
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
|
||||||
moduleProvider:(RCTBridgeModuleProviderBlock)block
|
moduleProvider:(RCTBridgeModuleProviderBlock)block
|
||||||
launchOptions:(NSDictionary *)launchOptions NS_DESIGNATED_INITIALIZER;
|
launchOptions:(NSDictionary *)launchOptions NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is used to call functions in the JavaScript application context.
|
* This method is used to call functions in the JavaScript application context.
|
||||||
|
@ -105,7 +115,7 @@ static const char *__rct_import_##module##_##method##__ = #module"."#method;
|
||||||
/**
|
/**
|
||||||
* Use this to check if the bridge is currently loading.
|
* Use this to check if the bridge is currently loading.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, readonly, getter=isLoaded) BOOL loaded;
|
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reload the bundle and reset executor and modules.
|
* Reload the bundle and reset executor and modules.
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
#import "RCTSparseArray.h"
|
#import "RCTSparseArray.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
|
|
||||||
|
NSString *const RCTReloadNotification = @"RCTReloadNotification";
|
||||||
|
NSString *const RCTJavaScriptDidLoadNotification = @"RCTJavaScriptDidLoadNotification";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Must be kept in sync with `MessageQueue.js`.
|
* Must be kept in sync with `MessageQueue.js`.
|
||||||
*/
|
*/
|
||||||
|
@ -144,9 +147,9 @@ static NSArray *RCTBridgeModuleClassesByModuleID(void)
|
||||||
|
|
||||||
// Get class
|
// Get class
|
||||||
Class cls = NSClassFromString(moduleClassName);
|
Class cls = NSClassFromString(moduleClassName);
|
||||||
RCTCAssert([cls conformsToProtocol:@protocol(RCTBridgeModule)],
|
RCTAssert([cls conformsToProtocol:@protocol(RCTBridgeModule)],
|
||||||
@"%@ does not conform to the RCTBridgeModule protocol",
|
@"%@ does not conform to the RCTBridgeModule protocol",
|
||||||
NSStringFromClass(cls));
|
NSStringFromClass(cls));
|
||||||
|
|
||||||
// Register module
|
// Register module
|
||||||
[(NSMutableArray *)RCTModuleNamesByID addObject:RCTBridgeModuleNameForClass(cls)];
|
[(NSMutableArray *)RCTModuleNamesByID addObject:RCTBridgeModuleNameForClass(cls)];
|
||||||
|
@ -279,34 +282,34 @@ NS_INLINE NSString *RCTStringUpToFirstArgument(NSString *methodName) {
|
||||||
|
|
||||||
// Get method signature
|
// Get method signature
|
||||||
_methodSignature = _isClassMethod ?
|
_methodSignature = _isClassMethod ?
|
||||||
[_moduleClass methodSignatureForSelector:_selector] :
|
[_moduleClass methodSignatureForSelector:_selector] :
|
||||||
[_moduleClass instanceMethodSignatureForSelector:_selector];
|
[_moduleClass instanceMethodSignatureForSelector:_selector];
|
||||||
|
|
||||||
// Process arguments
|
// Process arguments
|
||||||
NSUInteger numberOfArguments = _methodSignature.numberOfArguments;
|
NSUInteger numberOfArguments = _methodSignature.numberOfArguments;
|
||||||
NSMutableArray *argumentBlocks = [[NSMutableArray alloc] initWithCapacity:numberOfArguments - 2];
|
NSMutableArray *argumentBlocks = [[NSMutableArray alloc] initWithCapacity:numberOfArguments - 2];
|
||||||
|
|
||||||
#define RCT_ARG_BLOCK(_logic) \
|
#define RCT_ARG_BLOCK(_logic) \
|
||||||
[argumentBlocks addObject:^(RCTBridge *bridge, NSInvocation *invocation, NSUInteger index, id json) { \
|
[argumentBlocks addObject:^(RCTBridge *bridge, NSInvocation *invocation, NSUInteger index, id json) { \
|
||||||
_logic \
|
_logic \
|
||||||
[invocation setArgument:&value atIndex:index]; \
|
[invocation setArgument:&value atIndex:index]; \
|
||||||
}]; \
|
}]; \
|
||||||
|
|
||||||
void (^addBlockArgument)(void) = ^{
|
void (^addBlockArgument)(void) = ^{
|
||||||
RCT_ARG_BLOCK(
|
RCT_ARG_BLOCK(
|
||||||
if (json && ![json isKindOfClass:[NSNumber class]]) {
|
if (json && ![json isKindOfClass:[NSNumber class]]) {
|
||||||
RCTLogError(@"Argument %tu (%@) of %@.%@ should be a number", index,
|
RCTLogError(@"Argument %tu (%@) of %@.%@ should be a number", index,
|
||||||
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
|
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
|
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
|
||||||
__autoreleasing id value = (json ? ^(NSArray *args) {
|
__autoreleasing id value = (json ? ^(NSArray *args) {
|
||||||
[bridge _invokeAndProcessModule:@"BatchedBridge"
|
[bridge _invokeAndProcessModule:@"BatchedBridge"
|
||||||
method:@"invokeCallbackAndReturnFlushedQueue"
|
method:@"invokeCallbackAndReturnFlushedQueue"
|
||||||
arguments:@[json, args]];
|
arguments:@[json, args]];
|
||||||
} : ^(NSArray *unused) {});
|
} : ^(NSArray *unused) {});
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
void (^defaultCase)(const char *) = ^(const char *argumentType) {
|
void (^defaultCase)(const char *) = ^(const char *argumentType) {
|
||||||
|
@ -330,29 +333,29 @@ NS_INLINE NSString *RCTStringUpToFirstArgument(NSString *methodName) {
|
||||||
switch (argumentType[0]) {
|
switch (argumentType[0]) {
|
||||||
|
|
||||||
#define RCT_CONVERT_CASE(_value, _type) \
|
#define RCT_CONVERT_CASE(_value, _type) \
|
||||||
case _value: { \
|
case _value: { \
|
||||||
_type (*convert)(id, SEL, id) = (typeof(convert))[RCTConvert methodForSelector:selector]; \
|
_type (*convert)(id, SEL, id) = (typeof(convert))[RCTConvert methodForSelector:selector]; \
|
||||||
RCT_ARG_BLOCK( _type value = convert([RCTConvert class], selector, json); ) \
|
RCT_ARG_BLOCK( _type value = convert([RCTConvert class], selector, json); ) \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_CONVERT_CASE(':', SEL)
|
RCT_CONVERT_CASE(':', SEL)
|
||||||
RCT_CONVERT_CASE('*', const char *)
|
RCT_CONVERT_CASE('*', const char *)
|
||||||
RCT_CONVERT_CASE('c', char)
|
RCT_CONVERT_CASE('c', char)
|
||||||
RCT_CONVERT_CASE('C', unsigned char)
|
RCT_CONVERT_CASE('C', unsigned char)
|
||||||
RCT_CONVERT_CASE('s', short)
|
RCT_CONVERT_CASE('s', short)
|
||||||
RCT_CONVERT_CASE('S', unsigned short)
|
RCT_CONVERT_CASE('S', unsigned short)
|
||||||
RCT_CONVERT_CASE('i', int)
|
RCT_CONVERT_CASE('i', int)
|
||||||
RCT_CONVERT_CASE('I', unsigned int)
|
RCT_CONVERT_CASE('I', unsigned int)
|
||||||
RCT_CONVERT_CASE('l', long)
|
RCT_CONVERT_CASE('l', long)
|
||||||
RCT_CONVERT_CASE('L', unsigned long)
|
RCT_CONVERT_CASE('L', unsigned long)
|
||||||
RCT_CONVERT_CASE('q', long long)
|
RCT_CONVERT_CASE('q', long long)
|
||||||
RCT_CONVERT_CASE('Q', unsigned long long)
|
RCT_CONVERT_CASE('Q', unsigned long long)
|
||||||
RCT_CONVERT_CASE('f', float)
|
RCT_CONVERT_CASE('f', float)
|
||||||
RCT_CONVERT_CASE('d', double)
|
RCT_CONVERT_CASE('d', double)
|
||||||
RCT_CONVERT_CASE('B', BOOL)
|
RCT_CONVERT_CASE('B', BOOL)
|
||||||
RCT_CONVERT_CASE('@', id)
|
RCT_CONVERT_CASE('@', id)
|
||||||
RCT_CONVERT_CASE('^', void *)
|
RCT_CONVERT_CASE('^', void *)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
defaultCase(argumentType);
|
defaultCase(argumentType);
|
||||||
|
@ -368,47 +371,47 @@ NS_INLINE NSString *RCTStringUpToFirstArgument(NSString *methodName) {
|
||||||
switch (argumentType[0]) {
|
switch (argumentType[0]) {
|
||||||
|
|
||||||
#define RCT_CASE(_value, _class, _logic) \
|
#define RCT_CASE(_value, _class, _logic) \
|
||||||
case _value: { \
|
case _value: { \
|
||||||
RCT_ARG_BLOCK( \
|
RCT_ARG_BLOCK( \
|
||||||
if (json && ![json isKindOfClass:[_class class]]) { \
|
if (json && ![json isKindOfClass:[_class class]]) { \
|
||||||
RCTLogError(@"Argument %tu (%@) of %@.%@ should be of type %@", index, \
|
RCTLogError(@"Argument %tu (%@) of %@.%@ should be of type %@", index, \
|
||||||
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, [_class class]); \
|
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, [_class class]); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
_logic \
|
_logic \
|
||||||
) \
|
) \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_CASE(':', NSString, SEL value = NSSelectorFromString(json); )
|
RCT_CASE(':', NSString, SEL value = NSSelectorFromString(json); )
|
||||||
RCT_CASE('*', NSString, const char *value = [json UTF8String]; )
|
RCT_CASE('*', NSString, const char *value = [json UTF8String]; )
|
||||||
|
|
||||||
#define RCT_SIMPLE_CASE(_value, _type, _selector) \
|
#define RCT_SIMPLE_CASE(_value, _type, _selector) \
|
||||||
case _value: { \
|
case _value: { \
|
||||||
RCT_ARG_BLOCK( \
|
RCT_ARG_BLOCK( \
|
||||||
if (json && ![json respondsToSelector:@selector(_selector)]) { \
|
if (json && ![json respondsToSelector:@selector(_selector)]) { \
|
||||||
RCTLogError(@"Argument %tu (%@) of %@.%@ does not respond to selector: %@", \
|
RCTLogError(@"Argument %tu (%@) of %@.%@ does not respond to selector: %@", \
|
||||||
index, json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, @#_selector); \
|
index, json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, @#_selector); \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
_type value = [json _selector]; \
|
_type value = [json _selector]; \
|
||||||
) \
|
) \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_SIMPLE_CASE('c', char, charValue)
|
RCT_SIMPLE_CASE('c', char, charValue)
|
||||||
RCT_SIMPLE_CASE('C', unsigned char, unsignedCharValue)
|
RCT_SIMPLE_CASE('C', unsigned char, unsignedCharValue)
|
||||||
RCT_SIMPLE_CASE('s', short, shortValue)
|
RCT_SIMPLE_CASE('s', short, shortValue)
|
||||||
RCT_SIMPLE_CASE('S', unsigned short, unsignedShortValue)
|
RCT_SIMPLE_CASE('S', unsigned short, unsignedShortValue)
|
||||||
RCT_SIMPLE_CASE('i', int, intValue)
|
RCT_SIMPLE_CASE('i', int, intValue)
|
||||||
RCT_SIMPLE_CASE('I', unsigned int, unsignedIntValue)
|
RCT_SIMPLE_CASE('I', unsigned int, unsignedIntValue)
|
||||||
RCT_SIMPLE_CASE('l', long, longValue)
|
RCT_SIMPLE_CASE('l', long, longValue)
|
||||||
RCT_SIMPLE_CASE('L', unsigned long, unsignedLongValue)
|
RCT_SIMPLE_CASE('L', unsigned long, unsignedLongValue)
|
||||||
RCT_SIMPLE_CASE('q', long long, longLongValue)
|
RCT_SIMPLE_CASE('q', long long, longLongValue)
|
||||||
RCT_SIMPLE_CASE('Q', unsigned long long, unsignedLongLongValue)
|
RCT_SIMPLE_CASE('Q', unsigned long long, unsignedLongLongValue)
|
||||||
RCT_SIMPLE_CASE('f', float, floatValue)
|
RCT_SIMPLE_CASE('f', float, floatValue)
|
||||||
RCT_SIMPLE_CASE('d', double, doubleValue)
|
RCT_SIMPLE_CASE('d', double, doubleValue)
|
||||||
RCT_SIMPLE_CASE('B', BOOL, boolValue)
|
RCT_SIMPLE_CASE('B', BOOL, boolValue)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
defaultCase(argumentType);
|
defaultCase(argumentType);
|
||||||
|
@ -500,13 +503,13 @@ static RCTSparseArray *RCTExportedMethodsByModuleID(void)
|
||||||
|
|
||||||
// Create method
|
// Create method
|
||||||
RCTModuleMethod *moduleMethod =
|
RCTModuleMethod *moduleMethod =
|
||||||
[[RCTModuleMethod alloc] initWithMethodName:@(entries[0])
|
[[RCTModuleMethod alloc] initWithMethodName:@(entries[0])
|
||||||
JSMethodName:strlen(entries[1]) ? @(entries[1]) : nil];
|
JSMethodName:strlen(entries[1]) ? @(entries[1]) : nil];
|
||||||
|
|
||||||
// Cache method
|
// Cache method
|
||||||
NSArray *methods = methodsByModuleClassName[moduleMethod.moduleClassName];
|
NSArray *methods = methodsByModuleClassName[moduleMethod.moduleClassName];
|
||||||
methodsByModuleClassName[moduleMethod.moduleClassName] =
|
methodsByModuleClassName[moduleMethod.moduleClassName] =
|
||||||
methods ? [methods arrayByAddingObject:moduleMethod] : @[moduleMethod];
|
methods ? [methods arrayByAddingObject:moduleMethod] : @[moduleMethod];
|
||||||
}
|
}
|
||||||
|
|
||||||
methodsByModuleID = [[RCTSparseArray alloc] initWithCapacity:[classes count]];
|
methodsByModuleID = [[RCTSparseArray alloc] initWithCapacity:[classes count]];
|
||||||
|
@ -557,15 +560,15 @@ static NSDictionary *RCTRemoteModulesConfig(NSDictionary *modulesByName)
|
||||||
NSMutableDictionary *methodsByName = [NSMutableDictionary dictionaryWithCapacity:methods.count];
|
NSMutableDictionary *methodsByName = [NSMutableDictionary dictionaryWithCapacity:methods.count];
|
||||||
[methods enumerateObjectsUsingBlock:^(RCTModuleMethod *method, NSUInteger methodID, BOOL *_stop) {
|
[methods enumerateObjectsUsingBlock:^(RCTModuleMethod *method, NSUInteger methodID, BOOL *_stop) {
|
||||||
methodsByName[method.JSMethodName] = @{
|
methodsByName[method.JSMethodName] = @{
|
||||||
@"methodID": @(methodID),
|
@"methodID": @(methodID),
|
||||||
@"type": @"remote",
|
@"type": @"remote",
|
||||||
};
|
};
|
||||||
}];
|
}];
|
||||||
|
|
||||||
NSDictionary *module = @{
|
NSDictionary *module = @{
|
||||||
@"moduleID": @(moduleID),
|
@"moduleID": @(moduleID),
|
||||||
@"methods": methodsByName
|
@"methods": methodsByName
|
||||||
};
|
};
|
||||||
|
|
||||||
remoteModuleConfigByClassName[NSStringFromClass(moduleClass)] = module;
|
remoteModuleConfigByClassName[NSStringFromClass(moduleClass)] = module;
|
||||||
}];
|
}];
|
||||||
|
@ -629,16 +632,16 @@ static NSDictionary *RCTLocalModulesConfig()
|
||||||
for (NSString *moduleDotMethod in RCTJSMethods()) {
|
for (NSString *moduleDotMethod in RCTJSMethods()) {
|
||||||
|
|
||||||
NSArray *parts = [moduleDotMethod componentsSeparatedByString:@"."];
|
NSArray *parts = [moduleDotMethod componentsSeparatedByString:@"."];
|
||||||
RCTCAssert(parts.count == 2, @"'%@' is not a valid JS method definition - expected 'Module.method' format.", moduleDotMethod);
|
RCTAssert(parts.count == 2, @"'%@' is not a valid JS method definition - expected 'Module.method' format.", moduleDotMethod);
|
||||||
|
|
||||||
// Add module if it doesn't already exist
|
// Add module if it doesn't already exist
|
||||||
NSString *moduleName = parts[0];
|
NSString *moduleName = parts[0];
|
||||||
NSDictionary *module = localModules[moduleName];
|
NSDictionary *module = localModules[moduleName];
|
||||||
if (!module) {
|
if (!module) {
|
||||||
module = @{
|
module = @{
|
||||||
@"moduleID": @(localModules.count),
|
@"moduleID": @(localModules.count),
|
||||||
@"methods": [[NSMutableDictionary alloc] init]
|
@"methods": [[NSMutableDictionary alloc] init]
|
||||||
};
|
};
|
||||||
localModules[moduleName] = module;
|
localModules[moduleName] = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,9 +650,9 @@ static NSDictionary *RCTLocalModulesConfig()
|
||||||
NSMutableDictionary *methods = module[@"methods"];
|
NSMutableDictionary *methods = module[@"methods"];
|
||||||
if (!methods[methodName]) {
|
if (!methods[methodName]) {
|
||||||
methods[methodName] = @{
|
methods[methodName] = @{
|
||||||
@"methodID": @(methods.count),
|
@"methodID": @(methods.count),
|
||||||
@"type": @"local"
|
@"type": @"local"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add module and method lookup
|
// Add module and method lookup
|
||||||
|
@ -667,22 +670,21 @@ static NSDictionary *RCTLocalModulesConfig()
|
||||||
NSDictionary *_modulesByName;
|
NSDictionary *_modulesByName;
|
||||||
id<RCTJavaScriptExecutor> _javaScriptExecutor;
|
id<RCTJavaScriptExecutor> _javaScriptExecutor;
|
||||||
Class _executorClass;
|
Class _executorClass;
|
||||||
NSString *_bundlePath;
|
NSURL *_bundleURL;
|
||||||
NSDictionary *_launchOptions;
|
|
||||||
RCTBridgeModuleProviderBlock _moduleProvider;
|
RCTBridgeModuleProviderBlock _moduleProvider;
|
||||||
BOOL _loaded;
|
BOOL _loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
|
|
||||||
- (instancetype)initWithBundlePath:(NSString *)bundlePath
|
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
|
||||||
moduleProvider:(RCTBridgeModuleProviderBlock)block
|
moduleProvider:(RCTBridgeModuleProviderBlock)block
|
||||||
launchOptions:(NSDictionary *)launchOptions
|
launchOptions:(NSDictionary *)launchOptions
|
||||||
{
|
{
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_bundlePath = bundlePath;
|
_bundleURL = bundleURL;
|
||||||
_moduleProvider = block;
|
_moduleProvider = block;
|
||||||
_launchOptions = launchOptions;
|
_launchOptions = [launchOptions copy];
|
||||||
[self setUp];
|
[self setUp];
|
||||||
[self bindKeys];
|
[self bindKeys];
|
||||||
}
|
}
|
||||||
|
@ -695,7 +697,7 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
_javaScriptExecutor = [[executorClass alloc] init];
|
_javaScriptExecutor = [[executorClass alloc] init];
|
||||||
_latestJSExecutor = _javaScriptExecutor;
|
_latestJSExecutor = _javaScriptExecutor;
|
||||||
_eventDispatcher = [[RCTEventDispatcher alloc] initWithBridge:self];
|
_eventDispatcher = [[RCTEventDispatcher alloc] initWithBridge:self];
|
||||||
_shadowQueue = dispatch_queue_create("com.facebook.ReactKit.ShadowQueue", DISPATCH_QUEUE_SERIAL);
|
_shadowQueue = dispatch_queue_create("com.facebook.React.ShadowQueue", DISPATCH_QUEUE_SERIAL);
|
||||||
|
|
||||||
// Register passed-in module instances
|
// Register passed-in module instances
|
||||||
NSMutableDictionary *preregisteredModules = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *preregisteredModules = [[NSMutableDictionary alloc] init];
|
||||||
|
@ -743,21 +745,25 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
@"localModulesConfig": RCTLocalModulesConfig()
|
@"localModulesConfig": RCTLocalModulesConfig()
|
||||||
}, NULL);
|
}, NULL);
|
||||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||||
[_javaScriptExecutor injectJSONText:configJSON asGlobalObjectNamed:@"__fbBatchedBridgeConfig" callback:^(id err) {
|
[_javaScriptExecutor injectJSONText:configJSON
|
||||||
dispatch_semaphore_signal(semaphore);
|
asGlobalObjectNamed:@"__fbBatchedBridgeConfig" callback:^(id err) {
|
||||||
}];
|
dispatch_semaphore_signal(semaphore);
|
||||||
|
}];
|
||||||
|
|
||||||
|
_loading = YES;
|
||||||
if (_javaScriptExecutor == nil) {
|
if (_javaScriptExecutor == nil) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HACK (tadeu): If it failed to connect to the debugger, set loaded to true so we can
|
* HACK (tadeu): If it failed to connect to the debugger, set loading to NO
|
||||||
* reload
|
* so we can attempt to reload again.
|
||||||
*/
|
*/
|
||||||
_loaded = YES;
|
_loading = NO;
|
||||||
} else if (_bundlePath != nil) { // Allow testing without a script
|
|
||||||
|
} else if (_bundleURL) { // Allow testing without a script
|
||||||
|
|
||||||
RCTJavaScriptLoader *loader = [[RCTJavaScriptLoader alloc] initWithBridge:self];
|
RCTJavaScriptLoader *loader = [[RCTJavaScriptLoader alloc] initWithBridge:self];
|
||||||
[loader loadBundleAtURL:[NSURL URLWithString:_bundlePath] onComplete:^(NSError *error) {
|
[loader loadBundleAtURL:_bundleURL onComplete:^(NSError *error) {
|
||||||
_loaded = YES;
|
_loading = NO;
|
||||||
if (error != nil) {
|
if (error != nil) {
|
||||||
NSArray *stack = [[error userInfo] objectForKey:@"stack"];
|
NSArray *stack = [[error userInfo] objectForKey:@"stack"];
|
||||||
if (stack) {
|
if (stack) {
|
||||||
|
@ -770,6 +776,11 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
} else {
|
} else {
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(reload)
|
||||||
|
name:RCTReloadNotification
|
||||||
|
object:nil];
|
||||||
}
|
}
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(reload)
|
selector:@selector(reload)
|
||||||
|
@ -781,53 +792,56 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
|
|
||||||
- (void)bindKeys
|
- (void)bindKeys
|
||||||
{
|
{
|
||||||
#if TARGET_IPHONE_SIMULATOR
|
|
||||||
__weak RCTBridge *weakSelf = self;
|
|
||||||
|
|
||||||
// Workaround around the first cmd+r not working: http://openradar.appspot.com/19613391
|
#if TARGET_IPHONE_SIMULATOR
|
||||||
// You can register just the cmd key and do nothing. This will trigger the bug and cmd+r
|
|
||||||
|
__weak RCTBridge *weakSelf = self;
|
||||||
|
RCTKeyCommands *commands = [RCTKeyCommands sharedInstance];
|
||||||
|
|
||||||
|
// Workaround around the first cmd+R not working: http://openradar.appspot.com/19613391
|
||||||
|
// You can register just the cmd key and do nothing. This will trigger the bug and cmd+R
|
||||||
// will work like a charm!
|
// will work like a charm!
|
||||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@""
|
[commands registerKeyCommandWithInput:@""
|
||||||
modifierFlags:UIKeyModifierCommand
|
modifierFlags:UIKeyModifierCommand
|
||||||
action:^(UIKeyCommand *command) {
|
action:NULL];
|
||||||
// Do nothing
|
// reload in current mode
|
||||||
}];
|
[commands registerKeyCommandWithInput:@"r"
|
||||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"r"
|
modifierFlags:UIKeyModifierCommand
|
||||||
modifierFlags:UIKeyModifierCommand
|
action:^(UIKeyCommand *command) {
|
||||||
action:^(UIKeyCommand *command) {
|
[weakSelf reload];
|
||||||
[weakSelf reload];
|
}];
|
||||||
}];
|
// reset to normal mode
|
||||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"n"
|
[commands registerKeyCommandWithInput:@"n"
|
||||||
modifierFlags:UIKeyModifierCommand
|
modifierFlags:UIKeyModifierCommand
|
||||||
action:^(UIKeyCommand *command) {
|
action:^(UIKeyCommand *command) {
|
||||||
RCTBridge *strongSelf = weakSelf;
|
__strong RCTBridge *strongSelf = weakSelf;
|
||||||
if (!strongSelf) {
|
strongSelf.executorClass = Nil;
|
||||||
return;
|
[strongSelf reload];
|
||||||
}
|
}];
|
||||||
strongSelf->_executorClass = Nil;
|
// reload in debug mode
|
||||||
[strongSelf reload];
|
[commands registerKeyCommandWithInput:@"d"
|
||||||
}];
|
modifierFlags:UIKeyModifierCommand
|
||||||
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"d"
|
action:^(UIKeyCommand *command) {
|
||||||
modifierFlags:UIKeyModifierCommand
|
__strong RCTBridge *strongSelf = weakSelf;
|
||||||
action:^(UIKeyCommand *command) {
|
strongSelf.executorClass = NSClassFromString(@"RCTWebSocketExecutor");
|
||||||
RCTBridge *strongSelf = weakSelf;
|
if (!strongSelf.executorClass) {
|
||||||
if (!strongSelf) {
|
strongSelf.executorClass = NSClassFromString(@"RCTWebViewExecutor");
|
||||||
return;
|
}
|
||||||
}
|
if (!strongSelf.executorClass) {
|
||||||
strongSelf->_executorClass = NSClassFromString(@"RCTWebSocketExecutor");
|
RCTLogError(@"WebSocket debugger is not available. "
|
||||||
if (!strongSelf->_executorClass) {
|
"Did you forget to include RCTWebSocketExecutor?");
|
||||||
RCTLogError(@"WebSocket debugger is not available. Did you forget to include RCTWebSocketExecutor?");
|
}
|
||||||
}
|
[strongSelf reload];
|
||||||
[strongSelf reload];
|
}];
|
||||||
}];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSDictionary *)modules
|
- (NSDictionary *)modules
|
||||||
{
|
{
|
||||||
RCTAssert(_modulesByName != nil, @"Bridge modules have not yet been initialized. \
|
RCTAssert(_modulesByName != nil, @"Bridge modules have not yet been initialized. "
|
||||||
You may be trying to access a module too early in the startup procedure.");
|
"You may be trying to access a module too early in the startup procedure.");
|
||||||
|
|
||||||
return _modulesByName;
|
return _modulesByName;
|
||||||
}
|
}
|
||||||
|
@ -874,7 +888,6 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
// Release modules (breaks retain cycle if module has strong bridge reference)
|
// Release modules (breaks retain cycle if module has strong bridge reference)
|
||||||
_modulesByID = nil;
|
_modulesByID = nil;
|
||||||
_modulesByName = nil;
|
_modulesByName = nil;
|
||||||
_loaded = NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -898,10 +911,10 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
NSNumber *methodID = RCTLocalMethodIDs[moduleDotMethod];
|
NSNumber *methodID = RCTLocalMethodIDs[moduleDotMethod];
|
||||||
RCTAssert(methodID != nil, @"Method '%@' not registered.", moduleDotMethod);
|
RCTAssert(methodID != nil, @"Method '%@' not registered.", moduleDotMethod);
|
||||||
|
|
||||||
if (self.loaded) {
|
if (!_loading) {
|
||||||
[self _invokeAndProcessModule:@"BatchedBridge"
|
[self _invokeAndProcessModule:@"BatchedBridge"
|
||||||
method:@"callFunctionReturnFlushedQueue"
|
method:@"callFunctionReturnFlushedQueue"
|
||||||
arguments:@[moduleID, methodID, args ?: @[]]];
|
arguments:@[moduleID, methodID, args ?: @[]]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1051,20 +1064,18 @@ static id<RCTJavaScriptExecutor> _latestJSExecutor;
|
||||||
|
|
||||||
- (void)reload
|
- (void)reload
|
||||||
{
|
{
|
||||||
if (_loaded) {
|
if (!_loading) {
|
||||||
// If the bridge has not loaded yet, the context will be already invalid at
|
// If the bridge has not loaded yet, the context will be already invalid at
|
||||||
// the time the javascript gets executed.
|
// the time the javascript gets executed.
|
||||||
// It will crash the javascript, and even the next `load` won't render.
|
// It will crash the javascript, and even the next `load` won't render.
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self setUp];
|
[self setUp];
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTReloadViewsNotification
|
|
||||||
object:self];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)logMessage:(NSString *)message level:(NSString *)level
|
+ (void)logMessage:(NSString *)message level:(NSString *)level
|
||||||
{
|
{
|
||||||
if (!_latestJSExecutor || ![_latestJSExecutor isValid]) {
|
if (![_latestJSExecutor isValid]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,8 @@ typedef void (^RCTResponseSenderBlock)(NSArray *response);
|
||||||
* match the Objective-C class name.
|
* match the Objective-C class name.
|
||||||
*/
|
*/
|
||||||
#define RCT_EXPORT_MODULE(js_name) \
|
#define RCT_EXPORT_MODULE(js_name) \
|
||||||
+ (NSString *)moduleName { __attribute__((used, section("__DATA,RCTExportModule" \
|
+ (NSString *)moduleName { __attribute__((used, section("__DATA,RCTExportModule" \
|
||||||
))) static const char *__rct_export_entry__ = { __func__ }; return @#js_name; } \
|
))) static const char *__rct_export_entry__ = { __func__ }; return @#js_name; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Place this macro inside the method body of any method you want to expose
|
* Place this macro inside the method body of any method you want to expose
|
||||||
|
@ -59,17 +59,17 @@ typedef void (^RCTResponseSenderBlock)(NSArray *response);
|
||||||
* a js_name argument and the exposed method will match the first part of the
|
* a js_name argument and the exposed method will match the first part of the
|
||||||
* Objective-C method selector name (up to the first colon).
|
* Objective-C method selector name (up to the first colon).
|
||||||
*
|
*
|
||||||
* For example, in MyClass.m:
|
* For example, in ModuleName.m:
|
||||||
*
|
*
|
||||||
* - (void)doSomething:(NSString *)aString withA:(NSInteger)a andB:(NSInteger)b
|
* - (void)doSomething:(NSString *)aString withA:(NSInteger)a andB:(NSInteger)b
|
||||||
* {}
|
* { ... }
|
||||||
*
|
*
|
||||||
* becomes
|
* becomes
|
||||||
*
|
*
|
||||||
* RCT_EXPORT_METHOD(doSomething:(NSString *)aString
|
* RCT_EXPORT_METHOD(doSomething:(NSString *)aString
|
||||||
* withA:(NSInteger)a
|
* withA:(NSInteger)a
|
||||||
* andB:(NSInteger)b)
|
* andB:(NSInteger)b)
|
||||||
* {}
|
* { ... }
|
||||||
*
|
*
|
||||||
* and is exposed to JavaScript as `NativeModules.ModuleName.doSomething`.
|
* and is exposed to JavaScript as `NativeModules.ModuleName.doSomething`.
|
||||||
*/
|
*/
|
||||||
|
@ -96,11 +96,3 @@ typedef void (^RCTResponseSenderBlock)(NSArray *response);
|
||||||
- (void)batchDidComplete;
|
- (void)batchDidComplete;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
void RCTBridgeModuleRegisterClass(Class cls, NSString *moduleName);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -14,15 +14,15 @@
|
||||||
#import "RCTSourceCode.h"
|
#import "RCTSourceCode.h"
|
||||||
#import "RCTWebViewExecutor.h"
|
#import "RCTWebViewExecutor.h"
|
||||||
|
|
||||||
@interface RCTDevMenu () <UIActionSheetDelegate> {
|
@interface RCTDevMenu () <UIActionSheetDelegate>
|
||||||
BOOL _liveReload;
|
|
||||||
}
|
|
||||||
|
|
||||||
@property (nonatomic, weak) RCTBridge *bridge;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation RCTDevMenu
|
@implementation RCTDevMenu
|
||||||
|
{
|
||||||
|
BOOL _liveReload;
|
||||||
|
__weak RCTBridge *_bridge;
|
||||||
|
}
|
||||||
|
|
||||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||||
{
|
{
|
||||||
|
@ -34,8 +34,8 @@
|
||||||
|
|
||||||
- (void)show
|
- (void)show
|
||||||
{
|
{
|
||||||
NSString *debugTitleChrome = self.bridge.executorClass != Nil && self.bridge.executorClass == NSClassFromString(@"RCTWebSocketExecutor") ? @"Disable Chrome Debugging" : @"Enable Chrome Debugging";
|
NSString *debugTitleChrome = _bridge.executorClass != Nil && _bridge.executorClass == NSClassFromString(@"RCTWebSocketExecutor") ? @"Disable Chrome Debugging" : @"Enable Chrome Debugging";
|
||||||
NSString *debugTitleSafari = self.bridge.executorClass == [RCTWebViewExecutor class] ? @"Disable Safari Debugging" : @"Enable Safari Debugging";
|
NSString *debugTitleSafari = _bridge.executorClass == [RCTWebViewExecutor class] ? @"Disable Safari Debugging" : @"Enable Safari Debugging";
|
||||||
NSString *liveReloadTitle = _liveReload ? @"Disable Live Reload" : @"Enable Live Reload";
|
NSString *liveReloadTitle = _liveReload ? @"Disable Live Reload" : @"Enable Live Reload";
|
||||||
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"React Native: Development"
|
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"React Native: Development"
|
||||||
delegate:self
|
delegate:self
|
||||||
|
@ -49,15 +49,15 @@
|
||||||
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
|
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
|
||||||
{
|
{
|
||||||
if (buttonIndex == 0) {
|
if (buttonIndex == 0) {
|
||||||
[self.bridge reload];
|
[_bridge reload];
|
||||||
} else if (buttonIndex == 1) {
|
} else if (buttonIndex == 1) {
|
||||||
Class cls = NSClassFromString(@"RCTWebSocketExecutor");
|
Class cls = NSClassFromString(@"RCTWebSocketExecutor");
|
||||||
self.bridge.executorClass = (self.bridge.executorClass != cls) ? cls : nil;
|
_bridge.executorClass = (_bridge.executorClass != cls) ? cls : nil;
|
||||||
[self.bridge reload];
|
[_bridge reload];
|
||||||
} else if (buttonIndex == 2) {
|
} else if (buttonIndex == 2) {
|
||||||
Class cls = [RCTWebViewExecutor class];
|
Class cls = [RCTWebViewExecutor class];
|
||||||
self.bridge.executorClass = (self.bridge.executorClass != cls) ? cls : Nil;
|
_bridge.executorClass = (_bridge.executorClass != cls) ? cls : Nil;
|
||||||
[self.bridge reload];
|
[_bridge reload];
|
||||||
} else if (buttonIndex == 3) {
|
} else if (buttonIndex == 3) {
|
||||||
_liveReload = !_liveReload;
|
_liveReload = !_liveReload;
|
||||||
[self _pollAndReload];
|
[self _pollAndReload];
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
- (void)_pollAndReload
|
- (void)_pollAndReload
|
||||||
{
|
{
|
||||||
if (_liveReload) {
|
if (_liveReload) {
|
||||||
RCTSourceCode *sourceCodeModule = self.bridge.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])];
|
RCTSourceCode *sourceCodeModule = _bridge.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])];
|
||||||
NSURL *url = sourceCodeModule.scriptURL;
|
NSURL *url = sourceCodeModule.scriptURL;
|
||||||
NSURL *longPollURL = [[NSURL alloc] initWithString:@"/onchange" relativeToURL:url];
|
NSURL *longPollURL = [[NSURL alloc] initWithString:@"/onchange" relativeToURL:url];
|
||||||
[self performSelectorInBackground:@selector(_checkForUpdates:) withObject:longPollURL];
|
[self performSelectorInBackground:@selector(_checkForUpdates:) withObject:longPollURL];
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
if (_liveReload && response.statusCode == 205) {
|
if (_liveReload && response.statusCode == 205) {
|
||||||
[[RCTRedBox sharedInstance] dismiss];
|
[[RCTRedBox sharedInstance] dismiss];
|
||||||
[self.bridge reload];
|
[_bridge reload];
|
||||||
}
|
}
|
||||||
[self _pollAndReload];
|
[self _pollAndReload];
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
/**
|
/**
|
||||||
* Class that allows easy embedding, loading, life-cycle management of a
|
* Class that allows easy embedding, loading, life-cycle management of a
|
||||||
* JavaScript application inside of a native application.
|
* JavaScript application inside of a native application.
|
||||||
* TODO: Before loading new application source, publish global notification in
|
|
||||||
* JavaScript so that applications can clean up resources. (launch blocker).
|
|
||||||
* TODO: Incremental module loading. (low pri).
|
* TODO: Incremental module loading. (low pri).
|
||||||
*/
|
*/
|
||||||
@interface RCTJavaScriptLoader : NSObject
|
@interface RCTJavaScriptLoader : NSObject
|
||||||
|
|
|
@ -46,8 +46,7 @@
|
||||||
*/
|
*/
|
||||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||||
{
|
{
|
||||||
RCTAssertMainThread();
|
if ((self = [super init])) {
|
||||||
if (self = [super init]) {
|
|
||||||
_bridge = bridge;
|
_bridge = bridge;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
@ -56,12 +55,14 @@
|
||||||
- (void)loadBundleAtURL:(NSURL *)scriptURL onComplete:(void (^)(NSError *))onComplete
|
- (void)loadBundleAtURL:(NSURL *)scriptURL onComplete:(void (^)(NSError *))onComplete
|
||||||
{
|
{
|
||||||
if (scriptURL == nil) {
|
if (scriptURL == nil) {
|
||||||
NSError *error = [NSError errorWithDomain:@"JavaScriptLoader"
|
NSError *error = [NSError errorWithDomain:@"JavaScriptLoader" code:1 userInfo:@{
|
||||||
code:1
|
NSLocalizedDescriptionKey: @"No script URL provided"
|
||||||
userInfo:@{NSLocalizedDescriptionKey: @"No script URL provided"}];
|
}];
|
||||||
onComplete(error);
|
onComplete(error);
|
||||||
return;
|
return;
|
||||||
} else if ([scriptURL isFileURL]) {
|
}
|
||||||
|
|
||||||
|
if ([scriptURL isFileURL]) {
|
||||||
NSString *bundlePath = [[NSBundle bundleForClass:[self class]] resourcePath];
|
NSString *bundlePath = [[NSBundle bundleForClass:[self class]] resourcePath];
|
||||||
NSString *localPath = [scriptURL.absoluteString substringFromIndex:@"file://".length];
|
NSString *localPath = [scriptURL.absoluteString substringFromIndex:@"file://".length];
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,8 @@ static RCTKeyCommands *RKKeyCommandsSharedInstance = nil;
|
||||||
// lookup seems to return nil sometimes, even if the key is found in the dictionary.
|
// lookup seems to return nil sometimes, even if the key is found in the dictionary.
|
||||||
// To fix this, we use a linear search, since there won't be many keys anyway
|
// To fix this, we use a linear search, since there won't be many keys anyway
|
||||||
|
|
||||||
[_commandBindings enumerateKeysAndObjectsUsingBlock:^(UIKeyCommand *k, void (^block)(UIKeyCommand *), BOOL *stop) {
|
[_commandBindings enumerateKeysAndObjectsUsingBlock:
|
||||||
|
^(UIKeyCommand *k, void (^block)(UIKeyCommand *), BOOL *stop) {
|
||||||
if ([key.input isEqualToString:k.input] && key.modifierFlags == k.modifierFlags) {
|
if ([key.input isEqualToString:k.input] && key.modifierFlags == k.modifierFlags) {
|
||||||
block(key);
|
block(key);
|
||||||
}
|
}
|
||||||
|
@ -92,10 +93,12 @@ static RCTKeyCommands *RKKeyCommandsSharedInstance = nil;
|
||||||
UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:input
|
UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:input
|
||||||
modifierFlags:flags
|
modifierFlags:flags
|
||||||
action:@selector(RCT_handleKeyCommand:)];
|
action:@selector(RCT_handleKeyCommand:)];
|
||||||
_commandBindings[command] = block;
|
|
||||||
|
_commandBindings[command] = block ?: ^(UIKeyCommand *cmd) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)unregisterKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
|
- (void)unregisterKeyCommandWithInput:(NSString *)input
|
||||||
|
modifierFlags:(UIKeyModifierFlags)flags
|
||||||
{
|
{
|
||||||
RCTAssertMainThread();
|
RCTAssertMainThread();
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,6 @@ extern "C" {
|
||||||
#define RCTLOG_FATAL_LEVEL RCTLogLevelMustFix
|
#define RCTLOG_FATAL_LEVEL RCTLogLevelMustFix
|
||||||
#define RCTLOG_REDBOX_LEVEL RCTLogLevelError
|
#define RCTLOG_REDBOX_LEVEL RCTLogLevelError
|
||||||
|
|
||||||
/**
|
|
||||||
* A regular expression that can be used to selectively limit the throwing of
|
|
||||||
* a exception to specific log contents.
|
|
||||||
*/
|
|
||||||
#define RCTLOG_FATAL_REGEX nil
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enum representing the severity of the log message.
|
* An enum representing the severity of the log message.
|
||||||
*/
|
*/
|
||||||
|
@ -104,24 +98,10 @@ void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix);
|
||||||
*/
|
*/
|
||||||
void _RCTLogFormat(RCTLogLevel, const char *, int, NSString *, ...) NS_FORMAT_FUNCTION(4,5);
|
void _RCTLogFormat(RCTLogLevel, const char *, int, NSString *, ...) NS_FORMAT_FUNCTION(4,5);
|
||||||
#define _RCTLog(lvl, ...) do { \
|
#define _RCTLog(lvl, ...) do { \
|
||||||
NSString *msg = [NSString stringWithFormat:__VA_ARGS__]; \
|
if (lvl >= RCTLOG_FATAL_LEVEL) { RCTAssert(NO, __VA_ARGS__); } \
|
||||||
if (lvl >= RCTLOG_FATAL_LEVEL) { \
|
|
||||||
BOOL fail = YES; \
|
|
||||||
if (RCTLOG_FATAL_REGEX) { \
|
|
||||||
if ([msg rangeOfString:RCTLOG_FATAL_REGEX options:NSRegularExpressionSearch].length) { \
|
|
||||||
fail = NO; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
RCTCAssert(!fail, @"FATAL ERROR: %@", msg); \
|
|
||||||
}\
|
|
||||||
_RCTLogFormat(lvl, __FILE__, __LINE__, __VA_ARGS__); \
|
_RCTLogFormat(lvl, __FILE__, __LINE__, __VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
|
||||||
* Legacy injection function - don't use this.
|
|
||||||
*/
|
|
||||||
void RCTInjectLogFunction(void (^)(NSString *msg));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logging macros. Use these to log information, warnings and errors in your
|
* Logging macros. Use these to log information, warnings and errors in your
|
||||||
* own code.
|
* own code.
|
||||||
|
|
|
@ -149,14 +149,25 @@ NSString *RCTFormatLog(
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _RCTLogFormat(RCTLogLevel level, const char *fileName, int lineNumber, NSString *format, ...)
|
void _RCTLogFormat(
|
||||||
|
RCTLogLevel level,
|
||||||
|
const char *fileName,
|
||||||
|
int lineNumber,
|
||||||
|
NSString *format, ...)
|
||||||
{
|
{
|
||||||
if (RCTCurrentLogFunction && level >= RCTCurrentLogThreshold) {
|
|
||||||
|
#if DEBUG
|
||||||
|
BOOL log = YES;
|
||||||
|
#else
|
||||||
|
BOOL log = (RCTCurrentLogFunction != nil);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (log && level >= RCTCurrentLogThreshold) {
|
||||||
|
|
||||||
// Get message
|
// Get message
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
__block NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
// Add prefix
|
// Add prefix
|
||||||
|
@ -186,26 +197,3 @@ void _RCTLogFormat(RCTLogLevel level, const char *fileName, int lineNumber, NSSt
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Deprecated
|
|
||||||
|
|
||||||
void RCTInjectLogFunction(void (^logFunction)(NSString *msg))
|
|
||||||
{
|
|
||||||
RCTSetLogFunction(^(RCTLogLevel level,
|
|
||||||
NSString *fileName,
|
|
||||||
NSNumber *lineNumber,
|
|
||||||
NSString *message) {
|
|
||||||
|
|
||||||
if (level > RCTLogLevelError) {
|
|
||||||
|
|
||||||
// Use custom log function
|
|
||||||
NSString *loc = fileName ? [NSString stringWithFormat:@"[%@:%@] ", fileName, lineNumber] : @"";
|
|
||||||
logFunction([loc stringByAppendingString:message]);
|
|
||||||
|
|
||||||
} else if (RCTDefaultLogFunction && level >= RCTCurrentLogThreshold) {
|
|
||||||
|
|
||||||
// Use default logger
|
|
||||||
RCTDefaultLogFunction(level, fileName, lineNumber, message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#import "RCTRedBox.h"
|
#import "RCTRedBox.h"
|
||||||
|
|
||||||
|
#import "RCTBridge.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
|
|
||||||
@interface RCTRedBoxWindow : UIWindow <UITableViewDelegate, UITableViewDataSource>
|
@interface RCTRedBoxWindow : UIWindow <UITableViewDelegate, UITableViewDataSource>
|
||||||
|
@ -120,7 +121,7 @@
|
||||||
|
|
||||||
- (void)reload
|
- (void)reload
|
||||||
{
|
{
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"RCTReloadNotification" object:nil userInfo:nil];
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTReloadNotification object:nil userInfo:nil];
|
||||||
[self dismiss];
|
[self dismiss];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,6 @@
|
||||||
|
|
||||||
#import "RCTBridge.h"
|
#import "RCTBridge.h"
|
||||||
|
|
||||||
extern NSString *const RCTJavaScriptDidLoadNotification;
|
|
||||||
extern NSString *const RCTReloadNotification;
|
|
||||||
extern NSString *const RCTReloadViewsNotification;
|
|
||||||
|
|
||||||
@interface RCTRootView : UIView <RCTInvalidating>
|
@interface RCTRootView : UIView <RCTInvalidating>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,16 +64,13 @@ extern NSString *const RCTReloadViewsNotification;
|
||||||
@property (nonatomic, assign) BOOL enableDevMenu;
|
@property (nonatomic, assign) BOOL enableDevMenu;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reload this root view, or all root views, respectively.
|
* The backing view controller of the root view.
|
||||||
*/
|
*/
|
||||||
- (void)reload;
|
|
||||||
+ (void)reloadAll;
|
|
||||||
|
|
||||||
@property (nonatomic, weak) UIViewController *backingViewController;
|
@property (nonatomic, weak) UIViewController *backingViewController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The React-managed contents view of the root view.
|
||||||
|
*/
|
||||||
@property (nonatomic, strong, readonly) UIView *contentView;
|
@property (nonatomic, strong, readonly) UIView *contentView;
|
||||||
|
|
||||||
- (void)startOrResetInteractionTiming;
|
|
||||||
- (NSDictionary *)endAndResetInteractionTiming;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -24,10 +24,6 @@
|
||||||
#import "RCTWebViewExecutor.h"
|
#import "RCTWebViewExecutor.h"
|
||||||
#import "UIView+React.h"
|
#import "UIView+React.h"
|
||||||
|
|
||||||
NSString *const RCTJavaScriptDidLoadNotification = @"RCTJavaScriptDidLoadNotification";
|
|
||||||
NSString *const RCTReloadNotification = @"RCTReloadNotification";
|
|
||||||
NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HACK(t6568049) This should be removed soon, hiding to prevent people from
|
* HACK(t6568049) This should be removed soon, hiding to prevent people from
|
||||||
* relying on it
|
* relying on it
|
||||||
|
@ -50,7 +46,6 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
||||||
RCTBridge *_bridge;
|
RCTBridge *_bridge;
|
||||||
RCTTouchHandler *_touchHandler;
|
RCTTouchHandler *_touchHandler;
|
||||||
NSString *_moduleName;
|
NSString *_moduleName;
|
||||||
BOOL _registered;
|
|
||||||
NSDictionary *_launchOptions;
|
NSDictionary *_launchOptions;
|
||||||
UIView *_contentView;
|
UIView *_contentView;
|
||||||
}
|
}
|
||||||
|
@ -62,13 +57,26 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
||||||
RCTAssert(moduleName, @"A moduleName is required to create an RCTRootView");
|
RCTAssert(moduleName, @"A moduleName is required to create an RCTRootView");
|
||||||
|
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
|
|
||||||
|
self.backgroundColor = [UIColor whiteColor];
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
_enableDevMenu = YES;
|
_enableDevMenu = YES;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_bridge = bridge;
|
_bridge = bridge;
|
||||||
_moduleName = moduleName;
|
_moduleName = moduleName;
|
||||||
self.backgroundColor = [UIColor whiteColor];
|
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
|
||||||
[self setUp];
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(bundleFinishedLoading)
|
||||||
|
name:RCTJavaScriptDidLoadNotification
|
||||||
|
object:_bridge];
|
||||||
|
if (!_bridge.loading) {
|
||||||
|
[self bundleFinishedLoading];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -77,57 +85,29 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
||||||
moduleName:(NSString *)moduleName
|
moduleName:(NSString *)moduleName
|
||||||
launchOptions:(NSDictionary *)launchOptions
|
launchOptions:(NSDictionary *)launchOptions
|
||||||
{
|
{
|
||||||
RCTBridge *bridge = [[RCTBridge alloc] initWithBundlePath:bundleURL.absoluteString
|
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL
|
||||||
moduleProvider:nil
|
moduleProvider:nil
|
||||||
launchOptions:launchOptions];
|
launchOptions:launchOptions];
|
||||||
return [self initWithBridge:bridge
|
|
||||||
moduleName:moduleName];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc
|
return [self initWithBridge:bridge moduleName:moduleName];
|
||||||
{
|
|
||||||
[self tearDown];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setUp
|
|
||||||
{
|
|
||||||
if (!_registered) {
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(reload)
|
|
||||||
name:RCTReloadViewsNotification
|
|
||||||
object:_bridge];
|
|
||||||
if (_bridge.loaded) {
|
|
||||||
[self bundleFinishedLoading];
|
|
||||||
} else {
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(bundleFinishedLoading)
|
|
||||||
name:RCTJavaScriptDidLoadNotification
|
|
||||||
object:_bridge];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tearDown
|
|
||||||
{
|
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
||||||
if (_registered) {
|
|
||||||
_registered = NO;
|
|
||||||
[_contentView removeGestureRecognizer:_touchHandler];
|
|
||||||
[_contentView removeFromSuperview];
|
|
||||||
[_touchHandler invalidate];
|
|
||||||
[_bridge enqueueJSCall:@"ReactIOS.unmountComponentAtNodeAndRemoveContainer"
|
|
||||||
args:@[_contentView.reactTag]];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isValid
|
- (BOOL)isValid
|
||||||
{
|
{
|
||||||
return _registered;
|
return _contentView.userInteractionEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)invalidate
|
- (void)invalidate
|
||||||
{
|
{
|
||||||
[self tearDown];
|
_contentView.userInteractionEnabled = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
[_touchHandler invalidate];
|
||||||
|
[_bridge enqueueJSCall:@"ReactIOS.unmountComponentAtNodeAndRemoveContainer"
|
||||||
|
args:@[_contentView.reactTag]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIViewController *)backingViewController {
|
- (UIViewController *)backingViewController {
|
||||||
|
@ -143,7 +123,7 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification";
|
||||||
{
|
{
|
||||||
if (motion == UIEventSubtypeMotionShake && self.enableDevMenu) {
|
if (motion == UIEventSubtypeMotionShake && self.enableDevMenu) {
|
||||||
if (!_devMenu) {
|
if (!_devMenu) {
|
||||||
_devMenu = [[RCTDevMenu alloc] initWithBridge:self.bridge];
|
_devMenu = [[RCTDevMenu alloc] initWithBridge:_bridge];
|
||||||
}
|
}
|
||||||
[_devMenu show];
|
[_devMenu show];
|
||||||
}
|
}
|
||||||
|
@ -155,7 +135,7 @@ RCT_IMPORT_METHOD(ReactIOS, unmountComponentAtNodeAndRemoveContainer)
|
||||||
- (void)bundleFinishedLoading
|
- (void)bundleFinishedLoading
|
||||||
{
|
{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
_registered = YES;
|
|
||||||
/**
|
/**
|
||||||
* Every root view that is created must have a unique react tag.
|
* Every root view that is created must have a unique react tag.
|
||||||
* Numbering of these tags goes from 1, 11, 21, 31, etc
|
* Numbering of these tags goes from 1, 11, 21, 31, etc
|
||||||
|
@ -163,6 +143,8 @@ RCT_IMPORT_METHOD(ReactIOS, unmountComponentAtNodeAndRemoveContainer)
|
||||||
* NOTE: Since the bridge persists, the RootViews might be reused, so now
|
* NOTE: Since the bridge persists, the RootViews might be reused, so now
|
||||||
* the react tag is assigned every time we load new content.
|
* the react tag is assigned every time we load new content.
|
||||||
*/
|
*/
|
||||||
|
[_touchHandler invalidate];
|
||||||
|
[_contentView removeFromSuperview];
|
||||||
_contentView = [[UIView alloc] initWithFrame:self.bounds];
|
_contentView = [[UIView alloc] initWithFrame:self.bounds];
|
||||||
_contentView.reactTag = [_bridge.uiManager allocateRootTag];
|
_contentView.reactTag = [_bridge.uiManager allocateRootTag];
|
||||||
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
|
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
|
||||||
|
@ -183,45 +165,17 @@ RCT_IMPORT_METHOD(ReactIOS, unmountComponentAtNodeAndRemoveContainer)
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
[super layoutSubviews];
|
[super layoutSubviews];
|
||||||
_contentView.frame = self.bounds;
|
if (_contentView) {
|
||||||
if (_registered) {
|
_contentView.frame = self.bounds;
|
||||||
[_bridge.uiManager setFrame:self.frame forRootView:_contentView];
|
[_bridge.uiManager setFrame:self.frame forRootView:_contentView];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFrame:(CGRect)frame
|
|
||||||
{
|
|
||||||
[super setFrame:frame];
|
|
||||||
_contentView.frame = self.bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)reload
|
|
||||||
{
|
|
||||||
[self tearDown];
|
|
||||||
[self setUp];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)reloadAll
|
|
||||||
{
|
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTReloadNotification
|
|
||||||
object:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSNumber *)reactTag
|
- (NSNumber *)reactTag
|
||||||
{
|
{
|
||||||
return _contentView.reactTag;
|
return _contentView.reactTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)startOrResetInteractionTiming
|
|
||||||
{
|
|
||||||
[_touchHandler startOrResetInteractionTiming];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSDictionary *)endAndResetInteractionTiming
|
|
||||||
{
|
|
||||||
return [_touchHandler endAndResetInteractionTiming];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation RCTUIManager (RCTRootView)
|
@implementation RCTUIManager (RCTRootView)
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
+ (instancetype)touchWithEventName:(NSString *)eventName touches:(NSArray *)touches changedIndexes:(NSArray *)changedIndexes originatingTime:(CFTimeInterval)originatingTime
|
+ (instancetype)touchWithEventName:(NSString *)eventName touches:(NSArray *)touches changedIndexes:(NSArray *)changedIndexes originatingTime:(CFTimeInterval)originatingTime
|
||||||
{
|
{
|
||||||
RCTTouchEvent *touchEvent = [[self alloc] init];
|
RCTTouchEvent *touchEvent = [[self alloc] init];
|
||||||
touchEvent->_id = [self newID];
|
touchEvent->_id = [self newTaskID];
|
||||||
touchEvent->_eventName = [eventName copy];
|
touchEvent->_eventName = [eventName copy];
|
||||||
touchEvent->_touches = [touches copy];
|
touchEvent->_touches = [touches copy];
|
||||||
touchEvent->_changedIndexes = [changedIndexes copy];
|
touchEvent->_changedIndexes = [changedIndexes copy];
|
||||||
|
@ -45,10 +45,10 @@
|
||||||
return touchEvent;
|
return touchEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSUInteger)newID
|
+ (NSUInteger)newTaskID
|
||||||
{
|
{
|
||||||
static NSUInteger id = 0;
|
static NSUInteger taskID = 0;
|
||||||
return ++id;
|
return ++taskID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -282,7 +282,7 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveTouches);
|
||||||
[_bridgeInteractionTiming addObject:@{
|
[_bridgeInteractionTiming addObject:@{
|
||||||
@"timeSeconds": @(sender.timestamp),
|
@"timeSeconds": @(sender.timestamp),
|
||||||
@"operation": @"mainThreadDisplayLink",
|
@"operation": @"mainThreadDisplayLink",
|
||||||
@"taskID": @([RCTTouchEvent newID]),
|
@"taskID": @([RCTTouchEvent newTaskID]),
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,12 +42,9 @@ static void RCTReportError(RCTJavaScriptCallback callback, NSString *fmt, ...)
|
||||||
|
|
||||||
- (instancetype)initWithWebView:(UIWebView *)webView
|
- (instancetype)initWithWebView:(UIWebView *)webView
|
||||||
{
|
{
|
||||||
if (!webView) {
|
|
||||||
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Can't init with a nil webview" userInfo:nil];
|
|
||||||
}
|
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_objectsToInject = [[NSMutableDictionary alloc] init];
|
_objectsToInject = [[NSMutableDictionary alloc] init];
|
||||||
_webView = webView;
|
_webView = webView ?: [[UIWebView alloc] init];
|
||||||
_webView.delegate = self;
|
_webView.delegate = self;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
@ -55,7 +52,7 @@ static void RCTReportError(RCTJavaScriptCallback callback, NSString *fmt, ...)
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
return [self initWithWebView:[[UIWebView alloc] init]];
|
return [self initWithWebView:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isValid
|
- (BOOL)isValid
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#import "RCTScrollableProtocol.h"
|
#import "RCTScrollableProtocol.h"
|
||||||
#import "RCTShadowView.h"
|
#import "RCTShadowView.h"
|
||||||
#import "RCTSparseArray.h"
|
#import "RCTSparseArray.h"
|
||||||
|
#import "RCTTouchHandler.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
#import "RCTView.h"
|
#import "RCTView.h"
|
||||||
#import "RCTViewManager.h"
|
#import "RCTViewManager.h"
|
||||||
|
@ -211,7 +212,7 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
|
||||||
static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
||||||
{
|
{
|
||||||
NSString *name = moduleName;
|
NSString *name = moduleName;
|
||||||
RCTCAssert(name.length, @"Invalid moduleName '%@'", moduleName);
|
RCTAssert(name.length, @"Invalid moduleName '%@'", moduleName);
|
||||||
if ([name hasSuffix:@"Manager"]) {
|
if ([name hasSuffix:@"Manager"]) {
|
||||||
name = [name substringToIndex:name.length - @"Manager".length];
|
name = [name substringToIndex:name.length - @"Manager".length];
|
||||||
}
|
}
|
||||||
|
@ -258,31 +259,6 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
||||||
RCTAssert(!self.valid, @"must call -invalidate before -dealloc");
|
RCTAssert(!self.valid, @"must call -invalidate before -dealloc");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBridge:(RCTBridge *)bridge
|
|
||||||
{
|
|
||||||
if (_bridge) {
|
|
||||||
|
|
||||||
// Clear previous bridge data
|
|
||||||
[self invalidate];
|
|
||||||
}
|
|
||||||
if (bridge) {
|
|
||||||
|
|
||||||
_bridge = bridge;
|
|
||||||
_shadowQueue = _bridge.shadowQueue;
|
|
||||||
_shadowViewRegistry = [[RCTSparseArray alloc] init];
|
|
||||||
|
|
||||||
// Get view managers from bridge
|
|
||||||
NSMutableDictionary *viewManagers = [[NSMutableDictionary alloc] init];
|
|
||||||
[_bridge.modules enumerateKeysAndObjectsUsingBlock:^(NSString *moduleName, RCTViewManager *manager, BOOL *stop) {
|
|
||||||
if ([manager isKindOfClass:[RCTViewManager class]]) {
|
|
||||||
viewManagers[RCTViewNameForModuleName(moduleName)] = manager;
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
|
|
||||||
_viewManagers = [viewManagers copy];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isValid
|
- (BOOL)isValid
|
||||||
{
|
{
|
||||||
return _viewRegistry != nil;
|
return _viewRegistry != nil;
|
||||||
|
@ -292,8 +268,13 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
||||||
{
|
{
|
||||||
RCTAssertMainThread();
|
RCTAssertMainThread();
|
||||||
|
|
||||||
_viewRegistry = nil;
|
for (NSNumber *rootViewTag in _rootViewTags) {
|
||||||
|
((UIView *)_viewRegistry[rootViewTag]).userInteractionEnabled = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rootViewTags = nil;
|
||||||
_shadowViewRegistry = nil;
|
_shadowViewRegistry = nil;
|
||||||
|
_viewRegistry = nil;
|
||||||
_bridge = nil;
|
_bridge = nil;
|
||||||
|
|
||||||
[_pendingUIBlocksLock lock];
|
[_pendingUIBlocksLock lock];
|
||||||
|
@ -301,6 +282,25 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
||||||
[_pendingUIBlocksLock unlock];
|
[_pendingUIBlocksLock unlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setBridge:(RCTBridge *)bridge
|
||||||
|
{
|
||||||
|
RCTAssert(_bridge == nil, @"Should not re-use same UIIManager instance");
|
||||||
|
|
||||||
|
_bridge = bridge;
|
||||||
|
_shadowQueue = _bridge.shadowQueue;
|
||||||
|
_shadowViewRegistry = [[RCTSparseArray alloc] init];
|
||||||
|
|
||||||
|
// Get view managers from bridge
|
||||||
|
NSMutableDictionary *viewManagers = [[NSMutableDictionary alloc] init];
|
||||||
|
[_bridge.modules enumerateKeysAndObjectsUsingBlock:^(NSString *moduleName, RCTViewManager *manager, BOOL *stop) {
|
||||||
|
if ([manager isKindOfClass:[RCTViewManager class]]) {
|
||||||
|
viewManagers[RCTViewNameForModuleName(moduleName)] = manager;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
_viewManagers = [viewManagers copy];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)registerRootView:(UIView *)rootView;
|
- (void)registerRootView:(UIView *)rootView;
|
||||||
{
|
{
|
||||||
RCTAssertMainThread();
|
RCTAssertMainThread();
|
||||||
|
@ -310,8 +310,8 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
||||||
@"View %@ with tag #%@ is not a root view", rootView, reactTag);
|
@"View %@ with tag #%@ is not a root view", rootView, reactTag);
|
||||||
|
|
||||||
UIView *existingView = _viewRegistry[reactTag];
|
UIView *existingView = _viewRegistry[reactTag];
|
||||||
RCTCAssert(existingView == nil || existingView == rootView,
|
RCTAssert(existingView == nil || existingView == rootView,
|
||||||
@"Expect all root views to have unique tag. Added %@ twice", reactTag);
|
@"Expect all root views to have unique tag. Added %@ twice", reactTag);
|
||||||
|
|
||||||
// Register view
|
// Register view
|
||||||
_viewRegistry[reactTag] = rootView;
|
_viewRegistry[reactTag] = rootView;
|
||||||
|
@ -548,7 +548,7 @@ RCT_EXPORT_METHOD(removeSubviewsFromContainerWithID:(NSNumber *)containerID)
|
||||||
}
|
}
|
||||||
// Construction of removed children must be done "up front", before indices are disturbed by removals.
|
// Construction of removed children must be done "up front", before indices are disturbed by removals.
|
||||||
NSMutableArray *removedChildren = [NSMutableArray arrayWithCapacity:atIndices.count];
|
NSMutableArray *removedChildren = [NSMutableArray arrayWithCapacity:atIndices.count];
|
||||||
RCTCAssert(container != nil, @"container view (for ID %@) not found", container);
|
RCTAssert(container != nil, @"container view (for ID %@) not found", container);
|
||||||
for (NSInteger i = 0; i < [atIndices count]; i++) {
|
for (NSInteger i = 0; i < [atIndices count]; i++) {
|
||||||
NSInteger index = [atIndices[i] integerValue];
|
NSInteger index = [atIndices[i] integerValue];
|
||||||
if (index < [[container reactSubviews] count]) {
|
if (index < [[container reactSubviews] count]) {
|
||||||
|
@ -577,7 +577,7 @@ RCT_EXPORT_METHOD(removeRootView:(NSNumber *)rootReactTag)
|
||||||
[_rootViewTags removeObject:rootReactTag];
|
[_rootViewTags removeObject:rootReactTag];
|
||||||
|
|
||||||
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
||||||
RCTCAssertMainThread();
|
RCTAssertMainThread();
|
||||||
UIView *rootView = viewRegistry[rootReactTag];
|
UIView *rootView = viewRegistry[rootReactTag];
|
||||||
[uiManager _purgeChildren:rootView.reactSubviews fromRegistry:viewRegistry];
|
[uiManager _purgeChildren:rootView.reactSubviews fromRegistry:viewRegistry];
|
||||||
viewRegistry[rootReactTag] = nil;
|
viewRegistry[rootReactTag] = nil;
|
||||||
|
@ -666,7 +666,7 @@ RCT_EXPORT_METHOD(manageChildren:(NSNumber *)containerReactTag
|
||||||
|
|
||||||
NSArray *sortedIndices = [[destinationsToChildrenToAdd allKeys] sortedArrayUsingSelector:@selector(compare:)];
|
NSArray *sortedIndices = [[destinationsToChildrenToAdd allKeys] sortedArrayUsingSelector:@selector(compare:)];
|
||||||
for (NSNumber *reactIndex in sortedIndices) {
|
for (NSNumber *reactIndex in sortedIndices) {
|
||||||
[container insertReactSubview:destinationsToChildrenToAdd[reactIndex] atIndex:[reactIndex integerValue]];
|
[container insertReactSubview:destinationsToChildrenToAdd[reactIndex] atIndex:reactIndex.integerValue];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,7 +757,7 @@ RCT_EXPORT_METHOD(createView:(NSNumber *)reactTag
|
||||||
_shadowViewRegistry[reactTag] = shadowView;
|
_shadowViewRegistry[reactTag] = shadowView;
|
||||||
|
|
||||||
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
||||||
RCTCAssertMainThread();
|
RCTAssertMainThread();
|
||||||
|
|
||||||
UIView *view = [manager view];
|
UIView *view = [manager view];
|
||||||
if (view) {
|
if (view) {
|
||||||
|
@ -782,6 +782,7 @@ RCT_EXPORT_METHOD(createView:(NSNumber *)reactTag
|
||||||
viewRegistry[reactTag] = view;
|
viewRegistry[reactTag] = view;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove viewName param as it isn't needed
|
// TODO: remove viewName param as it isn't needed
|
||||||
RCT_EXPORT_METHOD(updateView:(NSNumber *)reactTag
|
RCT_EXPORT_METHOD(updateView:(NSNumber *)reactTag
|
||||||
viewName:(__unused NSString *)_
|
viewName:(__unused NSString *)_
|
||||||
|
@ -898,7 +899,7 @@ RCT_EXPORT_METHOD(measure:(NSNumber *)reactTag
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this doesn't work because sometimes view is inside a modal window
|
// TODO: this doesn't work because sometimes view is inside a modal window
|
||||||
// RCTCAssert([rootView isReactRootView], @"React view is not inside a react root view");
|
// RCTAssert([rootView isReactRootView], @"React view is not inside a react root view");
|
||||||
|
|
||||||
// By convention, all coordinates, whether they be touch coordinates, or
|
// By convention, all coordinates, whether they be touch coordinates, or
|
||||||
// measurement coordinates are with respect to the root view.
|
// measurement coordinates are with respect to the root view.
|
||||||
|
@ -1036,12 +1037,12 @@ RCT_EXPORT_METHOD(setMainScrollViewTag:(NSNumber *)reactTag)
|
||||||
uiManager.mainScrollView.nativeMainScrollDelegate = nil;
|
uiManager.mainScrollView.nativeMainScrollDelegate = nil;
|
||||||
}
|
}
|
||||||
if (reactTag) {
|
if (reactTag) {
|
||||||
id rkObject = viewRegistry[reactTag];
|
id view = viewRegistry[reactTag];
|
||||||
if ([rkObject conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
||||||
uiManager.mainScrollView = (id<RCTScrollableProtocol>)rkObject;
|
uiManager.mainScrollView = (id<RCTScrollableProtocol>)view;
|
||||||
((id<RCTScrollableProtocol>)rkObject).nativeMainScrollDelegate = uiManager.nativeMainScrollDelegate;
|
uiManager.mainScrollView.nativeMainScrollDelegate = uiManager.nativeMainScrollDelegate;
|
||||||
} else {
|
} else {
|
||||||
RCTCAssert(NO, @"Tag #%@ does not conform to RCTScrollableProtocol", reactTag);
|
RCTAssert(NO, @"Tag #%@ does not conform to RCTScrollableProtocol", reactTag);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uiManager.mainScrollView = nil;
|
uiManager.mainScrollView = nil;
|
||||||
|
@ -1049,28 +1050,30 @@ RCT_EXPORT_METHOD(setMainScrollViewTag:(NSNumber *)reactTag)
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: we could just pass point property
|
||||||
RCT_EXPORT_METHOD(scrollTo:(NSNumber *)reactTag
|
RCT_EXPORT_METHOD(scrollTo:(NSNumber *)reactTag
|
||||||
withOffsetX:(NSNumber *)offsetX
|
withOffsetX:(CGFloat)offsetX
|
||||||
offsetY:(NSNumber *)offsetY)
|
offsetY:(CGFloat)offsetY)
|
||||||
{
|
{
|
||||||
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
||||||
UIView *view = viewRegistry[reactTag];
|
UIView *view = viewRegistry[reactTag];
|
||||||
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
||||||
[(id<RCTScrollableProtocol>)view scrollToOffset:CGPointMake([offsetX floatValue], [offsetY floatValue]) animated:YES];
|
[(id<RCTScrollableProtocol>)view scrollToOffset:(CGPoint){offsetX, offsetY} animated:YES];
|
||||||
} else {
|
} else {
|
||||||
RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
|
RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: we could just pass point property
|
||||||
RCT_EXPORT_METHOD(scrollWithoutAnimationTo:(NSNumber *)reactTag
|
RCT_EXPORT_METHOD(scrollWithoutAnimationTo:(NSNumber *)reactTag
|
||||||
offsetX:(NSNumber *)offsetX
|
offsetX:(CGFloat)offsetX
|
||||||
offsetY:(NSNumber *)offsetY)
|
offsetY:(CGFloat)offsetY)
|
||||||
{
|
{
|
||||||
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
||||||
UIView *view = viewRegistry[reactTag];
|
UIView *view = viewRegistry[reactTag];
|
||||||
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
||||||
[(id<RCTScrollableProtocol>)view scrollToOffset:CGPointMake([offsetX floatValue], [offsetY floatValue]) animated:NO];
|
[(id<RCTScrollableProtocol>)view scrollToOffset:(CGPoint){offsetX, offsetY} animated:NO];
|
||||||
} else {
|
} else {
|
||||||
RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
|
RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
|
||||||
}
|
}
|
||||||
|
@ -1078,12 +1081,12 @@ RCT_EXPORT_METHOD(scrollWithoutAnimationTo:(NSNumber *)reactTag
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(zoomToRect:(NSNumber *)reactTag
|
RCT_EXPORT_METHOD(zoomToRect:(NSNumber *)reactTag
|
||||||
withRect:(NSDictionary *)rectDict)
|
withRect:(CGRect)rect)
|
||||||
{
|
{
|
||||||
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
|
||||||
UIView *view = viewRegistry[reactTag];
|
UIView *view = viewRegistry[reactTag];
|
||||||
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
|
||||||
[(id<RCTScrollableProtocol>)view zoomToRect:[RCTConvert CGRect:rectDict] animated:YES];
|
[(id<RCTScrollableProtocol>)view zoomToRect:rect animated:YES];
|
||||||
} else {
|
} else {
|
||||||
RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
|
RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
|
||||||
}
|
}
|
||||||
|
@ -1209,8 +1212,8 @@ RCT_EXPORT_METHOD(clearJSResponder)
|
||||||
if (RCTClassOverridesInstanceMethod([manager class], @selector(customBubblingEventTypes))) {
|
if (RCTClassOverridesInstanceMethod([manager class], @selector(customBubblingEventTypes))) {
|
||||||
NSDictionary *eventTypes = [manager customBubblingEventTypes];
|
NSDictionary *eventTypes = [manager customBubblingEventTypes];
|
||||||
for (NSString *eventName in eventTypes) {
|
for (NSString *eventName in eventTypes) {
|
||||||
RCTCAssert(!customBubblingEventTypesConfigs[eventName],
|
RCTAssert(!customBubblingEventTypesConfigs[eventName],
|
||||||
@"Event '%@' registered multiple times.", eventName);
|
@"Event '%@' registered multiple times.", eventName);
|
||||||
}
|
}
|
||||||
[customBubblingEventTypesConfigs addEntriesFromDictionary:eventTypes];
|
[customBubblingEventTypesConfigs addEntriesFromDictionary:eventTypes];
|
||||||
}
|
}
|
||||||
|
@ -1261,7 +1264,7 @@ RCT_EXPORT_METHOD(clearJSResponder)
|
||||||
if (RCTClassOverridesInstanceMethod([manager class], @selector(customDirectEventTypes))) {
|
if (RCTClassOverridesInstanceMethod([manager class], @selector(customDirectEventTypes))) {
|
||||||
NSDictionary *eventTypes = [manager customDirectEventTypes];
|
NSDictionary *eventTypes = [manager customDirectEventTypes];
|
||||||
for (NSString *eventName in eventTypes) {
|
for (NSString *eventName in eventTypes) {
|
||||||
RCTCAssert(!customDirectEventTypes[eventName], @"Event '%@' registered multiple times.", eventName);
|
RCTAssert(!customDirectEventTypes[eventName], @"Event '%@' registered multiple times.", eventName);
|
||||||
}
|
}
|
||||||
[customDirectEventTypes addEntriesFromDictionary:eventTypes];
|
[customDirectEventTypes addEntriesFromDictionary:eventTypes];
|
||||||
}
|
}
|
||||||
|
@ -1395,9 +1398,12 @@ RCT_EXPORT_METHOD(startOrResetInteractionTiming)
|
||||||
NSSet *rootViewTags = [_rootViewTags copy];
|
NSSet *rootViewTags = [_rootViewTags copy];
|
||||||
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||||
for (NSNumber *reactTag in rootViewTags) {
|
for (NSNumber *reactTag in rootViewTags) {
|
||||||
id rootView = viewRegistry[reactTag];
|
UIView *rootView = viewRegistry[reactTag];
|
||||||
if ([rootView respondsToSelector:@selector(startOrResetInteractionTiming)]) {
|
for (RCTTouchHandler *handler in rootView.gestureRecognizers) {
|
||||||
[rootView startOrResetInteractionTiming];
|
if ([handler isKindOfClass:[RCTTouchHandler class]]) {
|
||||||
|
[handler startOrResetInteractionTiming];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
@ -1410,9 +1416,12 @@ RCT_EXPORT_METHOD(endAndResetInteractionTiming:(RCTResponseSenderBlock)onSuccess
|
||||||
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||||
NSMutableDictionary *timingData = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *timingData = [[NSMutableDictionary alloc] init];
|
||||||
for (NSNumber *reactTag in rootViewTags) {
|
for (NSNumber *reactTag in rootViewTags) {
|
||||||
id rootView = viewRegistry[reactTag];
|
UIView *rootView = viewRegistry[reactTag];
|
||||||
if ([rootView respondsToSelector:@selector(endAndResetInteractionTiming)]) {
|
for (RCTTouchHandler *handler in rootView.gestureRecognizers) {
|
||||||
timingData[reactTag.stringValue] = [rootView endAndResetInteractionTiming];
|
if ([handler isKindOfClass:[RCTTouchHandler class]]) {
|
||||||
|
[handler endAndResetInteractionTiming];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onSuccess(@[timingData]);
|
onSuccess(@[timingData]);
|
||||||
|
|
Loading…
Reference in New Issue