This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

167
node_modules/react-native/React/Base/RCTAssert.h generated vendored Normal file
View File

@ -0,0 +1,167 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTDefines.h>
/*
* Defined in RCTUtils.m
*/
RCT_EXTERN BOOL RCTIsMainQueue(void);
/**
* This is the main assert macro that you should use. Asserts should be compiled out
* in production builds. You can customize the assert behaviour by setting a custom
* assert handler through `RCTSetAssertFunction`.
*/
#ifndef NS_BLOCK_ASSERTIONS
#define RCTAssert(condition, ...) \
do { \
if ((condition) == 0) { \
_RCTAssertFormat(#condition, __FILE__, __LINE__, __func__, __VA_ARGS__); \
if (RCT_NSASSERT) { \
[[NSAssertionHandler currentHandler] handleFailureInFunction:(NSString * _Nonnull) @(__func__) \
file:(NSString * _Nonnull) @(__FILE__) \
lineNumber:__LINE__ \
description:__VA_ARGS__]; \
} \
} \
} while (false)
#else
#define RCTAssert(condition, ...) \
do { \
} while (false)
#endif
RCT_EXTERN void _RCTAssertFormat(const char *, const char *, int, const char *, NSString *, ...)
NS_FORMAT_FUNCTION(5, 6);
/**
* Report a fatal condition when executing. These calls will _NOT_ be compiled out
* in production, and crash the app by default. You can customize the fatal behaviour
* by setting a custom fatal handler through `RCTSetFatalHandler` and
* `RCTSetFatalExceptionHandler`.
*/
RCT_EXTERN void RCTFatal(NSError *error);
RCT_EXTERN void RCTFatalException(NSException *exception);
/**
* The default error domain to be used for React errors.
*/
RCT_EXTERN NSString *const RCTErrorDomain;
/**
* JS Stack trace provided as part of an NSError's userInfo
*/
RCT_EXTERN NSString *const RCTJSStackTraceKey;
/**
* Raw JS Stack trace string provided as part of an NSError's userInfo
*/
RCT_EXTERN NSString *const RCTJSRawStackTraceKey;
/**
* Name of fatal exceptions generated by RCTFatal
*/
RCT_EXTERN NSString *const RCTFatalExceptionName;
/**
* A block signature to be used for custom assertion handling.
*/
typedef void (^RCTAssertFunction)(
NSString *condition,
NSString *fileName,
NSNumber *lineNumber,
NSString *function,
NSString *message);
typedef void (^RCTFatalHandler)(NSError *error);
typedef void (^RCTFatalExceptionHandler)(NSException *exception);
/**
* Convenience macro for asserting that a parameter is non-nil/non-zero.
*/
#define RCTAssertParam(name) RCTAssert(name, @"'%s' is a required parameter", #name)
/**
* Convenience macro for asserting that we're running on main queue.
*/
#define RCTAssertMainQueue() RCTAssert(RCTIsMainQueue(), @"This function must be called on the main queue")
/**
* Convenience macro for asserting that we're running off the main queue.
*/
#define RCTAssertNotMainQueue() RCTAssert(!RCTIsMainQueue(), @"This function must not be called on the main queue")
/**
* 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 assert
* functionality.
*/
RCT_EXTERN void RCTSetAssertFunction(RCTAssertFunction assertFunction);
RCT_EXTERN 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.
*/
RCT_EXTERN void RCTAddAssertFunction(RCTAssertFunction assertFunction);
/**
* This method temporarily overrides the assert function while performing the
* specified block. This is useful for testing purposes (to detect if a given
* function asserts something) or to suppress or override assertions temporarily.
*/
RCT_EXTERN void RCTPerformBlockWithAssertFunction(void (^block)(void), RCTAssertFunction assertFunction);
/**
* These methods get and set the current fatal handler called by the `RCTFatal`
* and `RCTFatalException` methods.
*/
RCT_EXTERN void RCTSetFatalHandler(RCTFatalHandler fatalHandler);
RCT_EXTERN RCTFatalHandler RCTGetFatalHandler(void);
RCT_EXTERN void RCTSetFatalExceptionHandler(RCTFatalExceptionHandler fatalExceptionHandler);
RCT_EXTERN RCTFatalExceptionHandler RCTGetFatalExceptionHandler(void);
/**
* Get the current thread's name (or the current queue, if in debug mode)
*/
RCT_EXTERN NSString *RCTCurrentThreadName(void);
/**
* Helper to get generate exception message from NSError
*/
RCT_EXTERN NSString *
RCTFormatError(NSString *message, NSArray<NSDictionary<NSString *, id> *> *stacktrace, NSUInteger maxMessageLength);
/**
* Formats a JS stack trace for logging.
*/
RCT_EXTERN NSString *RCTFormatStackTrace(NSArray<NSDictionary<NSString *, id> *> *stackTrace);
/**
* Convenience macro to assert which thread is currently running (DEBUG mode only)
*/
#if DEBUG
#define RCTAssertThread(thread, format...) \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") RCTAssert( \
[(id)thread isKindOfClass:[NSString class]] \
? [RCTCurrentThreadName() isEqualToString:(NSString *)thread] \
: [(id)thread isKindOfClass:[NSThread class]] ? [NSThread currentThread] == (NSThread *)thread \
: dispatch_get_current_queue() == (dispatch_queue_t)thread, \
format); \
_Pragma("clang diagnostic pop")
#else
#define RCTAssertThread(thread, format...) \
do { \
} while (0)
#endif

231
node_modules/react-native/React/Base/RCTAssert.m generated vendored Normal file
View File

@ -0,0 +1,231 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTAssert.h"
#import "RCTLog.h"
NSString *const RCTErrorDomain = @"RCTErrorDomain";
NSString *const RCTJSStackTraceKey = @"RCTJSStackTraceKey";
NSString *const RCTJSRawStackTraceKey = @"RCTJSRawStackTraceKey";
NSString *const RCTFatalExceptionName = @"RCTFatalException";
NSString *const RCTUntruncatedMessageKey = @"RCTUntruncatedMessageKey";
static NSString *const RCTAssertFunctionStack = @"RCTAssertFunctionStack";
RCTAssertFunction RCTCurrentAssertFunction = nil;
RCTFatalHandler RCTCurrentFatalHandler = nil;
RCTFatalExceptionHandler RCTCurrentFatalExceptionHandler = nil;
NSException *_RCTNotImplementedException(SEL, Class);
NSException *_RCTNotImplementedException(SEL cmd, Class cls)
{
NSString *msg = [NSString stringWithFormat:
@"%s is not implemented "
"for the class %@",
sel_getName(cmd),
cls];
return [NSException exceptionWithName:@"RCTNotDesignatedInitializerException" reason:msg userInfo:nil];
}
void RCTSetAssertFunction(RCTAssertFunction assertFunction)
{
RCTCurrentAssertFunction = assertFunction;
}
RCTAssertFunction RCTGetAssertFunction(void)
{
return RCTCurrentAssertFunction;
}
void RCTAddAssertFunction(RCTAssertFunction assertFunction)
{
RCTAssertFunction existing = RCTCurrentAssertFunction;
if (existing) {
RCTCurrentAssertFunction =
^(NSString *condition, NSString *fileName, NSNumber *lineNumber, NSString *function, NSString *message) {
existing(condition, fileName, lineNumber, function, message);
assertFunction(condition, fileName, lineNumber, function, message);
};
} else {
RCTCurrentAssertFunction = assertFunction;
}
}
/**
* returns the topmost stacked assert function for the current thread, which
* may not be the same as the current value of RCTCurrentAssertFunction.
*/
static RCTAssertFunction RCTGetLocalAssertFunction()
{
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
NSArray<RCTAssertFunction> *functionStack = threadDictionary[RCTAssertFunctionStack];
RCTAssertFunction assertFunction = functionStack.lastObject;
if (assertFunction) {
return assertFunction;
}
return RCTCurrentAssertFunction;
}
void RCTPerformBlockWithAssertFunction(void (^block)(void), RCTAssertFunction assertFunction)
{
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
NSMutableArray<RCTAssertFunction> *functionStack = threadDictionary[RCTAssertFunctionStack];
if (!functionStack) {
functionStack = [NSMutableArray new];
threadDictionary[RCTAssertFunctionStack] = functionStack;
}
[functionStack addObject:assertFunction];
block();
[functionStack removeLastObject];
}
NSString *RCTCurrentThreadName(void)
{
NSThread *thread = [NSThread currentThread];
NSString *threadName = RCTIsMainQueue() || thread.isMainThread ? @"main" : thread.name;
if (threadName.length == 0) {
const char *label = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL);
if (label && strlen(label) > 0) {
threadName = @(label);
} else {
threadName = [NSString stringWithFormat:@"%p", thread];
}
}
return threadName;
}
void _RCTAssertFormat(
const char *condition,
const char *fileName,
int lineNumber,
const char *function,
NSString *format,
...)
{
RCTAssertFunction assertFunction = RCTGetLocalAssertFunction();
if (assertFunction) {
va_list args;
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
assertFunction(@(condition), @(fileName), @(lineNumber), @(function), message);
}
}
void RCTFatal(NSError *error)
{
_RCTLogNativeInternal(RCTLogLevelFatal, NULL, 0, @"%@", error.localizedDescription);
RCTFatalHandler fatalHandler = RCTGetFatalHandler();
if (fatalHandler) {
fatalHandler(error);
} else {
#if DEBUG
@try {
#endif
NSString *name = [NSString stringWithFormat:@"%@: %@", RCTFatalExceptionName, error.localizedDescription];
// Truncate the localized description to 175 characters to avoid wild screen overflows
NSString *message = RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], 175);
// Attach an untruncated copy of the description to the userInfo, in case it is needed
NSMutableDictionary *userInfo = [error.userInfo mutableCopy];
[userInfo setObject:RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], -1)
forKey:RCTUntruncatedMessageKey];
// Expected resulting exception information:
// name: RCTFatalException: <underlying error description>
// reason: <underlying error description plus JS stack trace, truncated to 175 characters>
// userInfo: <underlying error userinfo, plus untruncated description plus JS stack trace>
@throw [[NSException alloc] initWithName:name reason:message userInfo:userInfo];
#if DEBUG
} @catch (NSException *e) {
}
#endif
}
}
void RCTSetFatalHandler(RCTFatalHandler fatalHandler)
{
RCTCurrentFatalHandler = fatalHandler;
}
RCTFatalHandler RCTGetFatalHandler(void)
{
return RCTCurrentFatalHandler;
}
NSString *
RCTFormatError(NSString *message, NSArray<NSDictionary<NSString *, id> *> *stackTrace, NSUInteger maxMessageLength)
{
if (maxMessageLength > 0 && message.length > maxMessageLength) {
message = [[message substringToIndex:maxMessageLength] stringByAppendingString:@"..."];
}
NSString *prettyStack = RCTFormatStackTrace(stackTrace);
return [NSString
stringWithFormat:@"%@%@%@", message, prettyStack ? @", stack:\n" : @"", prettyStack ? prettyStack : @""];
}
NSString *RCTFormatStackTrace(NSArray<NSDictionary<NSString *, id> *> *stackTrace)
{
if (stackTrace) {
NSMutableString *prettyStack = [NSMutableString string];
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:@"\\b((?:seg-\\d+(?:_\\d+)?|\\d+)\\.js)"
options:NSRegularExpressionCaseInsensitive
error:NULL];
for (NSDictionary<NSString *, id> *frame in stackTrace) {
NSString *fileName = [frame[@"file"] lastPathComponent];
NSTextCheckingResult *match =
fileName != nil ? [regex firstMatchInString:fileName options:0 range:NSMakeRange(0, fileName.length)] : nil;
if (match) {
fileName = [NSString stringWithFormat:@"%@:", [fileName substringWithRange:match.range]];
} else {
fileName = @"";
}
[prettyStack
appendFormat:@"%@@%@%@:%@\n", frame[@"methodName"], fileName, frame[@"lineNumber"], frame[@"column"]];
}
return prettyStack;
}
return nil;
}
void RCTFatalException(NSException *exception)
{
_RCTLogNativeInternal(RCTLogLevelFatal, NULL, 0, @"%@: %@", exception.name, exception.reason);
RCTFatalExceptionHandler fatalExceptionHandler = RCTGetFatalExceptionHandler();
if (fatalExceptionHandler) {
fatalExceptionHandler(exception);
} else {
#if DEBUG
@try {
#endif
@throw exception;
#if DEBUG
} @catch (NSException *e) {
}
#endif
}
}
void RCTSetFatalExceptionHandler(RCTFatalExceptionHandler fatalExceptionHandler)
{
RCTCurrentFatalExceptionHandler = fatalExceptionHandler;
}
RCTFatalExceptionHandler RCTGetFatalExceptionHandler(void)
{
return RCTCurrentFatalExceptionHandler;
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTBridge.h>
@class RCTModuleData;
@protocol RCTJavaScriptExecutor;
RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
RCT_EXTERN void RCTRegisterModule(Class);
@interface RCTBridge ()
// Private designated initializer
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate
bundleURL:(NSURL *)bundleURL
moduleProvider:(RCTBridgeModuleListProvider)block
launchOptions:(NSDictionary *)launchOptions NS_DESIGNATED_INITIALIZER;
// Used for the profiler flow events between JS and native
@property (nonatomic, assign) int64_t flowID;
@property (nonatomic, assign) CFMutableDictionaryRef flowIDMap;
@property (nonatomic, strong) NSLock *flowIDMapLock;
// Used by RCTDevMenu
@property (nonatomic, copy) NSString *bridgeDescription;
+ (instancetype)currentBridge;
+ (void)setCurrentBridge:(RCTBridge *)bridge;
/**
* Bridge setup code - creates an instance of RCTBachedBridge. Exposed for
* test only
*/
- (void)setUp;
/**
* This method is used to invoke a callback that was registered in the
* JavaScript application context. Safe to call from any thread.
*/
- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args;
/**
* This property is mostly used on the main thread, but may be touched from
* a background thread if the RCTBridge happens to deallocate on a background
* thread. Therefore, we want all writes to it to be seen atomically.
*/
@property (atomic, strong) RCTBridge *batchedBridge;
/**
* The block that creates the modules' instances to be added to the bridge.
* Exposed for RCTCxxBridge
*/
@property (nonatomic, copy, readonly) RCTBridgeModuleListProvider moduleProvider;
/**
* Used by RCTDevMenu to override the `hot` param of the current bundleURL.
*/
@property (nonatomic, strong, readwrite) NSURL *bundleURL;
@end
@interface RCTBridge (RCTCxxBridge)
/**
* Used by RCTModuleData
*/
@property (nonatomic, weak, readonly) RCTBridge *parentBridge;
/**
* Used by RCTModuleData
*/
@property (nonatomic, assign, readonly) BOOL moduleSetupComplete;
/**
* Called on the child bridge to run the executor and start loading.
*/
- (void)start;
/**
* Used by RCTModuleData to register the module for frame updates after it is
* lazily initialized.
*/
- (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module withModuleData:(RCTModuleData *)moduleData;
/**
* Dispatch work to a module's queue - this is also suports the fake RCTJSThread
* queue. Exposed for the RCTProfiler
*/
- (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue;
/**
* Get the module data for a given module name. Used by UIManager to implement
* the `dispatchViewManagerCommand` method.
*/
- (RCTModuleData *)moduleDataForName:(NSString *)moduleName;
/**
* Registers additional classes with the ModuleRegistry.
*/
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)newModules;
/**
* Updates the ModuleRegistry with a pre-initialized instance.
*/
- (void)updateModuleWithInstance:(id<RCTBridgeModule>)instance;
/**
* Systrace profiler toggling methods exposed for the RCTDevMenu
*/
- (void)startProfiling;
- (void)stopProfiling:(void (^)(NSData *))callback;
/**
* Synchronously call a specific native module's method and return the result
*/
- (id)callNativeModule:(NSUInteger)moduleID method:(NSUInteger)methodID params:(NSArray *)params;
/**
* Hook exposed for RCTLog to send logs to JavaScript when not running in JSC
*/
- (void)logMessage:(NSString *)message level:(NSString *)level;
/**
* Allow super fast, one time, timers to skip the queue and be directly executed
*/
- (void)_immediatelyCallTimer:(NSNumber *)timer;
@end
@interface RCTBridge (Inspector)
@property (nonatomic, readonly, getter=isInspectable) BOOL inspectable;
@end
@interface RCTCxxBridge : RCTBridge
// TODO(cjhopman): this seems unsafe unless we require that it is only called on the main js queue.
@property (nonatomic, readonly) void *runtime;
- (instancetype)initWithParentBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
@end

297
node_modules/react-native/React/Base/RCTBridge.h generated vendored Normal file
View File

@ -0,0 +1,297 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTBridgeDelegate.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTDefines.h>
#import <React/RCTFrameUpdate.h>
#import <React/RCTInvalidating.h>
@class JSValue;
@class RCTBridge;
@class RCTEventDispatcher;
@class RCTPerformanceLogger;
/**
* This notification fires when the bridge initializes.
*/
RCT_EXTERN NSString *const RCTJavaScriptWillStartLoadingNotification;
/**
* This notification fires when the bridge starts executing the JS bundle.
*/
RCT_EXTERN NSString *const RCTJavaScriptWillStartExecutingNotification;
/**
* This notification fires when the bridge has finished loading the JS bundle.
*/
RCT_EXTERN NSString *const RCTJavaScriptDidLoadNotification;
/**
* This notification fires when the bridge failed to load the JS bundle. The
* `error` key can be used to determine the error that occurred.
*/
RCT_EXTERN NSString *const RCTJavaScriptDidFailToLoadNotification;
/**
* This notification fires each time a native module is instantiated. The
* `module` key will contain a reference to the newly-created module instance.
* Note that this notification may be fired before the module is available via
* the `[bridge moduleForClass:]` method.
*/
RCT_EXTERN NSString *const RCTDidInitializeModuleNotification;
/**
* This notification fires each time a module is setup after it is initialized. The
* `RCTDidSetupModuleNotificationModuleNameKey` key will contain a reference to the module name and
* `RCTDidSetupModuleNotificationSetupTimeKey` will contain the setup time in ms.
*/
RCT_EXTERN NSString *const RCTDidSetupModuleNotification;
/**
* Key for the module name (NSString) in the
* RCTDidSetupModuleNotification userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTDidSetupModuleNotificationModuleNameKey;
/**
* Key for the setup time (NSNumber) in the
* RCTDidSetupModuleNotification userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTDidSetupModuleNotificationSetupTimeKey;
/**
* DEPRECATED - Use RCTReloadCommand instead. This notification fires just before the bridge starts
* processing a request to reload.
*/
RCT_EXTERN NSString *const RCTBridgeWillReloadNotification;
/**
* This notification fires whenever a fast refresh happens.
*/
RCT_EXTERN NSString *const RCTBridgeFastRefreshNotification;
/**
* This notification fires just before the bridge begins downloading a script
* from the packager.
*/
RCT_EXTERN NSString *const RCTBridgeWillDownloadScriptNotification;
/**
* This notification fires just after the bridge finishes downloading a script
* from the packager.
*/
RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotification;
/**
* This notification fires right after the bridge is about to invalidate NativeModule
* instances during teardown. Handle this notification to perform additional invalidation.
*/
RCT_EXTERN NSString *const RCTBridgeWillInvalidateModulesNotification;
/**
* This notification fires right after the bridge finishes invalidating NativeModule
* instances during teardown. Handle this notification to perform additional invalidation.
*/
RCT_EXTERN NSString *const RCTBridgeDidInvalidateModulesNotification;
/**
* This notification fires right before the bridge starting invalidation process.
* Handle this notification to perform additional invalidation.
* The notification can be issued on any thread.
*/
RCT_EXTERN NSString *const RCTBridgeWillBeInvalidatedNotification;
/**
* Key for the RCTSource object in the RCTBridgeDidDownloadScriptNotification
* userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotificationSourceKey;
/**
* Key for the reload reason in the RCTBridgeWillReloadNotification userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotificationReasonKey;
/**
* Key for the bridge description (NSString_ in the
* RCTBridgeDidDownloadScriptNotification userInfo dictionary.
*/
RCT_EXTERN NSString *const RCTBridgeDidDownloadScriptNotificationBridgeDescriptionKey;
/**
* This block can be used to instantiate modules that require additional
* init parameters, or additional configuration prior to being used.
* The bridge will call this block to instantiate the modules, and will
* be responsible for invalidating/releasing them when the bridge is destroyed.
* For this reason, the block should always return new module instances, and
* module instances should not be shared between bridges.
*/
typedef NSArray<id<RCTBridgeModule>> * (^RCTBridgeModuleListProvider)(void);
/**
* This function returns the module name for a given class.
*/
RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
/**
* Experimental.
* Check/set if JSI-bound NativeModule is enabled. By default it's off.
*/
RCT_EXTERN BOOL RCTTurboModuleEnabled(void);
RCT_EXTERN void RCTEnableTurboModule(BOOL enabled);
/**
* Async batched bridge used to communicate with the JavaScript application.
*/
@interface RCTBridge : NSObject <RCTInvalidating>
/**
* Creates a new bridge with a custom RCTBridgeDelegate.
*
* All the interaction with the JavaScript context should be done using the bridge
* instance of the RCTBridgeModules. Modules will be automatically instantiated
* using the default contructor, but you can optionally pass in an array of
* pre-initialized module instances if they require additional init parameters
* or configuration.
*/
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions;
/**
* DEPRECATED: Use initWithDelegate:launchOptions: instead
*
* The designated initializer. This creates a new bridge on top of the specified
* executor. The bridge should then be used for all subsequent communication
* with the JavaScript code running in the executor. Modules will be automatically
* instantiated using the default contructor, but you can optionally pass in an
* array of pre-initialized module instances if they require additional init
* parameters or configuration.
*/
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleProvider:(RCTBridgeModuleListProvider)block
launchOptions:(NSDictionary *)launchOptions;
/**
* This method is used to call functions in the JavaScript application context.
* It is primarily intended for use by modules that require two-way communication
* with the JavaScript code. Safe to call from any thread.
*/
- (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args;
- (void)enqueueJSCall:(NSString *)module
method:(NSString *)method
args:(NSArray *)args
completion:(dispatch_block_t)completion;
/**
* This method registers the file path of an additional JS segment by its ID.
*
* @experimental
*/
- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path;
/**
* Retrieve a bridge module instance by name or class. Note that modules are
* lazily instantiated, so calling these methods for the first time with a given
* module name/class may cause the class to be synchronously instantiated,
* potentially blocking both the calling thread and main thread for a short time.
*
* Note: This method does NOT lazily load the particular module if it's not yet loaded.
*/
- (id)moduleForName:(NSString *)moduleName;
- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad;
// Note: This method lazily load the module as necessary.
- (id)moduleForClass:(Class)moduleClass;
/**
* When a NativeModule performs a lookup for a TurboModule, we need to query
* the lookupDelegate.
*/
- (void)setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate;
/**
* Convenience method for retrieving all modules conforming to a given protocol.
* Modules will be synchronously instantiated if they haven't already been,
* potentially blocking both the calling thread and main thread for a short time.
*/
- (NSArray *)modulesConformingToProtocol:(Protocol *)protocol;
/**
* Test if a module has been initialized. Use this prior to calling
* `moduleForClass:` or `moduleForName:` if you do not want to cause the module
* to be instantiated if it hasn't been already.
*/
- (BOOL)moduleIsInitialized:(Class)moduleClass;
/**
* All registered bridge module classes.
*/
@property (nonatomic, copy, readonly) NSArray<Class> *moduleClasses;
/**
* URL of the script that was loaded into the bridge.
*/
@property (nonatomic, strong, readonly) NSURL *bundleURL;
/**
* The class of the executor currently being used. Changes to this value will
* take effect after the bridge is reloaded.
*/
@property (nonatomic, strong) Class executorClass;
/**
* The delegate provided during the bridge initialization
*/
@property (nonatomic, weak, readonly) id<RCTBridgeDelegate> delegate;
/**
* The launch options that were used to initialize the bridge.
*/
@property (nonatomic, copy, readonly) NSDictionary *launchOptions;
/**
* Use this to check if the bridge is currently loading.
*/
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
/**
* Use this to check if the bridge has been invalidated.
*/
@property (nonatomic, readonly, getter=isValid) BOOL valid;
/**
* Link to the Performance Logger that logs React Native perf events.
*/
@property (nonatomic, readonly, strong) RCTPerformanceLogger *performanceLogger;
/**
* Reload the bundle and reset executor & modules. Safe to call from any thread.
*/
- (void)reload __deprecated_msg("Use RCTReloadCommand instead");
/**
* Reload the bundle and reset executor & modules. Safe to call from any thread.
*/
- (void)reloadWithReason:(NSString *)reason __deprecated_msg("Use RCTReloadCommand instead");
/**
* Handle notifications for a fast refresh. Safe to call from any thread.
*/
- (void)onFastRefresh;
/**
* Inform the bridge, and anything subscribing to it, that it should reload.
*/
- (void)requestReload __deprecated_msg("Use RCTReloadCommand instead");
/**
* Says whether bridge has started receiving calls from javascript.
*/
- (BOOL)isBatchActive;
@end

391
node_modules/react-native/React/Base/RCTBridge.m generated vendored Normal file
View File

@ -0,0 +1,391 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBridge.h"
#import "RCTBridge+Private.h"
#import <objc/runtime.h>
#import "RCTConvert.h"
#import "RCTEventDispatcher.h"
#if RCT_ENABLE_INSPECTOR
#import "RCTInspectorDevServerHelper.h"
#endif
#import "RCTLog.h"
#import "RCTModuleData.h"
#import "RCTPerformanceLogger.h"
#import "RCTProfile.h"
#import "RCTReloadCommand.h"
#import "RCTUtils.h"
NSString *const RCTJavaScriptWillStartLoadingNotification = @"RCTJavaScriptWillStartLoadingNotification";
NSString *const RCTJavaScriptWillStartExecutingNotification = @"RCTJavaScriptWillStartExecutingNotification";
NSString *const RCTJavaScriptDidLoadNotification = @"RCTJavaScriptDidLoadNotification";
NSString *const RCTJavaScriptDidFailToLoadNotification = @"RCTJavaScriptDidFailToLoadNotification";
NSString *const RCTDidInitializeModuleNotification = @"RCTDidInitializeModuleNotification";
NSString *const RCTDidSetupModuleNotification = @"RCTDidSetupModuleNotification";
NSString *const RCTDidSetupModuleNotificationModuleNameKey = @"moduleName";
NSString *const RCTDidSetupModuleNotificationSetupTimeKey = @"setupTime";
NSString *const RCTBridgeWillReloadNotification = @"RCTBridgeWillReloadNotification";
NSString *const RCTBridgeFastRefreshNotification = @"RCTBridgeFastRefreshNotification";
NSString *const RCTBridgeWillDownloadScriptNotification = @"RCTBridgeWillDownloadScriptNotification";
NSString *const RCTBridgeDidDownloadScriptNotification = @"RCTBridgeDidDownloadScriptNotification";
NSString *const RCTBridgeWillInvalidateModulesNotification = @"RCTBridgeWillInvalidateModulesNotification";
NSString *const RCTBridgeDidInvalidateModulesNotification = @"RCTBridgeDidInvalidateModulesNotification";
NSString *const RCTBridgeWillBeInvalidatedNotification = @"RCTBridgeWillBeInvalidatedNotification";
NSString *const RCTBridgeDidDownloadScriptNotificationSourceKey = @"source";
NSString *const RCTBridgeDidDownloadScriptNotificationBridgeDescriptionKey = @"bridgeDescription";
static NSMutableArray<Class> *RCTModuleClasses;
static dispatch_queue_t RCTModuleClassesSyncQueue;
NSArray<Class> *RCTGetModuleClasses(void)
{
__block NSArray<Class> *result;
dispatch_sync(RCTModuleClassesSyncQueue, ^{
result = [RCTModuleClasses copy];
});
return result;
}
/**
* Register the given class as a bridge module. All modules must be registered
* prior to the first bridge initialization.
*/
void RCTRegisterModule(Class);
void RCTRegisterModule(Class moduleClass)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
RCTModuleClasses = [NSMutableArray new];
RCTModuleClassesSyncQueue =
dispatch_queue_create("com.facebook.react.ModuleClassesSyncQueue", DISPATCH_QUEUE_CONCURRENT);
});
RCTAssert(
[moduleClass conformsToProtocol:@protocol(RCTBridgeModule)],
@"%@ does not conform to the RCTBridgeModule protocol",
moduleClass);
// Register module
dispatch_barrier_async(RCTModuleClassesSyncQueue, ^{
[RCTModuleClasses addObject:moduleClass];
});
}
/**
* This function returns the module name for a given class.
*/
NSString *RCTBridgeModuleNameForClass(Class cls)
{
#if RCT_DEBUG
RCTAssert(
[cls conformsToProtocol:@protocol(RCTBridgeModule)],
@"Bridge module `%@` does not conform to RCTBridgeModule",
cls);
#endif
NSString *name = [cls moduleName];
if (name.length == 0) {
name = NSStringFromClass(cls);
}
return RCTDropReactPrefixes(name);
}
static BOOL turboModuleEnabled = NO;
BOOL RCTTurboModuleEnabled(void)
{
#if RCT_DEBUG
// TODO(T53341772): Allow TurboModule for test environment. Right now this breaks RNTester tests if enabled.
if (RCTRunningInTestEnvironment()) {
return NO;
}
#endif
return turboModuleEnabled;
}
void RCTEnableTurboModule(BOOL enabled)
{
turboModuleEnabled = enabled;
}
@interface RCTBridge () <RCTReloadListener>
@end
@implementation RCTBridge {
NSURL *_delegateBundleURL;
}
dispatch_queue_t RCTJSThread;
+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Set up JS thread
RCTJSThread = (id)kCFNull;
});
}
static RCTBridge *RCTCurrentBridgeInstance = nil;
/**
* The last current active bridge instance. This is set automatically whenever
* the bridge is accessed. It can be useful for static functions or singletons
* that need to access the bridge for purposes such as logging, but should not
* be relied upon to return any particular instance, due to race conditions.
*/
+ (instancetype)currentBridge
{
return RCTCurrentBridgeInstance;
}
+ (void)setCurrentBridge:(RCTBridge *)currentBridge
{
RCTCurrentBridgeInstance = currentBridge;
}
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
{
return [self initWithDelegate:delegate bundleURL:nil moduleProvider:nil launchOptions:launchOptions];
}
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleProvider:(RCTBridgeModuleListProvider)block
launchOptions:(NSDictionary *)launchOptions
{
return [self initWithDelegate:nil bundleURL:bundleURL moduleProvider:block launchOptions:launchOptions];
}
- (instancetype)initWithDelegate:(id<RCTBridgeDelegate>)delegate
bundleURL:(NSURL *)bundleURL
moduleProvider:(RCTBridgeModuleListProvider)block
launchOptions:(NSDictionary *)launchOptions
{
if (self = [super init]) {
_delegate = delegate;
_bundleURL = bundleURL;
_moduleProvider = block;
_launchOptions = [launchOptions copy];
[self setUp];
}
return self;
}
RCT_NOT_IMPLEMENTED(-(instancetype)init)
- (void)dealloc
{
/**
* This runs only on the main thread, but crashes the subclass
* RCTAssertMainQueue();
*/
[self invalidate];
}
- (void)setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate
{
[self.batchedBridge setRCTTurboModuleLookupDelegate:turboModuleLookupDelegate];
}
- (void)didReceiveReloadCommand
{
[self reloadWithReason:@"Command"];
}
- (NSArray<Class> *)moduleClasses
{
return self.batchedBridge.moduleClasses;
}
- (id)moduleForName:(NSString *)moduleName
{
return [self.batchedBridge moduleForName:moduleName];
}
- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad
{
return [self.batchedBridge moduleForName:moduleName lazilyLoadIfNecessary:lazilyLoad];
}
- (id)moduleForClass:(Class)moduleClass
{
id module = [self.batchedBridge moduleForClass:moduleClass];
if (!module) {
module = [self moduleForName:RCTBridgeModuleNameForClass(moduleClass)];
}
return module;
}
- (NSArray *)modulesConformingToProtocol:(Protocol *)protocol
{
NSMutableArray *modules = [NSMutableArray new];
for (Class moduleClass in [self.moduleClasses copy]) {
if ([moduleClass conformsToProtocol:protocol]) {
id module = [self moduleForClass:moduleClass];
if (module) {
[modules addObject:module];
}
}
}
return [modules copy];
}
- (BOOL)moduleIsInitialized:(Class)moduleClass
{
return [self.batchedBridge moduleIsInitialized:moduleClass];
}
/**
* DEPRECATED - please use RCTReloadCommand.
*/
- (void)reload
{
[self reloadWithReason:@"Unknown from bridge"];
}
/**
* DEPRECATED - please use RCTReloadCommand.
*/
- (void)reloadWithReason:(NSString *)reason
{
#if RCT_ENABLE_INSPECTOR
// Disable debugger to resume the JsVM & avoid thread locks while reloading
[RCTInspectorDevServerHelper disableDebugger];
#endif
[[NSNotificationCenter defaultCenter] postNotificationName:RCTBridgeWillReloadNotification object:self userInfo:nil];
/**
* Any thread
*/
dispatch_async(dispatch_get_main_queue(), ^{
// WARNING: Invalidation is async, so it may not finish before re-setting up the bridge,
// causing some issues. TODO: revisit this post-Fabric/TurboModule.
[self invalidate];
// Reload is a special case, do not preserve launchOptions and treat reload as a fresh start
self->_launchOptions = nil;
[self setUp];
});
}
- (void)onFastRefresh
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTBridgeFastRefreshNotification object:self];
}
/**
* DEPRECATED - please use RCTReloadCommand.
*/
- (void)requestReload
{
[self reloadWithReason:@"Requested from bridge"];
}
- (Class)bridgeClass
{
return [RCTCxxBridge class];
}
- (void)setUp
{
RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBridge setUp]", nil);
_performanceLogger = [RCTPerformanceLogger new];
[_performanceLogger markStartForTag:RCTPLBridgeStartup];
[_performanceLogger markStartForTag:RCTPLTTI];
Class bridgeClass = self.bridgeClass;
// Only update bundleURL from delegate if delegate bundleURL has changed
NSURL *previousDelegateURL = _delegateBundleURL;
_delegateBundleURL = [self.delegate sourceURLForBridge:self];
if (_delegateBundleURL && ![_delegateBundleURL isEqual:previousDelegateURL]) {
_bundleURL = _delegateBundleURL;
}
// Sanitize the bundle URL
_bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString];
RCTExecuteOnMainQueue(^{
RCTRegisterReloadCommandListener(self);
RCTReloadCommandSetBundleURL(self->_bundleURL);
});
self.batchedBridge = [[bridgeClass alloc] initWithParentBridge:self];
[self.batchedBridge start];
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
- (BOOL)isLoading
{
return self.batchedBridge.loading;
}
- (BOOL)isValid
{
return self.batchedBridge.valid;
}
- (BOOL)isBatchActive
{
return [_batchedBridge isBatchActive];
}
- (void)invalidate
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTBridgeWillBeInvalidatedNotification object:self];
RCTBridge *batchedBridge = self.batchedBridge;
self.batchedBridge = nil;
if (batchedBridge) {
RCTExecuteOnMainQueue(^{
[batchedBridge invalidate];
});
}
}
- (void)updateModuleWithInstance:(id<RCTBridgeModule>)instance
{
[self.batchedBridge updateModuleWithInstance:instance];
}
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
{
[self.batchedBridge registerAdditionalModuleClasses:modules];
}
- (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
{
NSArray<NSString *> *ids = [moduleDotMethod componentsSeparatedByString:@"."];
NSString *module = ids[0];
NSString *method = ids[1];
[self enqueueJSCall:module method:method args:args completion:NULL];
}
- (void)enqueueJSCall:(NSString *)module
method:(NSString *)method
args:(NSArray *)args
completion:(dispatch_block_t)completion
{
[self.batchedBridge enqueueJSCall:module method:method args:args completion:completion];
}
- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args
{
[self.batchedBridge enqueueCallback:cbID args:args];
}
- (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
{
[self.batchedBridge registerSegmentWithId:segmentId path:path];
}
@end

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTJavaScriptLoader.h>
@class RCTBridge;
@protocol RCTBridgeModule;
@protocol RCTBridgeDelegate <NSObject>
/**
* The location of the JavaScript source file. When running from the packager
* this should be an absolute URL, e.g. `http://localhost:8081/index.ios.bundle`.
* When running from a locally bundled JS file, this should be a `file://` url
* pointing to a path inside the app resources, e.g. `file://.../main.jsbundle`.
*/
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge;
@optional
/**
* The bridge initializes any registered RCTBridgeModules automatically, however
* if you wish to instantiate your own module instances, you can return them
* from this method.
*
* Note: You should always return a new instance for each call, rather than
* returning the same instance each time the bridge is reloaded. Module instances
* should not be shared between bridges, and this may cause unexpected behavior.
*
* It is also possible to override standard modules with your own implementations
* by returning a class with the same `moduleName` from this method, but this is
* not recommended in most cases - if the module methods and behavior do not
* match exactly, it may lead to bugs or crashes.
*/
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge;
/**
* Configure whether the JSCExecutor created should use the system JSC API or
* alternative hooks provided. When returning YES from this method, you must have
* previously called facebook::react::setCustomJSCWrapper.
*
* @experimental
*/
- (BOOL)shouldBridgeUseCustomJSC:(RCTBridge *)bridge;
/**
* The bridge will call this method when a module been called from JS
* cannot be found among registered modules.
* It should return YES if the module with name 'moduleName' was registered
* in the implementation, and the system must attempt to look for it again among registered.
* If the module was not registered, return NO to prevent further searches.
*/
- (BOOL)bridge:(RCTBridge *)bridge didNotFindModule:(NSString *)moduleName;
/**
* The bridge will automatically attempt to load the JS source code from the
* location specified by the `sourceURLForBridge:` method, however, if you want
* to handle loading the JS yourself, you can do so by implementing this method.
*/
- (void)loadSourceForBridge:(RCTBridge *)bridge
onProgress:(RCTSourceLoadProgressBlock)onProgress
onComplete:(RCTSourceLoadBlock)loadCallback;
/**
* Similar to loadSourceForBridge:onProgress:onComplete: but without progress
* reporting.
*/
- (void)loadSourceForBridge:(RCTBridge *)bridge withBlock:(RCTSourceLoadBlock)loadCallback;
/**
* Retrieve the list of lazy-native-modules names for the given bridge.
*/
- (NSDictionary<NSString *, Class> *)extraLazyModuleClassesForBridge:(RCTBridge *)bridge;
@end

37
node_modules/react-native/React/Base/RCTBridgeMethod.h generated vendored Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@class RCTBridge;
typedef NS_ENUM(NSUInteger, RCTFunctionType) {
RCTFunctionTypeNormal,
RCTFunctionTypePromise,
RCTFunctionTypeSync,
};
static inline const char *RCTFunctionDescriptorFromType(RCTFunctionType type)
{
switch (type) {
case RCTFunctionTypeNormal:
return "async";
case RCTFunctionTypePromise:
return "promise";
case RCTFunctionTypeSync:
return "sync";
}
};
@protocol RCTBridgeMethod <NSObject>
@property (nonatomic, readonly) const char *JSMethodName;
@property (nonatomic, readonly) RCTFunctionType functionType;
- (id)invokeWithBridge:(RCTBridge *)bridge module:(id)module arguments:(NSArray *)arguments;
@end

371
node_modules/react-native/React/Base/RCTBridgeModule.h generated vendored Normal file
View File

@ -0,0 +1,371 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTDefines.h>
@class RCTBridge;
@protocol RCTBridgeMethod;
/**
* The type of a block that is capable of sending a response to a bridged
* operation. Use this for returning callback methods to JS.
*/
typedef void (^RCTResponseSenderBlock)(NSArray *response);
/**
* The type of a block that is capable of sending an error response to a
* bridged operation. Use this for returning error information to JS.
*/
typedef void (^RCTResponseErrorBlock)(NSError *error);
/**
* Block that bridge modules use to resolve the JS promise waiting for a result.
* Nil results are supported and are converted to JS's undefined value.
*/
typedef void (^RCTPromiseResolveBlock)(id result);
/**
* Block that bridge modules use to reject the JS promise waiting for a result.
* The error may be nil but it is preferable to pass an NSError object for more
* precise error messages.
*/
typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);
/**
* This constant can be returned from +methodQueue to force module
* methods to be called on the JavaScript thread. This can have serious
* implications for performance, so only use this if you're sure it's what
* you need.
*
* NOTE: RCTJSThread is not a real libdispatch queue
*/
RCT_EXTERN dispatch_queue_t RCTJSThread;
RCT_EXTERN_C_BEGIN
typedef struct RCTMethodInfo {
const char *const jsName;
const char *const objcName;
const BOOL isSync;
} RCTMethodInfo;
RCT_EXTERN_C_END
/**
* Provides the interface needed to register a bridge module.
*/
@protocol RCTBridgeModule <NSObject>
/**
* Place this macro in your class implementation to automatically register
* your module with the bridge when it loads. The optional js_name argument
* will be used as the JS module name. If omitted, the JS module name will
* match the Objective-C class name.
*/
#define RCT_EXPORT_MODULE(js_name) \
RCT_EXTERN void RCTRegisterModule(Class); \
+(NSString *)moduleName \
{ \
return @ #js_name; \
} \
+(void)load \
{ \
RCTRegisterModule(self); \
}
/**
* Same as RCT_EXPORT_MODULE, but uses __attribute__((constructor)) for module
* registration. Useful for registering swift classes that forbids use of load
* Used in RCT_EXTERN_REMAP_MODULE
*/
#define RCT_EXPORT_MODULE_NO_LOAD(js_name, objc_name) \
RCT_EXTERN void RCTRegisterModule(Class); \
+(NSString *)moduleName \
{ \
return @ #js_name; \
} \
__attribute__((constructor)) static void RCT_CONCAT(initialize_, objc_name)() \
{ \
RCTRegisterModule([objc_name class]); \
}
/**
* To improve startup performance users may want to generate their module lists
* at build time and hook the delegate to merge with the runtime list. This
* macro takes the place of the above for those cases by omitting the +load
* generation.
*
*/
#define RCT_EXPORT_PRE_REGISTERED_MODULE(js_name) \
+(NSString *)moduleName \
{ \
return @ #js_name; \
}
// Implemented by RCT_EXPORT_MODULE
+ (NSString *)moduleName;
@optional
/**
* A reference to the RCTBridge. Useful for modules that require access
* to bridge features, such as sending events or making JS calls. This
* will be set automatically by the bridge when it initializes the module.
* To implement this in your module, just add `@synthesize bridge = _bridge;`
* If using Swift, add `@objc var bridge: RCTBridge!` to your module.
*/
@property (nonatomic, weak, readonly) RCTBridge *bridge;
/**
* The queue that will be used to call all exported methods. If omitted, this
* will call on a default background queue, which is avoids blocking the main
* thread.
*
* If the methods in your module need to interact with UIKit methods, they will
* probably need to call those on the main thread, as most of UIKit is main-
* thread-only. You can tell React Native to call your module methods on the
* main thread by returning a reference to the main queue, like this:
*
* - (dispatch_queue_t)methodQueue
* {
* return dispatch_get_main_queue();
* }
*
* If you don't want to specify the queue yourself, but you need to use it
* inside your class (e.g. if you have internal methods that need to dispatch
* onto that queue), you can just add `@synthesize methodQueue = _methodQueue;`
* and the bridge will populate the methodQueue property for you automatically
* when it initializes the module.
*/
@property (nonatomic, strong, readonly) dispatch_queue_t methodQueue;
/**
* Wrap the parameter line of your method implementation with this macro to
* expose it to JS. By default the exposed method will match the first part of
* the Objective-C method selector name (up to the first colon). Use
* RCT_REMAP_METHOD to specify the JS name of the method.
*
* For example, in ModuleName.m:
*
* - (void)doSomething:(NSString *)aString withA:(NSInteger)a andB:(NSInteger)b
* { ... }
*
* becomes
*
* RCT_EXPORT_METHOD(doSomething:(NSString *)aString
* withA:(NSInteger)a
* andB:(NSInteger)b)
* { ... }
*
* and is exposed to JavaScript as `NativeModules.ModuleName.doSomething`.
*
* ## Promises
*
* Bridge modules can also define methods that are exported to JavaScript as
* methods that return a Promise, and are compatible with JS async functions.
*
* Declare the last two parameters of your native method to be a resolver block
* and a rejecter block. The resolver block must precede the rejecter block.
*
* For example:
*
* RCT_EXPORT_METHOD(doSomethingAsync:(NSString *)aString
* resolver:(RCTPromiseResolveBlock)resolve
* rejecter:(RCTPromiseRejectBlock)reject
* { ... }
*
* Calling `NativeModules.ModuleName.doSomethingAsync(aString)` from
* JavaScript will return a promise that is resolved or rejected when your
* native method implementation calls the respective block.
*
*/
#define RCT_EXPORT_METHOD(method) RCT_REMAP_METHOD(, method)
/**
* Same as RCT_EXPORT_METHOD but the method is called from JS
* synchronously **on the JS thread**, possibly returning a result.
*
* WARNING: in the vast majority of cases, you should use RCT_EXPORT_METHOD which
* allows your native module methods to be called asynchronously: calling
* methods synchronously can have strong performance penalties and introduce
* threading-related bugs to your native modules.
*
* The return type must be of object type (id) and should be serializable
* to JSON. This means that the hook can only return nil or JSON values
* (e.g. NSNumber, NSString, NSArray, NSDictionary).
*
* Calling these methods when running under the websocket executor
* is currently not supported.
*/
#define RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(method) RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(id, method)
#define RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(returnType, method) \
RCT_REMAP_BLOCKING_SYNCHRONOUS_METHOD(, returnType, method)
/**
* Similar to RCT_EXPORT_METHOD but lets you set the JS name of the exported
* method. Example usage:
*
* RCT_REMAP_METHOD(executeQueryWithParameters,
* executeQuery:(NSString *)query parameters:(NSDictionary *)parameters)
* { ... }
*/
#define RCT_REMAP_METHOD(js_name, method) \
_RCT_EXTERN_REMAP_METHOD(js_name, method, NO) \
-(void)method RCT_DYNAMIC;
/**
* Similar to RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD but lets you set
* the JS name of the exported method. Example usage:
*
* RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(executeQueryWithParameters,
* executeQuery:(NSString *)query parameters:(NSDictionary *)parameters)
* { ... }
*/
#define RCT_REMAP_BLOCKING_SYNCHRONOUS_METHOD(js_name, returnType, method) \
_RCT_EXTERN_REMAP_METHOD(js_name, method, YES) \
-(returnType)method RCT_DYNAMIC;
/**
* Use this macro in a private Objective-C implementation file to automatically
* register an external module with the bridge when it loads. This allows you to
* register Swift or private Objective-C classes with the bridge.
*
* For example if one wanted to export a Swift class to the bridge:
*
* MyModule.swift:
*
* @objc(MyModule) class MyModule: NSObject {
*
* @objc func doSomething(string: String! withFoo a: Int, bar b: Int) { ... }
*
* }
*
* MyModuleExport.m:
*
* #import <React/RCTBridgeModule.h>
*
* @interface RCT_EXTERN_MODULE(MyModule, NSObject)
*
* RCT_EXTERN_METHOD(doSomething:(NSString *)string withFoo:(NSInteger)a bar:(NSInteger)b)
*
* @end
*
* This will now expose MyModule and the method to JavaScript via
* `NativeModules.MyModule.doSomething`
*/
#define RCT_EXTERN_MODULE(objc_name, objc_supername) RCT_EXTERN_REMAP_MODULE(, objc_name, objc_supername)
/**
* Like RCT_EXTERN_MODULE, but allows setting a custom JavaScript name.
*/
#define RCT_EXTERN_REMAP_MODULE(js_name, objc_name, objc_supername) \
objc_name: \
objc_supername @ \
end @interface objc_name(RCTExternModule)<RCTBridgeModule> \
@end \
@implementation objc_name (RCTExternModule) \
RCT_EXPORT_MODULE_NO_LOAD(js_name, objc_name)
/**
* Use this macro in accordance with RCT_EXTERN_MODULE to export methods
* of an external module.
*/
#define RCT_EXTERN_METHOD(method) _RCT_EXTERN_REMAP_METHOD(, method, NO)
/**
* Use this macro in accordance with RCT_EXTERN_MODULE to export methods
* of an external module that should be invoked synchronously.
*/
#define RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(method) _RCT_EXTERN_REMAP_METHOD(, method, YES)
/**
* Like RCT_EXTERN_REMAP_METHOD, but allows setting a custom JavaScript name
* and also whether this method is synchronous.
*/
#define _RCT_EXTERN_REMAP_METHOD(js_name, method, is_blocking_synchronous_method) \
+(const RCTMethodInfo *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) \
{ \
static RCTMethodInfo config = {#js_name, #method, is_blocking_synchronous_method}; \
return &config; \
}
/**
* Most modules can be used from any thread. All of the modules exported non-sync method will be called on its
* methodQueue, and the module will be constructed lazily when its first invoked. Some modules have main need to access
* information that's main queue only (e.g. most UIKit classes). Since we don't want to dispatch synchronously to the
* main thread to this safely, we construct these modules and export their constants ahead-of-time.
*
* Note that when set to false, the module constructor will be called from any thread.
*
* This requirement is currently inferred by checking if the module has a custom initializer or if there's exported
* constants. In the future, we'll stop automatically inferring this and instead only rely on this method.
*/
+ (BOOL)requiresMainQueueSetup;
/**
* Injects methods into JS. Entries in this array are used in addition to any
* methods defined using the macros above. This method is called only once,
* before registration.
*/
- (NSArray<id<RCTBridgeMethod>> *)methodsToExport;
/**
* Injects constants into JS. These constants are made accessible via NativeModules.ModuleName.X. It is only called once
* for the lifetime of the bridge, so it is not suitable for returning dynamic values, but may be used for long-lived
* values such as session keys, that are regenerated only as part of a reload of the entire React application.
*
* If you implement this method and do not implement `requiresMainQueueSetup`, you will trigger deprecated logic
* that eagerly initializes your module on bridge startup. In the future, this behaviour will be changed to default
* to initializing lazily, and even modules with constants will be initialized lazily.
*/
- (NSDictionary *)constantsToExport;
/**
* Notifies the module that a batch of JS method invocations has just completed.
*/
- (void)batchDidComplete;
/**
* Notifies the module that the active batch of JS method invocations has been
* partially flushed.
*
* This occurs before -batchDidComplete, and more frequently.
*/
- (void)partialBatchDidFlush;
@end
/**
* A protocol that allows TurboModules to do lookup on other TurboModules.
* Calling these methods may cause a module to be synchronously instantiated.
*/
@protocol RCTTurboModuleLookupDelegate <NSObject>
- (id)moduleForName:(const char *)moduleName;
/**
* Rationale:
* When TurboModules lookup other modules by name, we first check the TurboModule
* registry to see if a TurboModule exists with the respective name. In this case,
* we don't want a RedBox to be raised if the TurboModule isn't found.
*
* This method is deprecated and will be deleted after the migration from
* TurboModules to TurboModules is complete.
*/
- (id)moduleForName:(const char *)moduleName warnOnLookupFailure:(BOOL)warnOnLookupFailure;
- (BOOL)moduleIsInitialized:(const char *)moduleName;
@end
/**
* Experimental.
* A protocol to declare that a class supports TurboModule.
* This may be removed in the future.
* See RCTTurboModule.h for actual signature.
*/
@protocol RCTTurboModule;

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#if defined(__cplusplus)
extern "C" {
#endif
extern NSString *const RCTBundleURLProviderUpdatedNotification;
extern const NSUInteger kRCTBundleURLProviderDefaultPort;
#if defined(__cplusplus)
}
#endif
@interface RCTBundleURLProvider : NSObject
/**
* Set default settings on NSUserDefaults.
*/
- (void)setDefaults;
/**
* Reset every settings to default.
*/
- (void)resetToDefaults;
/**
* Return the server host. If its a development build and there's no jsLocation defined,
* it will return the server host IP address
*/
- (NSString *)packagerServerHost;
#if RCT_DEV
- (BOOL)isPackagerRunning:(NSString *)host;
#endif
/**
* Returns the jsBundleURL for a given bundle entrypoint and
* the fallback offline JS bundle if the packager is not running.
*/
- (NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot fallbackURLProvider:(NSURL * (^)(void))fallbackURLProvider;
/**
* Returns the jsBundleURL for a given bundle entrypoint and
* the fallback offline JS bundle if the packager is not running.
* if resourceName or extension are nil, "main" and "jsbundle" will be
* used, respectively.
*/
- (NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot
fallbackResource:(NSString *)resourceName
fallbackExtension:(NSString *)extension;
/**
* Returns the jsBundleURL for a given bundle entrypoint and
* the fallback offline JS bundle if the packager is not running.
*/
- (NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot fallbackResource:(NSString *)resourceName;
/**
* Returns the jsBundleURL for a given bundle entrypoint and
* the fallback offline JS bundle. If resourceName or extension
* are nil, "main" and "jsbundle" will be used, respectively.
*/
- (NSURL *)jsBundleURLForFallbackResource:(NSString *)resourceName fallbackExtension:(NSString *)extension;
/**
* Returns the resourceURL for a given bundle entrypoint and
* the fallback offline resource file if the packager is not running.
*/
- (NSURL *)resourceURLForResourceRoot:(NSString *)root
resourceName:(NSString *)name
resourceExtension:(NSString *)extension
offlineBundle:(NSBundle *)offlineBundle;
/**
* The IP address or hostname of the packager.
*/
@property (nonatomic, copy) NSString *jsLocation;
@property (nonatomic, assign) BOOL enableLiveReload;
@property (nonatomic, assign) BOOL enableMinification;
@property (nonatomic, assign) BOOL enableDev;
+ (instancetype)sharedSettings;
/**
Given a hostname for the packager and a bundle root, returns the URL to the js bundle. Generally you should use the
instance method -jsBundleURLForBundleRoot:fallbackResource: which includes logic to guess if the packager is running
and fall back to a pre-packaged bundle if it is not.
*/
+ (NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot
packagerHost:(NSString *)packagerHost
enableDev:(BOOL)enableDev
enableMinification:(BOOL)enableMinification;
/**
* Given a hostname for the packager and a resource path (including "/"), return the URL to the resource.
* In general, please use the instance method to decide if the packager is running and fallback to the pre-packaged
* resource if it is not: -resourceURLForResourceRoot:resourceName:resourceExtension:offlineBundle:
*/
+ (NSURL *)resourceURLForResourcePath:(NSString *)path packagerHost:(NSString *)packagerHost query:(NSString *)query;
@end

View File

@ -0,0 +1,261 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBundleURLProvider.h"
#import "RCTConvert.h"
#import "RCTDefines.h"
NSString *const RCTBundleURLProviderUpdatedNotification = @"RCTBundleURLProviderUpdatedNotification";
const NSUInteger kRCTBundleURLProviderDefaultPort = RCT_METRO_PORT;
static NSString *const kRCTJsLocationKey = @"RCT_jsLocation";
// This option is no longer exposed in the dev menu UI.
// It was renamed in D15958697 so it doesn't get stuck with no way to turn it off:
static NSString *const kRCTEnableLiveReloadKey = @"RCT_enableLiveReload_LEGACY";
static NSString *const kRCTEnableDevKey = @"RCT_enableDev";
static NSString *const kRCTEnableMinificationKey = @"RCT_enableMinification";
@implementation RCTBundleURLProvider
- (instancetype)init
{
self = [super init];
if (self) {
[self setDefaults];
}
return self;
}
- (NSDictionary *)defaults
{
return @{
kRCTEnableLiveReloadKey : @NO,
kRCTEnableDevKey : @YES,
kRCTEnableMinificationKey : @NO,
};
}
- (void)settingsUpdated
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTBundleURLProviderUpdatedNotification object:self];
}
- (void)setDefaults
{
[[NSUserDefaults standardUserDefaults] registerDefaults:[self defaults]];
}
- (void)resetToDefaults
{
for (NSString *key in [[self defaults] allKeys]) {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
}
[self setDefaults];
[self settingsUpdated];
}
static NSURL *serverRootWithHostPort(NSString *hostPort)
{
if ([hostPort rangeOfString:@":"].location != NSNotFound) {
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/", hostPort]];
}
return [NSURL
URLWithString:[NSString
stringWithFormat:@"http://%@:%lu/", hostPort, (unsigned long)kRCTBundleURLProviderDefaultPort]];
}
#if RCT_DEV
- (BOOL)isPackagerRunning:(NSString *)host
{
NSURL *url = [serverRootWithHostPort(host) URLByAppendingPathComponent:@"status"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
__block NSURLResponse *response;
__block NSData *data;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[[session dataTaskWithRequest:request
completionHandler:^(NSData *d, NSURLResponse *res, __unused NSError *err) {
data = d;
response = res;
dispatch_semaphore_signal(semaphore);
}] resume];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSString *status = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return [status isEqualToString:@"packager-status:running"];
}
- (NSString *)guessPackagerHost
{
static NSString *ipGuess;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *ipPath = [[NSBundle mainBundle] pathForResource:@"ip" ofType:@"txt"];
ipGuess =
[[NSString stringWithContentsOfFile:ipPath encoding:NSUTF8StringEncoding
error:nil] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
});
NSString *host = ipGuess ?: @"localhost";
if ([self isPackagerRunning:host]) {
return host;
}
return nil;
}
#endif
- (NSString *)packagerServerHost
{
NSString *location = [self jsLocation];
if (location != nil) {
return location;
}
#if RCT_DEV
NSString *host = [self guessPackagerHost];
if (host) {
return host;
}
#endif
return nil;
}
- (NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot fallbackURLProvider:(NSURL * (^)(void))fallbackURLProvider
{
NSString *packagerServerHost = [self packagerServerHost];
if (!packagerServerHost) {
return fallbackURLProvider();
} else {
return [RCTBundleURLProvider jsBundleURLForBundleRoot:bundleRoot
packagerHost:packagerServerHost
enableDev:[self enableDev]
enableMinification:[self enableMinification]];
}
}
- (NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot
fallbackResource:(NSString *)resourceName
fallbackExtension:(NSString *)extension
{
return [self jsBundleURLForBundleRoot:bundleRoot
fallbackURLProvider:^NSURL * {
return [self jsBundleURLForFallbackResource:resourceName fallbackExtension:extension];
}];
}
- (NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot fallbackResource:(NSString *)resourceName
{
return [self jsBundleURLForBundleRoot:bundleRoot fallbackResource:resourceName fallbackExtension:nil];
}
- (NSURL *)jsBundleURLForFallbackResource:(NSString *)resourceName fallbackExtension:(NSString *)extension
{
resourceName = resourceName ?: @"main";
extension = extension ?: @"jsbundle";
return [[NSBundle mainBundle] URLForResource:resourceName withExtension:extension];
}
- (NSURL *)resourceURLForResourceRoot:(NSString *)root
resourceName:(NSString *)name
resourceExtension:(NSString *)extension
offlineBundle:(NSBundle *)offlineBundle
{
NSString *packagerServerHost = [self packagerServerHost];
if (!packagerServerHost) {
// Serve offline bundle (local file)
NSBundle *bundle = offlineBundle ?: [NSBundle mainBundle];
return [bundle URLForResource:name withExtension:extension];
}
NSString *path = [NSString stringWithFormat:@"/%@/%@.%@", root, name, extension];
return [[self class] resourceURLForResourcePath:path packagerHost:packagerServerHost query:nil];
}
+ (NSURL *)jsBundleURLForBundleRoot:(NSString *)bundleRoot
packagerHost:(NSString *)packagerHost
enableDev:(BOOL)enableDev
enableMinification:(BOOL)enableMinification
{
NSString *path = [NSString stringWithFormat:@"/%@.bundle", bundleRoot];
// When we support only iOS 8 and above, use queryItems for a better API.
NSString *query = [NSString stringWithFormat:@"platform=ios&dev=%@&minify=%@",
enableDev ? @"true" : @"false",
enableMinification ? @"true" : @"false"];
return [[self class] resourceURLForResourcePath:path packagerHost:packagerHost query:query];
}
+ (NSURL *)resourceURLForResourcePath:(NSString *)path packagerHost:(NSString *)packagerHost query:(NSString *)query
{
NSURLComponents *components = [NSURLComponents componentsWithURL:serverRootWithHostPort(packagerHost)
resolvingAgainstBaseURL:NO];
components.path = path;
if (query != nil) {
components.query = query;
}
return components.URL;
}
- (void)updateValue:(id)object forKey:(NSString *)key
{
[[NSUserDefaults standardUserDefaults] setObject:object forKey:key];
[[NSUserDefaults standardUserDefaults] synchronize];
[self settingsUpdated];
}
- (BOOL)enableDev
{
return [[NSUserDefaults standardUserDefaults] boolForKey:kRCTEnableDevKey];
}
- (BOOL)enableLiveReload
{
return [[NSUserDefaults standardUserDefaults] boolForKey:kRCTEnableLiveReloadKey];
}
- (BOOL)enableMinification
{
return [[NSUserDefaults standardUserDefaults] boolForKey:kRCTEnableMinificationKey];
}
- (NSString *)jsLocation
{
return [[NSUserDefaults standardUserDefaults] stringForKey:kRCTJsLocationKey];
}
- (void)setEnableDev:(BOOL)enableDev
{
[self updateValue:@(enableDev) forKey:kRCTEnableDevKey];
}
- (void)setEnableLiveReload:(BOOL)enableLiveReload
{
[self updateValue:@(enableLiveReload) forKey:kRCTEnableLiveReloadKey];
}
- (void)setJsLocation:(NSString *)jsLocation
{
[self updateValue:jsLocation forKey:kRCTJsLocationKey];
}
- (void)setEnableMinification:(BOOL)enableMinification
{
[self updateValue:@(enableMinification) forKey:kRCTEnableMinificationKey];
}
+ (instancetype)sharedSettings
{
static RCTBundleURLProvider *sharedInstance;
static dispatch_once_t once_token;
dispatch_once(&once_token, ^{
sharedInstance = [RCTBundleURLProvider new];
});
return sharedInstance;
}
@end

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTEventDispatcher.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Generic untyped event for Components. Used internally by RCTDirectEventBlock and
* RCTBubblingEventBlock, for other use cases prefer using a class that implements
* RCTEvent to have a type safe way to initialize it.
*/
@interface RCTComponentEvent : NSObject <RCTEvent>
- (instancetype)initWithName:(NSString *)name viewTag:(NSNumber *)viewTag body:(NSDictionary *)body;
NS_ASSUME_NONNULL_END
@end

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTComponentEvent.h"
#import "RCTAssert.h"
@implementation RCTComponentEvent {
NSArray *_arguments;
}
@synthesize eventName = _eventName;
@synthesize viewTag = _viewTag;
- (instancetype)initWithName:(NSString *)name viewTag:(NSNumber *)viewTag body:(NSDictionary *)body
{
if (self = [super init]) {
NSMutableDictionary *mutableBody = [NSMutableDictionary dictionaryWithDictionary:body];
mutableBody[@"target"] = viewTag;
_eventName = RCTNormalizeInputEventName(name);
_viewTag = viewTag;
_arguments = @[ _viewTag, _eventName, mutableBody ];
}
return self;
}
RCT_NOT_IMPLEMENTED(-(instancetype)init)
- (NSArray *)arguments
{
return _arguments;
}
- (BOOL)canCoalesce
{
return NO;
}
+ (NSString *)moduleDotMethod
{
return @"RCTEventEmitter.receiveEvent";
}
@end

11
node_modules/react-native/React/Base/RCTConstants.h generated vendored Normal file
View File

@ -0,0 +1,11 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTDefines.h>
RCT_EXTERN NSString *const RCTUserInterfaceStyleDidChangeNotification;
RCT_EXTERN NSString *const RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey;

11
node_modules/react-native/React/Base/RCTConstants.m generated vendored Normal file
View File

@ -0,0 +1,11 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTConstants.h"
NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
NSString *const RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey = @"traitCollection";

263
node_modules/react-native/React/Base/RCTConvert.h generated vendored Normal file
View File

@ -0,0 +1,263 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>
#import <React/RCTAnimationType.h>
#import <React/RCTBorderStyle.h>
#import <React/RCTDefines.h>
#import <React/RCTLog.h>
#import <React/RCTPointerEvents.h>
#import <React/RCTTextDecorationLineType.h>
#import <yoga/Yoga.h>
#if TARGET_OS_IPHONE && WEBKIT_IOS_10_APIS_AVAILABLE
#import <WebKit/WebKit.h>
#endif
/**
* This class provides a collection of conversion functions for mapping
* JSON objects to native types and classes. These are useful when writing
* custom RCTViewManager setter methods.
*/
@interface RCTConvert : NSObject
+ (id)id:(id)json;
+ (BOOL)BOOL:(id)json;
+ (double)double:(id)json;
+ (float)float:(id)json;
+ (int)int:(id)json;
+ (int64_t)int64_t:(id)json;
+ (uint64_t)uint64_t:(id)json;
+ (NSInteger)NSInteger:(id)json;
+ (NSUInteger)NSUInteger:(id)json;
+ (NSArray *)NSArray:(id)json;
+ (NSDictionary *)NSDictionary:(id)json;
+ (NSString *)NSString:(id)json;
+ (NSNumber *)NSNumber:(id)json;
+ (NSSet *)NSSet:(id)json;
+ (NSData *)NSData:(id)json;
+ (NSIndexSet *)NSIndexSet:(id)json;
+ (NSURLRequestCachePolicy)NSURLRequestCachePolicy:(id)json;
+ (NSURL *)NSURL:(id)json;
+ (NSURLRequest *)NSURLRequest:(id)json;
typedef NSURL RCTFileURL;
+ (RCTFileURL *)RCTFileURL:(id)json;
+ (NSDate *)NSDate:(id)json;
+ (NSLocale *)NSLocale:(id)json;
+ (NSTimeZone *)NSTimeZone:(id)json;
+ (NSTimeInterval)NSTimeInterval:(id)json;
+ (NSLineBreakMode)NSLineBreakMode:(id)json;
+ (NSTextAlignment)NSTextAlignment:(id)json;
+ (NSUnderlineStyle)NSUnderlineStyle:(id)json;
+ (NSWritingDirection)NSWritingDirection:(id)json;
+ (UITextAutocapitalizationType)UITextAutocapitalizationType:(id)json;
+ (UITextFieldViewMode)UITextFieldViewMode:(id)json;
+ (UIKeyboardType)UIKeyboardType:(id)json;
+ (UIKeyboardAppearance)UIKeyboardAppearance:(id)json;
+ (UIReturnKeyType)UIReturnKeyType:(id)json;
#if !TARGET_OS_TV
+ (UIDataDetectorTypes)UIDataDetectorTypes:(id)json;
#endif
#if TARGET_OS_IPHONE && WEBKIT_IOS_10_APIS_AVAILABLE
+ (WKDataDetectorTypes)WKDataDetectorTypes:(id)json;
#endif
+ (UIViewContentMode)UIViewContentMode:(id)json;
#if !TARGET_OS_TV
+ (UIBarStyle)UIBarStyle:(id)json;
#endif
+ (CGFloat)CGFloat:(id)json;
+ (CGPoint)CGPoint:(id)json;
+ (CGSize)CGSize:(id)json;
+ (CGRect)CGRect:(id)json;
+ (UIEdgeInsets)UIEdgeInsets:(id)json;
+ (CGLineCap)CGLineCap:(id)json;
+ (CGLineJoin)CGLineJoin:(id)json;
+ (CGAffineTransform)CGAffineTransform:(id)json;
+ (UIColor *)UIColor:(id)json;
+ (CGColorRef)CGColor:(id)json CF_RETURNS_NOT_RETAINED;
+ (YGValue)YGValue:(id)json;
+ (NSArray<NSArray *> *)NSArrayArray:(id)json;
+ (NSArray<NSString *> *)NSStringArray:(id)json;
+ (NSArray<NSArray<NSString *> *> *)NSStringArrayArray:(id)json;
+ (NSArray<NSDictionary *> *)NSDictionaryArray:(id)json;
+ (NSArray<NSURL *> *)NSURLArray:(id)json;
+ (NSArray<RCTFileURL *> *)RCTFileURLArray:(id)json;
+ (NSArray<NSNumber *> *)NSNumberArray:(id)json;
+ (NSArray<UIColor *> *)UIColorArray:(id)json;
typedef NSArray CGColorArray;
+ (CGColorArray *)CGColorArray:(id)json;
/**
* Convert a JSON object to a Plist-safe equivalent by stripping null values.
*/
typedef id NSPropertyList;
+ (NSPropertyList)NSPropertyList:(id)json;
typedef BOOL css_backface_visibility_t;
+ (YGOverflow)YGOverflow:(id)json;
+ (YGDisplay)YGDisplay:(id)json;
+ (css_backface_visibility_t)css_backface_visibility_t:(id)json;
+ (YGFlexDirection)YGFlexDirection:(id)json;
+ (YGJustify)YGJustify:(id)json;
+ (YGAlign)YGAlign:(id)json;
+ (YGPositionType)YGPositionType:(id)json;
+ (YGWrap)YGWrap:(id)json;
+ (YGDirection)YGDirection:(id)json;
+ (RCTPointerEvents)RCTPointerEvents:(id)json;
+ (RCTAnimationType)RCTAnimationType:(id)json;
+ (RCTBorderStyle)RCTBorderStyle:(id)json;
+ (RCTTextDecorationLineType)RCTTextDecorationLineType:(id)json;
@end
@interface RCTConvert (Deprecated)
/**
* Use lightweight generics syntax instead, e.g. NSArray<NSString *>
*/
typedef NSArray NSArrayArray __deprecated_msg("Use NSArray<NSArray *>");
typedef NSArray NSStringArray __deprecated_msg("Use NSArray<NSString *>");
typedef NSArray NSStringArrayArray __deprecated_msg("Use NSArray<NSArray<NSString *> *>");
typedef NSArray NSDictionaryArray __deprecated_msg("Use NSArray<NSDictionary *>");
typedef NSArray NSURLArray __deprecated_msg("Use NSArray<NSURL *>");
typedef NSArray RCTFileURLArray __deprecated_msg("Use NSArray<RCTFileURL *>");
typedef NSArray NSNumberArray __deprecated_msg("Use NSArray<NSNumber *>");
typedef NSArray UIColorArray __deprecated_msg("Use NSArray<UIColor *>");
/**
* Synchronous image loading is generally a bad idea for performance reasons.
* If you need to pass image references, try to use `RCTImageSource` and then
* `RCTImageLoader` instead of converting directly to a UIImage.
*/
+ (UIImage *)UIImage:(id)json;
+ (CGImageRef)CGImage:(id)json CF_RETURNS_NOT_RETAINED;
@end
/**
* Underlying implementations of RCT_XXX_CONVERTER macros. Ignore these.
*/
RCT_EXTERN NSNumber *RCTConvertEnumValue(const char *, NSDictionary *, NSNumber *, id);
RCT_EXTERN NSNumber *RCTConvertMultiEnumValue(const char *, NSDictionary *, NSNumber *, id);
RCT_EXTERN NSArray *RCTConvertArrayValue(SEL, id);
/**
* This macro is used for logging conversion errors. This is just used to
* avoid repeating the same boilerplate for every error message.
*/
#define RCTLogConvertError(json, typeName) \
RCTLogError(@"JSON value '%@' of type %@ cannot be converted to %@", json, [json classForCoder], typeName)
/**
* This macro is used for creating simple converter functions that just call
* the specified getter method on the json value.
*/
#define RCT_CONVERTER(type, name, getter) RCT_CUSTOM_CONVERTER(type, name, [json getter])
/**
* This macro is used for creating converter functions with arbitrary logic.
*/
#define RCT_CUSTOM_CONVERTER(type, name, code) \
+(type)name : (id)json RCT_DYNAMIC \
{ \
if (!RCT_DEBUG) { \
return code; \
} else { \
@try { \
return code; \
} @catch (__unused NSException * e) { \
RCTLogConvertError(json, @ #type); \
json = nil; \
return code; \
} \
} \
}
/**
* This macro is similar to RCT_CONVERTER, but specifically geared towards
* numeric types. It will handle string input correctly, and provides more
* detailed error reporting if an invalid value is passed in.
*/
#define RCT_NUMBER_CONVERTER(type, getter) \
RCT_CUSTOM_CONVERTER(type, type, [RCT_DEBUG ? [self NSNumber:json] : json getter])
/**
* When using RCT_ENUM_CONVERTER in ObjC, the compiler is OK with us returning
* the underlying NSInteger/NSUInteger. In ObjC++, this is a type mismatch and
* we need to explicitly cast the return value to expected enum return type.
*/
#ifdef __cplusplus
#define _RCT_CAST(type, expr) static_cast<type>(expr)
#else
#define _RCT_CAST(type, expr) expr
#endif
/**
* This macro is used for creating converters for enum types.
*/
#define RCT_ENUM_CONVERTER(type, values, default, getter) \
+(type)type : (id)json RCT_DYNAMIC \
{ \
static NSDictionary *mapping; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
mapping = values; \
}); \
return _RCT_CAST(type, [RCTConvertEnumValue(#type, mapping, @(default), json) getter]); \
}
/**
* This macro is used for creating converters for enum types for
* multiple enum values combined with | operator
*/
#define RCT_MULTI_ENUM_CONVERTER(type, values, default, getter) \
+(type)type : (id)json RCT_DYNAMIC \
{ \
static NSDictionary *mapping; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
mapping = values; \
}); \
return _RCT_CAST(type, [RCTConvertMultiEnumValue(#type, mapping, @(default), json) getter]); \
}
/**
* This macro is used for creating explicitly-named converter functions
* for typed arrays.
*/
#define RCT_ARRAY_CONVERTER_NAMED(type, name) \
+(NSArray<type *> *)name##Array : (id)json RCT_DYNAMIC \
{ \
return RCTConvertArrayValue(@selector(name:), json); \
}
/**
* This macro is used for creating converter functions for typed arrays.
* RCT_ARRAY_CONVERTER_NAMED may be used when type contains characters
* which are disallowed in selector names.
*/
#define RCT_ARRAY_CONVERTER(type) RCT_ARRAY_CONVERTER_NAMED(type, type)

1241
node_modules/react-native/React/Base/RCTConvert.m generated vendored Normal file

File diff suppressed because it is too large Load Diff

18
node_modules/react-native/React/Base/RCTCxxConvert.h generated vendored Normal file
View File

@ -0,0 +1,18 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
/**
* This class provides a collection of conversion functions for mapping
* JSON objects to cxx types. Extensible via categories.
* Convert methods are expected to return cxx objects wraped in RCTManagedPointer.
*/
@interface RCTCxxConvert : NSObject
@end

12
node_modules/react-native/React/Base/RCTCxxConvert.m generated vendored Normal file
View File

@ -0,0 +1,12 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTCxxConvert.h"
@implementation RCTCxxConvert
@end

149
node_modules/react-native/React/Base/RCTDefines.h generated vendored Normal file
View File

@ -0,0 +1,149 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#if __OBJC__
#import <Foundation/Foundation.h>
#endif
/**
* Make global functions usable in C++
*/
#if defined(__cplusplus)
#define RCT_EXTERN extern "C" __attribute__((visibility("default")))
#define RCT_EXTERN_C_BEGIN extern "C" {
#define RCT_EXTERN_C_END }
#else
#define RCT_EXTERN extern __attribute__((visibility("default")))
#define RCT_EXTERN_C_BEGIN
#define RCT_EXTERN_C_END
#endif
/**
* The RCT_DEBUG macro can be used to exclude error checking and logging code
* from release builds to improve performance and reduce binary size.
*/
#ifndef RCT_DEBUG
#if DEBUG
#define RCT_DEBUG 1
#else
#define RCT_DEBUG 0
#endif
#endif
/**
* The RCT_DEV macro can be used to enable or disable development tools
* such as the debug executors, dev menu, red box, etc.
*/
#ifndef RCT_DEV
#if DEBUG
#define RCT_DEV 1
#else
#define RCT_DEV 0
#endif
#endif
/**
* RCT_DEV_MENU can be used to toggle the dev menu separately from RCT_DEV.
* By default though, it will inherit from RCT_DEV.
*/
#ifndef RCT_DEV_MENU
#define RCT_DEV_MENU RCT_DEV
#endif
#ifndef RCT_ENABLE_INSPECTOR
#if RCT_DEV && __has_include(<React/RCTInspectorDevServerHelper.h>)
#define RCT_ENABLE_INSPECTOR 1
#else
#define RCT_ENABLE_INSPECTOR 0
#endif
#endif
#ifndef ENABLE_PACKAGER_CONNECTION
#if RCT_DEV && (__has_include("RCTPackagerConnection.h") || __has_include(<React/RCTPackagerConnection.h>))
#define ENABLE_PACKAGER_CONNECTION 1
#else
#define ENABLE_PACKAGER_CONNECTION 0
#endif
#endif
#if RCT_DEV
#define RCT_IF_DEV(...) __VA_ARGS__
#else
#define RCT_IF_DEV(...)
#endif
#ifndef RCT_PROFILE
#define RCT_PROFILE RCT_DEV
#endif
/**
* Add the default Metro packager port number
*/
#ifndef RCT_METRO_PORT
#define RCT_METRO_PORT 8081
#else
// test if RCT_METRO_PORT is empty
#define RCT_METRO_PORT_DO_EXPAND(VAL) VAL##1
#define RCT_METRO_PORT_EXPAND(VAL) RCT_METRO_PORT_DO_EXPAND(VAL)
#if !defined(RCT_METRO_PORT) || (RCT_METRO_PORT_EXPAND(RCT_METRO_PORT) == 1)
// Only here if RCT_METRO_PORT is not defined
// OR RCT_METRO_PORT is the empty string
#undef RCT_METRO_PORT
#define RCT_METRO_PORT 8081
#endif
#endif
/**
* Add the default packager name
*/
#ifndef RCT_PACKAGER_NAME
#define RCT_PACKAGER_NAME @"Metro"
#endif
/**
* By default, only raise an NSAssertion in debug mode
* (custom assert functions will still be called).
*/
#ifndef RCT_NSASSERT
#define RCT_NSASSERT RCT_DEBUG
#endif
/**
* Concat two literals. Supports macro expansions,
* e.g. RCT_CONCAT(foo, __FILE__).
*/
#define RCT_CONCAT2(A, B) A##B
#define RCT_CONCAT(A, B) RCT_CONCAT2(A, B)
/**
* This attribute is used for static analysis.
*/
#if !defined RCT_DYNAMIC
#if __has_attribute(objc_dynamic)
#define RCT_DYNAMIC __attribute__((objc_dynamic))
#else
#define RCT_DYNAMIC
#endif
#endif
/**
* Throw an assertion for unimplemented methods.
*/
#define RCT_NOT_IMPLEMENTED(method) \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wmissing-method-return-type\"") \
_Pragma("clang diagnostic ignored \"-Wunused-parameter\"") \
RCT_EXTERN NSException *_RCTNotImplementedException(SEL, Class); \
method NS_UNAVAILABLE \
{ \
@throw _RCTNotImplementedException(_cmd, [self class]); \
} \
_Pragma("clang diagnostic pop")
/**
* Check if WebKit iOS 10.0 APIs are available.
*/
#define WEBKIT_IOS_10_APIS_AVAILABLE __has_include(<WebKit/WKAudiovisualMediaTypes.h>)

20
node_modules/react-native/React/Base/RCTDisplayLink.h generated vendored Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@protocol RCTBridgeModule;
@class RCTModuleData;
@interface RCTDisplayLink : NSObject
- (instancetype)init;
- (void)invalidate;
- (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module withModuleData:(RCTModuleData *)moduleData;
- (void)addToRunLoop:(NSRunLoop *)runLoop;
@end

153
node_modules/react-native/React/Base/RCTDisplayLink.m generated vendored Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTDisplayLink.h"
#import <Foundation/Foundation.h>
#import <QuartzCore/CADisplayLink.h>
#import "RCTAssert.h"
#import "RCTBridgeModule.h"
#import "RCTFrameUpdate.h"
#import "RCTModuleData.h"
#import "RCTProfile.h"
#define RCTAssertRunLoop() \
RCTAssert(_runLoop == [NSRunLoop currentRunLoop], @"This method must be called on the CADisplayLink run loop")
@implementation RCTDisplayLink {
CADisplayLink *_jsDisplayLink;
NSMutableSet<RCTModuleData *> *_frameUpdateObservers;
NSRunLoop *_runLoop;
}
- (instancetype)init
{
if ((self = [super init])) {
_frameUpdateObservers = [NSMutableSet new];
_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)];
}
return self;
}
- (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module withModuleData:(RCTModuleData *)moduleData
{
if (![moduleData.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)] ||
[_frameUpdateObservers containsObject:moduleData]) {
return;
}
[_frameUpdateObservers addObject:moduleData];
// Don't access the module instance via moduleData, as this will cause deadlock
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)module;
__weak typeof(self) weakSelf = self;
observer.pauseCallback = ^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
CFRunLoopRef cfRunLoop = [strongSelf->_runLoop getCFRunLoop];
if (!cfRunLoop) {
return;
}
if ([NSRunLoop currentRunLoop] == strongSelf->_runLoop) {
[weakSelf updateJSDisplayLinkState];
} else {
CFRunLoopPerformBlock(cfRunLoop, kCFRunLoopDefaultMode, ^{
[weakSelf updateJSDisplayLinkState];
});
CFRunLoopWakeUp(cfRunLoop);
}
};
// Assuming we're paused right now, we only need to update the display link's state
// when the new observer is not paused. If it not paused, the observer will immediately
// start receiving updates anyway.
if (![observer isPaused] && _runLoop) {
CFRunLoopPerformBlock([_runLoop getCFRunLoop], kCFRunLoopDefaultMode, ^{
[self updateJSDisplayLinkState];
});
}
}
- (void)addToRunLoop:(NSRunLoop *)runLoop
{
_runLoop = runLoop;
[_jsDisplayLink addToRunLoop:runLoop forMode:NSRunLoopCommonModes];
}
- (void)dealloc
{
[self invalidate];
}
- (void)invalidate
{
[_jsDisplayLink invalidate];
}
- (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue
{
if (queue == RCTJSThread) {
block();
} else if (queue) {
dispatch_async(queue, block);
}
}
- (void)_jsThreadUpdate:(CADisplayLink *)displayLink
{
RCTAssertRunLoop();
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTDisplayLink _jsThreadUpdate:]", nil);
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
for (RCTModuleData *moduleData in _frameUpdateObservers) {
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
if (!observer.paused) {
if (moduleData.methodQueue) {
RCTProfileBeginFlowEvent();
[self
dispatchBlock:^{
RCTProfileEndFlowEvent();
[observer didUpdateFrame:frameUpdate];
}
queue:moduleData.methodQueue];
} else {
[observer didUpdateFrame:frameUpdate];
}
}
}
[self updateJSDisplayLinkState];
RCTProfileImmediateEvent(RCTProfileTagAlways, @"JS Thread Tick", displayLink.timestamp, 'g');
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"objc_call");
}
- (void)updateJSDisplayLinkState
{
RCTAssertRunLoop();
BOOL pauseDisplayLink = YES;
for (RCTModuleData *moduleData in _frameUpdateObservers) {
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
if (!observer.paused) {
pauseDisplayLink = NO;
break;
}
}
_jsDisplayLink.paused = pauseDisplayLink;
}
@end

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@class RCTErrorInfo;
/**
* Provides an interface to customize React Native error messages and stack
* traces from exceptions.
*/
@protocol RCTErrorCustomizer <NSObject>
/**
* Customizes the given error, returning the passed info argument if no
* customization is required.
*/
- (nonnull RCTErrorInfo *)customizeErrorInfo:(nonnull RCTErrorInfo *)info;
@end

21
node_modules/react-native/React/Base/RCTErrorInfo.h generated vendored Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@class RCTJSStackFrame;
/**
* An ObjC wrapper for React Native errors.
*/
@interface RCTErrorInfo : NSObject
@property (nonatomic, copy, readonly) NSString *errorMessage;
@property (nonatomic, copy, readonly) NSArray<RCTJSStackFrame *> *stack;
- (instancetype)initWithErrorMessage:(NSString *)errorMessage stack:(NSArray<RCTJSStackFrame *> *)stack;
@end

24
node_modules/react-native/React/Base/RCTErrorInfo.m generated vendored Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTErrorInfo.h"
#import "RCTJSStackFrame.h"
@implementation RCTErrorInfo
- (instancetype)initWithErrorMessage:(NSString *)errorMessage stack:(NSArray<RCTJSStackFrame *> *)stack
{
self = [super init];
if (self) {
_errorMessage = [errorMessage copy];
_stack = [stack copy];
}
return self;
}
@end

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTBridge.h>
typedef NS_ENUM(NSInteger, RCTTextEventType) {
RCTTextEventTypeFocus,
RCTTextEventTypeBlur,
RCTTextEventTypeChange,
RCTTextEventTypeSubmit,
RCTTextEventTypeEnd,
RCTTextEventTypeKeyPress
};
/**
* The threshold at which text inputs will start warning that the JS thread
* has fallen behind (resulting in poor input performance, missed keys, etc.)
*/
RCT_EXTERN const NSInteger RCTTextUpdateLagWarningThreshold;
/**
* Takes an input event name and normalizes it to the form that is required
* by the events system (currently that means starting with the "top" prefix,
* but that's an implementation detail that may change in future).
*/
RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
@protocol RCTEvent <NSObject>
@required
@property (nonatomic, strong, readonly) NSNumber *viewTag;
@property (nonatomic, copy, readonly) NSString *eventName;
- (BOOL)canCoalesce;
/** used directly for doing a JS call */
+ (NSString *)moduleDotMethod;
/** must contain only JSON compatible values */
- (NSArray *)arguments;
@optional
/**
* Coalescing related methods must only be implemented if canCoalesce
* returns YES.
*/
@property (nonatomic, assign, readonly) uint16_t coalescingKey;
- (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent;
@end
/**
* This protocol allows observing events dispatched by RCTEventDispatcher.
*/
@protocol RCTEventDispatcherObserver <NSObject>
/**
* Called before dispatching an event, on the same thread the event was
* dispatched from.
*/
- (void)eventDispatcherWillDispatchEvent:(id<RCTEvent>)event;
@end
/**
* This class wraps the -[RCTBridge enqueueJSCall:args:] method, and
* provides some convenience methods for generating event calls.
*/
@interface RCTEventDispatcher : NSObject <RCTBridgeModule>
/**
* Deprecated, do not use.
*/
- (void)sendAppEventWithName:(NSString *)name body:(id)body __deprecated_msg("Subclass RCTEventEmitter instead");
/**
* Deprecated, do not use.
*/
- (void)sendDeviceEventWithName:(NSString *)name body:(id)body __deprecated_msg("Subclass RCTEventEmitter instead");
/**
* Send a text input/focus event. For internal use only.
*/
- (void)sendTextEventWithType:(RCTTextEventType)type
reactTag:(NSNumber *)reactTag
text:(NSString *)text
key:(NSString *)key
eventCount:(NSInteger)eventCount;
/**
* Send a pre-prepared event object.
*
* Events are sent to JS as soon as the thread is free to process them.
* If an event can be coalesced and there is another compatible event waiting, the coalescing will happen immediately.
*/
- (void)sendEvent:(id<RCTEvent>)event;
/**
* Add an event dispatcher observer.
*/
- (void)addDispatchObserver:(id<RCTEventDispatcherObserver>)observer;
/**
* Remove an event dispatcher observer.
*/
- (void)removeDispatchObserver:(id<RCTEventDispatcherObserver>)observer;
@end
@interface RCTBridge (RCTEventDispatcher)
- (RCTEventDispatcher *)eventDispatcher;
@end

View File

@ -0,0 +1,222 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTEventDispatcher.h"
#import "RCTAssert.h"
#import "RCTBridge+Private.h"
#import "RCTBridge.h"
#import "RCTComponentEvent.h"
#import "RCTProfile.h"
#import "RCTUtils.h"
const NSInteger RCTTextUpdateLagWarningThreshold = 3;
NSString *RCTNormalizeInputEventName(NSString *eventName)
{
if ([eventName hasPrefix:@"on"]) {
eventName = [eventName stringByReplacingCharactersInRange:(NSRange){0, 2} withString:@"top"];
} else if (![eventName hasPrefix:@"top"]) {
eventName = [[@"top" stringByAppendingString:[eventName substringToIndex:1].uppercaseString]
stringByAppendingString:[eventName substringFromIndex:1]];
}
return eventName;
}
static NSNumber *RCTGetEventID(NSNumber *viewTag, NSString *eventName, uint16_t coalescingKey)
{
return @(viewTag.intValue | (((uint64_t)eventName.hash & 0xFFFF) << 32) | (((uint64_t)coalescingKey) << 48));
}
static uint16_t RCTUniqueCoalescingKeyGenerator = 0;
@implementation RCTEventDispatcher {
// We need this lock to protect access to _events, _eventQueue and _eventsDispatchScheduled. It's filled in on main
// thread and consumed on js thread.
NSLock *_eventQueueLock;
// We have this id -> event mapping so we coalesce effectively.
NSMutableDictionary<NSNumber *, id<RCTEvent>> *_events;
// This array contains ids of events in order they come in, so we can emit them to JS in the exact same order.
NSMutableArray<NSNumber *> *_eventQueue;
BOOL _eventsDispatchScheduled;
NSHashTable<id<RCTEventDispatcherObserver>> *_observers;
NSLock *_observersLock;
}
@synthesize bridge = _bridge;
RCT_EXPORT_MODULE()
- (void)setBridge:(RCTBridge *)bridge
{
_bridge = bridge;
_events = [NSMutableDictionary new];
_eventQueue = [NSMutableArray new];
_eventQueueLock = [NSLock new];
_eventsDispatchScheduled = NO;
_observers = [NSHashTable weakObjectsHashTable];
_observersLock = [NSLock new];
}
- (void)sendAppEventWithName:(NSString *)name body:(id)body
{
[_bridge enqueueJSCall:@"RCTNativeAppEventEmitter"
method:@"emit"
args:body ? @[ name, body ] : @[ name ]
completion:NULL];
}
- (void)sendDeviceEventWithName:(NSString *)name body:(id)body
{
[_bridge enqueueJSCall:@"RCTDeviceEventEmitter"
method:@"emit"
args:body ? @[ name, body ] : @[ name ]
completion:NULL];
}
- (void)sendTextEventWithType:(RCTTextEventType)type
reactTag:(NSNumber *)reactTag
text:(NSString *)text
key:(NSString *)key
eventCount:(NSInteger)eventCount
{
static NSString *events[] = {@"focus", @"blur", @"change", @"submitEditing", @"endEditing", @"keyPress"};
NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:@{
@"eventCount" : @(eventCount),
}];
if (text) {
body[@"text"] = text;
}
if (key) {
if (key.length == 0) {
key = @"Backspace"; // backspace
} else {
switch ([key characterAtIndex:0]) {
case '\t':
key = @"Tab";
break;
case '\n':
key = @"Enter";
default:
break;
}
}
body[@"key"] = key;
}
RCTComponentEvent *event = [[RCTComponentEvent alloc] initWithName:events[type] viewTag:reactTag body:body];
[self sendEvent:event];
}
- (void)sendEvent:(id<RCTEvent>)event
{
[_observersLock lock];
for (id<RCTEventDispatcherObserver> observer in _observers) {
[observer eventDispatcherWillDispatchEvent:event];
}
[_observersLock unlock];
[_eventQueueLock lock];
NSNumber *eventID;
if (event.canCoalesce) {
eventID = RCTGetEventID(event.viewTag, event.eventName, event.coalescingKey);
id<RCTEvent> previousEvent = _events[eventID];
if (previousEvent) {
event = [previousEvent coalesceWithEvent:event];
} else {
[_eventQueue addObject:eventID];
}
} else {
id<RCTEvent> previousEvent = _events[eventID];
eventID = RCTGetEventID(event.viewTag, event.eventName, RCTUniqueCoalescingKeyGenerator++);
RCTAssert(
previousEvent == nil,
@"Got event %@ which cannot be coalesced, but has the same eventID %@ as the previous event %@",
event,
eventID,
previousEvent);
[_eventQueue addObject:eventID];
}
_events[eventID] = event;
BOOL scheduleEventsDispatch = NO;
if (!_eventsDispatchScheduled) {
_eventsDispatchScheduled = YES;
scheduleEventsDispatch = YES;
}
// We have to release the lock before dispatching block with events,
// since dispatchBlock: can be executed synchronously on the same queue.
// (This is happening when chrome debugging is turned on.)
[_eventQueueLock unlock];
if (scheduleEventsDispatch) {
[_bridge
dispatchBlock:^{
[self flushEventsQueue];
}
queue:RCTJSThread];
}
}
- (void)addDispatchObserver:(id<RCTEventDispatcherObserver>)observer
{
[_observersLock lock];
[_observers addObject:observer];
[_observersLock unlock];
}
- (void)removeDispatchObserver:(id<RCTEventDispatcherObserver>)observer
{
[_observersLock lock];
[_observers removeObject:observer];
[_observersLock unlock];
}
- (void)dispatchEvent:(id<RCTEvent>)event
{
[_bridge enqueueJSCall:[[event class] moduleDotMethod] args:[event arguments]];
}
- (dispatch_queue_t)methodQueue
{
return RCTJSThread;
}
// js thread only (which surprisingly can be the main thread, depends on used JS executor)
- (void)flushEventsQueue
{
[_eventQueueLock lock];
NSDictionary *events = _events;
_events = [NSMutableDictionary new];
NSMutableArray *eventQueue = _eventQueue;
_eventQueue = [NSMutableArray new];
_eventsDispatchScheduled = NO;
[_eventQueueLock unlock];
for (NSNumber *eventId in eventQueue) {
[self dispatchEvent:events[eventId]];
}
}
@end
@implementation RCTBridge (RCTEventDispatcher)
- (RCTEventDispatcher *)eventDispatcher
{
return [self moduleForClass:[RCTEventDispatcher class]];
}
@end

52
node_modules/react-native/React/Base/RCTFrameUpdate.h generated vendored Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@class CADisplayLink;
/**
* Interface containing the information about the last screen refresh.
*/
@interface RCTFrameUpdate : NSObject
/**
* Timestamp for the actual screen refresh
*/
@property (nonatomic, readonly) NSTimeInterval timestamp;
/**
* Time since the last frame update ( >= 16.6ms )
*/
@property (nonatomic, readonly) NSTimeInterval deltaTime;
- (instancetype)initWithDisplayLink:(CADisplayLink *)displayLink NS_DESIGNATED_INITIALIZER;
@end
/**
* Protocol that must be implemented for subscribing to display refreshes (DisplayLink updates)
*/
@protocol RCTFrameUpdateObserver <NSObject>
/**
* Method called on every screen refresh (if paused != YES)
*/
- (void)didUpdateFrame:(RCTFrameUpdate *)update;
/**
* Synthesize and set to true to pause the calls to -[didUpdateFrame:]
*/
@property (nonatomic, readonly, getter=isPaused) BOOL paused;
/**
* Callback for pause/resume observer.
* Observer should call it when paused property is changed.
*/
@property (nonatomic, copy) dispatch_block_t pauseCallback;
@end

27
node_modules/react-native/React/Base/RCTFrameUpdate.m generated vendored Normal file
View File

@ -0,0 +1,27 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <QuartzCore/CADisplayLink.h>
#import "RCTFrameUpdate.h"
#import "RCTUtils.h"
@implementation RCTFrameUpdate
RCT_NOT_IMPLEMENTED(-(instancetype)init)
- (instancetype)initWithDisplayLink:(CADisplayLink *)displayLink
{
if ((self = [super init])) {
_timestamp = displayLink.timestamp;
_deltaTime = displayLink.duration;
}
return self;
}
@end

40
node_modules/react-native/React/Base/RCTImageSource.h generated vendored Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTConvert.h>
/**
* Object containing an image URL and associated metadata.
*/
@interface RCTImageSource : NSObject
@property (nonatomic, copy, readonly) NSURLRequest *request;
@property (nonatomic, assign, readonly) CGSize size;
@property (nonatomic, assign, readonly) CGFloat scale;
/**
* Create a new image source object.
* Pass a size of CGSizeZero if you do not know or wish to specify the image
* size. Pass a scale of zero if you do not know or wish to specify the scale.
*/
- (instancetype)initWithURLRequest:(NSURLRequest *)request size:(CGSize)size scale:(CGFloat)scale;
/**
* Create a copy of the image source with the specified size and scale.
*/
- (instancetype)imageSourceWithSize:(CGSize)size scale:(CGFloat)scale;
@end
@interface RCTConvert (ImageSource)
+ (RCTImageSource *)RCTImageSource:(id)json;
+ (NSArray<RCTImageSource *> *)RCTImageSourceArray:(id)json;
@end

89
node_modules/react-native/React/Base/RCTImageSource.m generated vendored Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTImageSource.h"
#import "RCTUtils.h"
@interface RCTImageSource ()
@property (nonatomic, assign) BOOL packagerAsset;
@end
@implementation RCTImageSource
- (instancetype)initWithURLRequest:(NSURLRequest *)request size:(CGSize)size scale:(CGFloat)scale
{
if ((self = [super init])) {
_request = [request copy];
_size = size;
_scale = scale;
}
return self;
}
- (instancetype)imageSourceWithSize:(CGSize)size scale:(CGFloat)scale
{
RCTImageSource *imageSource = [[RCTImageSource alloc] initWithURLRequest:_request size:size scale:scale];
imageSource.packagerAsset = _packagerAsset;
return imageSource;
}
- (BOOL)isEqual:(RCTImageSource *)object
{
if (![object isKindOfClass:[RCTImageSource class]]) {
return NO;
}
return [_request isEqual:object.request] && _scale == object.scale &&
(CGSizeEqualToSize(_size, object.size) || CGSizeEqualToSize(object.size, CGSizeZero));
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<RCTImageSource: %p URL=%@, size=%@, scale=%0.f>",
self,
_request.URL,
NSStringFromCGSize(_size),
_scale];
}
@end
@implementation RCTConvert (ImageSource)
+ (RCTImageSource *)RCTImageSource:(id)json
{
if (!json) {
return nil;
}
NSURLRequest *request;
CGSize size = CGSizeZero;
CGFloat scale = 1.0;
BOOL packagerAsset = NO;
if ([json isKindOfClass:[NSDictionary class]]) {
if (!(request = [self NSURLRequest:json])) {
return nil;
}
size = [self CGSize:json];
scale = [self CGFloat:json[@"scale"]] ?: [self BOOL:json[@"deprecated"]] ? 0.0 : 1.0;
packagerAsset = [self BOOL:json[@"__packager_asset"]];
} else if ([json isKindOfClass:[NSString class]]) {
request = [self NSURLRequest:json];
} else {
RCTLogConvertError(json, @"an image. Did you forget to call resolveAssetSource() on the JS side?");
return nil;
}
RCTImageSource *imageSource = [[RCTImageSource alloc] initWithURLRequest:request size:size scale:scale];
imageSource.packagerAsset = packagerAsset;
return imageSource;
}
RCT_ARRAY_CONVERTER(RCTImageSource)
@end

14
node_modules/react-native/React/Base/RCTInvalidating.h generated vendored Normal file
View File

@ -0,0 +1,14 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@protocol RCTInvalidating <NSObject>
- (void)invalidate;
@end

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* This protocol should be adopted when a turbo module needs to directly call into Javascript.
* In bridge-less React Native, it is a replacement for [_bridge enqueueJSCall:].
*/
@protocol RCTJSInvokerModule
@property (nonatomic, copy, nonnull) void (^invokeJS)(NSString *module, NSString *method, NSArray *args);
@end

30
node_modules/react-native/React/Base/RCTJSStackFrame.h generated vendored Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@interface RCTJSStackFrame : NSObject
@property (nonatomic, copy, readonly) NSString *methodName;
@property (nonatomic, copy, readonly) NSString *file;
@property (nonatomic, readonly) NSInteger lineNumber;
@property (nonatomic, readonly) NSInteger column;
@property (nonatomic, readonly) NSInteger collapse;
- (instancetype)initWithMethodName:(NSString *)methodName
file:(NSString *)file
lineNumber:(NSInteger)lineNumber
column:(NSInteger)column
collapse:(NSInteger)collapse;
- (NSDictionary *)toDictionary;
+ (instancetype)stackFrameWithLine:(NSString *)line;
+ (instancetype)stackFrameWithDictionary:(NSDictionary *)dict;
+ (NSArray<RCTJSStackFrame *> *)stackFramesWithLines:(NSString *)lines;
+ (NSArray<RCTJSStackFrame *> *)stackFramesWithDictionaries:(NSArray<NSDictionary *> *)dicts;
@end

150
node_modules/react-native/React/Base/RCTJSStackFrame.m generated vendored Normal file
View File

@ -0,0 +1,150 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTJSStackFrame.h"
#import "RCTLog.h"
#import "RCTUtils.h"
/**
* The RegEx used to parse Error.stack.
*
* JavaScriptCore has the following format:
*
* Exception: Error: argh
* func1@/path/to/file.js:2:18
* func2@/path/to/file.js:6:8
* eval@[native code]
* global code@/path/to/file.js:13:5
*
* Another supported format:
*
* Error: argh
* at func1 (/path/to/file.js:2:18)
* at func2 (/path/to/file.js:6:8)
* at eval (native)
* at global (/path/to/file.js:13:5)
*/
static NSRegularExpression *RCTJSStackFrameRegex()
{
static dispatch_once_t onceToken;
static NSRegularExpression *_regex;
dispatch_once(&onceToken, ^{
NSString *pattern =
@"\\s*(?:at)?\\s*" // Skip leading "at" and whitespace, noncapturing
@"(.+?)" // Capture the function name (group 1)
@"\\s*[@(]" // Skip whitespace, then @ or (
@"(.*):" // Capture the file name (group 2), then colon
@"(\\d+):(\\d+)" // Line and column number (groups 3 and 4)
@"\\)?$" // Optional closing paren and EOL
;
NSError *regexError;
_regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&regexError];
if (regexError) {
RCTLogError(@"Failed to build regex: %@", [regexError localizedDescription]);
}
});
return _regex;
}
@implementation RCTJSStackFrame
- (instancetype)initWithMethodName:(NSString *)methodName
file:(NSString *)file
lineNumber:(NSInteger)lineNumber
column:(NSInteger)column
collapse:(NSInteger)collapse
{
if (self = [super init]) {
_methodName = methodName;
_file = file;
_lineNumber = lineNumber;
_column = column;
_collapse = collapse;
}
return self;
}
- (NSDictionary *)toDictionary
{
return @{
@"methodName" : RCTNullIfNil(self.methodName),
@"file" : RCTNullIfNil(self.file),
@"lineNumber" : @(self.lineNumber),
@"column" : @(self.column),
@"collapse" : @(self.collapse)
};
}
+ (instancetype)stackFrameWithLine:(NSString *)line
{
NSTextCheckingResult *match = [RCTJSStackFrameRegex() firstMatchInString:line
options:0
range:NSMakeRange(0, line.length)];
if (!match) {
return nil;
}
// methodName may not be present for e.g. anonymous functions
const NSRange methodNameRange = [match rangeAtIndex:1];
NSString *methodName = methodNameRange.location == NSNotFound ? nil : [line substringWithRange:methodNameRange];
NSString *file = [line substringWithRange:[match rangeAtIndex:2]];
NSString *lineNumber = [line substringWithRange:[match rangeAtIndex:3]];
NSString *column = [line substringWithRange:[match rangeAtIndex:4]];
return [[self alloc] initWithMethodName:methodName
file:file
lineNumber:[lineNumber integerValue]
column:[column integerValue]
collapse:@NO];
}
+ (instancetype)stackFrameWithDictionary:(NSDictionary *)dict
{
return [[self alloc] initWithMethodName:RCTNilIfNull(dict[@"methodName"])
file:dict[@"file"]
lineNumber:[RCTNilIfNull(dict[@"lineNumber"]) integerValue]
column:[RCTNilIfNull(dict[@"column"]) integerValue]
collapse:[RCTNilIfNull(dict[@"collapse"]) integerValue]];
}
+ (NSArray<RCTJSStackFrame *> *)stackFramesWithLines:(NSString *)lines
{
NSMutableArray *stack = [NSMutableArray new];
for (NSString *line in [lines componentsSeparatedByString:@"\n"]) {
RCTJSStackFrame *frame = [self stackFrameWithLine:line];
if (frame) {
[stack addObject:frame];
}
}
return stack;
}
+ (NSArray<RCTJSStackFrame *> *)stackFramesWithDictionaries:(NSArray<NSDictionary *> *)dicts
{
NSMutableArray *stack = [NSMutableArray new];
for (NSDictionary *dict in dicts) {
RCTJSStackFrame *frame = [self stackFrameWithDictionary:dict];
if (frame) {
[stack addObject:frame];
}
}
return stack;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p method name: %@; file name: %@; line: %ld; column: %ld>",
self.class,
self,
self.methodName,
self.file,
(long)self.lineNumber,
(long)self.column];
}
@end

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <objc/runtime.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTInvalidating.h>
typedef void (^RCTJavaScriptCompleteBlock)(NSError *error);
typedef void (^RCTJavaScriptCallback)(id result, NSError *error);
/**
* Abstracts away a JavaScript execution context - we may be running code in a
* web view (for debugging purposes), or may be running code in a `JSContext`.
*/
@protocol RCTJavaScriptExecutor <RCTInvalidating, RCTBridgeModule>
/**
* Used to set up the executor after the bridge has been fully initialized.
* Do any expensive setup in this method instead of `-init`.
*/
- (void)setUp;
/**
* Whether the executor has been invalidated
*/
@property (nonatomic, readonly, getter=isValid) BOOL valid;
/**
* Executes BatchedBridge.flushedQueue on JS thread and calls the given callback
* with JSValue, containing the next queue, and JSContext.
*/
- (void)flushedQueue:(RCTJavaScriptCallback)onComplete;
/**
* Executes BatchedBridge.callFunctionReturnFlushedQueue with the module name,
* method name and optional additional arguments on the JS thread and calls the
* given callback with JSValue, containing the next queue, and JSContext.
*/
- (void)callFunctionOnModule:(NSString *)module
method:(NSString *)method
arguments:(NSArray *)args
callback:(RCTJavaScriptCallback)onComplete;
/**
* Executes BatchedBridge.invokeCallbackAndReturnFlushedQueue with the cbID,
* and optional additional arguments on the JS thread and calls the
* given callback with JSValue, containing the next queue, and JSContext.
*/
- (void)invokeCallbackID:(NSNumber *)cbID arguments:(NSArray *)args callback:(RCTJavaScriptCallback)onComplete;
/**
* Runs an application script, and notifies of the script load being complete via `onComplete`.
*/
- (void)executeApplicationScript:(NSData *)script
sourceURL:(NSURL *)sourceURL
onComplete:(RCTJavaScriptCompleteBlock)onComplete;
- (void)injectJSONText:(NSString *)script
asGlobalObjectNamed:(NSString *)objectName
callback:(RCTJavaScriptCompleteBlock)onComplete;
/**
* Enqueue a block to run in the executors JS thread. Fallback to `dispatch_async`
* on the main queue if the executor doesn't own a thread.
*/
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block;
/**
* Special case for Timers + ContextExecutor - instead of the default
* if jsthread then call else dispatch call on jsthread
* ensure the call is made async on the jsthread
*/
- (void)executeAsyncBlockOnJavaScriptQueue:(dispatch_block_t)block;
@end

94
node_modules/react-native/React/Base/RCTJavaScriptLoader.h generated vendored Executable file
View File

@ -0,0 +1,94 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTDefines.h>
extern NSString *const RCTJavaScriptLoaderErrorDomain;
NS_ENUM(NSInteger){
RCTJavaScriptLoaderErrorNoScriptURL = 1,
RCTJavaScriptLoaderErrorFailedOpeningFile = 2,
RCTJavaScriptLoaderErrorFailedReadingFile = 3,
RCTJavaScriptLoaderErrorFailedStatingFile = 3,
RCTJavaScriptLoaderErrorURLLoadFailed = 3,
RCTJavaScriptLoaderErrorBCVersion = 4,
RCTJavaScriptLoaderErrorBCNotSupported = 4,
RCTJavaScriptLoaderErrorCannotBeLoadedSynchronously = 1000,
};
NS_ENUM(NSInteger){
RCTSourceFilesChangedCountNotBuiltByBundler = -2,
RCTSourceFilesChangedCountRebuiltFromScratch = -1,
};
@interface RCTLoadingProgress : NSObject
@property (nonatomic, copy) NSString *status;
@property (strong, nonatomic) NSNumber *done;
@property (strong, nonatomic) NSNumber *total;
@end
@interface RCTSource : NSObject
/**
* URL of the source object.
*/
@property (strong, nonatomic, readonly) NSURL *url;
/**
* JS source (or simply the binary header in the case of a RAM bundle).
*/
@property (strong, nonatomic, readonly) NSData *data;
/**
* Length of the entire JS bundle. Note that self.length != self.data.length in the case of certain bundle formats. For
* instance, when using RAM bundles:
*
* - self.data will point to the bundle header
* - self.data.length is the length of the bundle header, i.e. sizeof(facebook::react::BundleHeader)
* - self.length is the length of the entire bundle file (header + contents)
*/
@property (nonatomic, readonly) NSUInteger length;
/**
* Returns number of files changed when building this bundle:
*
* - RCTSourceFilesChangedCountNotBuiltByBundler if the source wasn't built by the bundler (e.g. read from disk)
* - RCTSourceFilesChangedCountRebuiltFromScratch if the source was rebuilt from scratch by the bundler
* - Otherwise, the number of files changed when incrementally rebuilding the source
*/
@property (nonatomic, readonly) NSInteger filesChangedCount;
@end
typedef void (^RCTSourceLoadProgressBlock)(RCTLoadingProgress *progressData);
typedef void (^RCTSourceLoadBlock)(NSError *error, RCTSource *source);
@interface RCTJavaScriptLoader : NSObject
+ (void)loadBundleAtURL:(NSURL *)scriptURL
onProgress:(RCTSourceLoadProgressBlock)onProgress
onComplete:(RCTSourceLoadBlock)onComplete;
/**
* @experimental
* Attempts to synchronously load the script at the given URL. The following two conditions must be met:
* 1. It must be a file URL.
* 2. It must not point to a text/javascript file.
* If the URL does not meet those conditions, this method will return nil and supply an error with the domain
* RCTJavaScriptLoaderErrorDomain and the code RCTJavaScriptLoaderErrorCannotBeLoadedSynchronously.
*/
+ (NSData *)attemptSynchronousLoadOfBundleAtURL:(NSURL *)scriptURL
runtimeBCVersion:(int32_t)runtimeBCVersion
sourceLength:(int64_t *)sourceLength
error:(NSError **)error;
@end

378
node_modules/react-native/React/Base/RCTJavaScriptLoader.mm generated vendored Executable file
View File

@ -0,0 +1,378 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTJavaScriptLoader.h"
#import <sys/stat.h>
#import <cxxreact/JSBundleType.h>
#import "RCTBridge.h"
#import "RCTConvert.h"
#import "RCTMultipartDataTask.h"
#import "RCTPerformanceLogger.h"
#import "RCTUtils.h"
NSString *const RCTJavaScriptLoaderErrorDomain = @"RCTJavaScriptLoaderErrorDomain";
static const int32_t JSNoBytecodeFileFormatVersion = -1;
@interface RCTSource () {
@public
NSURL *_url;
NSData *_data;
NSUInteger _length;
NSInteger _filesChangedCount;
}
@end
@implementation RCTSource
static RCTSource *RCTSourceCreate(NSURL *url, NSData *data, int64_t length) NS_RETURNS_RETAINED
{
RCTSource *source = [RCTSource new];
source->_url = url;
source->_data = data;
source->_length = length;
source->_filesChangedCount = RCTSourceFilesChangedCountNotBuiltByBundler;
return source;
}
@end
@implementation RCTLoadingProgress
- (NSString *)description
{
NSMutableString *desc = [NSMutableString new];
[desc appendString:_status ?: @"Loading"];
if ([_total integerValue] > 0) {
[desc appendFormat:@" %ld%% (%@/%@)", (long)(100 * [_done integerValue] / [_total integerValue]), _done, _total];
}
[desc appendString:@"\u2026"];
return desc;
}
@end
@implementation RCTJavaScriptLoader
RCT_NOT_IMPLEMENTED(-(instancetype)init)
+ (void)loadBundleAtURL:(NSURL *)scriptURL
onProgress:(RCTSourceLoadProgressBlock)onProgress
onComplete:(RCTSourceLoadBlock)onComplete
{
int64_t sourceLength;
NSError *error;
NSData *data = [self attemptSynchronousLoadOfBundleAtURL:scriptURL
runtimeBCVersion:JSNoBytecodeFileFormatVersion
sourceLength:&sourceLength
error:&error];
if (data) {
onComplete(nil, RCTSourceCreate(scriptURL, data, sourceLength));
return;
}
const BOOL isCannotLoadSyncError = [error.domain isEqualToString:RCTJavaScriptLoaderErrorDomain] &&
error.code == RCTJavaScriptLoaderErrorCannotBeLoadedSynchronously;
if (isCannotLoadSyncError) {
attemptAsynchronousLoadOfBundleAtURL(scriptURL, onProgress, onComplete);
} else {
onComplete(error, nil);
}
}
+ (NSData *)attemptSynchronousLoadOfBundleAtURL:(NSURL *)scriptURL
runtimeBCVersion:(int32_t)runtimeBCVersion
sourceLength:(int64_t *)sourceLength
error:(NSError **)error
{
NSString *unsanitizedScriptURLString = scriptURL.absoluteString;
// Sanitize the script URL
scriptURL = sanitizeURL(scriptURL);
if (!scriptURL) {
if (error) {
*error = [NSError
errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorNoScriptURL
userInfo:@{
NSLocalizedDescriptionKey : [NSString
stringWithFormat:@"No script URL provided. Make sure the packager is "
@"running or you have embedded a JS bundle in your application bundle.\n\n"
@"unsanitizedScriptURLString = %@",
unsanitizedScriptURLString]
}];
}
return nil;
}
// Load local script file
if (!scriptURL.fileURL) {
if (error) {
*error = [NSError errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorCannotBeLoadedSynchronously
userInfo:@{
NSLocalizedDescriptionKey :
[NSString stringWithFormat:@"Cannot load %@ URLs synchronously", scriptURL.scheme]
}];
}
return nil;
}
// Load the first 4 bytes to check if the bundle is regular or RAM ("Random Access Modules" bundle).
// The RAM bundle has a magic number in the 4 first bytes `(0xFB0BD1E5)`.
// The benefit of RAM bundle over a regular bundle is that we can lazily inject
// modules into JSC as they're required.
FILE *bundle = fopen(scriptURL.path.UTF8String, "r");
if (!bundle) {
if (error) {
*error = [NSError
errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorFailedOpeningFile
userInfo:@{
NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Error opening bundle %@", scriptURL.path]
}];
}
return nil;
}
facebook::react::BundleHeader header;
size_t readResult = fread(&header, sizeof(header), 1, bundle);
fclose(bundle);
if (readResult != 1) {
if (error) {
*error = [NSError
errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorFailedReadingFile
userInfo:@{
NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Error reading bundle %@", scriptURL.path]
}];
}
return nil;
}
facebook::react::ScriptTag tag = facebook::react::parseTypeFromHeader(header);
switch (tag) {
case facebook::react::ScriptTag::RAMBundle:
break;
case facebook::react::ScriptTag::String: {
#if RCT_ENABLE_INSPECTOR
NSData *source = [NSData dataWithContentsOfFile:scriptURL.path options:NSDataReadingMappedIfSafe error:error];
if (sourceLength && source != nil) {
*sourceLength = source.length;
}
return source;
#else
if (error) {
*error =
[NSError errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorCannotBeLoadedSynchronously
userInfo:@{NSLocalizedDescriptionKey : @"Cannot load text/javascript files synchronously"}];
}
return nil;
#endif
}
case facebook::react::ScriptTag::BCBundle:
if (runtimeBCVersion == JSNoBytecodeFileFormatVersion || runtimeBCVersion < 0) {
if (error) {
*error = [NSError
errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorBCNotSupported
userInfo:@{NSLocalizedDescriptionKey : @"Bytecode bundles are not supported by this runtime."}];
}
return nil;
} else if ((uint32_t)runtimeBCVersion != header.version) {
if (error) {
NSString *errDesc = [NSString
stringWithFormat:@"BC Version Mismatch. Expect: %d, Actual: %u", runtimeBCVersion, header.version];
*error = [NSError errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorBCVersion
userInfo:@{NSLocalizedDescriptionKey : errDesc}];
}
return nil;
}
break;
}
struct stat statInfo;
if (stat(scriptURL.path.UTF8String, &statInfo) != 0) {
if (error) {
*error = [NSError
errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorFailedStatingFile
userInfo:@{
NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Error stating bundle %@", scriptURL.path]
}];
}
return nil;
}
if (sourceLength) {
*sourceLength = statInfo.st_size;
}
return [NSData dataWithBytes:&header length:sizeof(header)];
}
static void parseHeaders(NSDictionary *headers, RCTSource *source)
{
source->_filesChangedCount = [headers[@"X-Metro-Files-Changed-Count"] integerValue];
}
static void attemptAsynchronousLoadOfBundleAtURL(
NSURL *scriptURL,
RCTSourceLoadProgressBlock onProgress,
RCTSourceLoadBlock onComplete)
{
scriptURL = sanitizeURL(scriptURL);
if (scriptURL.fileURL) {
// Reading in a large bundle can be slow. Dispatch to the background queue to do it.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSError *error = nil;
NSData *source = [NSData dataWithContentsOfFile:scriptURL.path options:NSDataReadingMappedIfSafe error:&error];
onComplete(error, RCTSourceCreate(scriptURL, source, source.length));
});
return;
}
RCTMultipartDataTask *task = [[RCTMultipartDataTask alloc] initWithURL:scriptURL
partHandler:^(NSInteger statusCode, NSDictionary *headers, NSData *data, NSError *error, BOOL done) {
if (!done) {
if (onProgress) {
onProgress(progressEventFromData(data));
}
return;
}
// Handle general request errors
if (error) {
if ([error.domain isEqualToString:NSURLErrorDomain]) {
error = [NSError
errorWithDomain:RCTJavaScriptLoaderErrorDomain
code:RCTJavaScriptLoaderErrorURLLoadFailed
userInfo:@{
NSLocalizedDescriptionKey :
[@"Could not connect to development server.\n\n"
"Ensure the following:\n"
"- Node server is running and available on the same network - run 'npm start' from react-native root\n"
"- Node server URL is correctly set in AppDelegate\n"
"- WiFi is enabled and connected to the same network as the Node Server\n\n"
"URL: " stringByAppendingString:scriptURL.absoluteString],
NSLocalizedFailureReasonErrorKey : error.localizedDescription,
NSUnderlyingErrorKey : error,
}];
}
onComplete(error, nil);
return;
}
// For multipart responses packager sets X-Http-Status header in case HTTP status code
// is different from 200 OK
NSString *statusCodeHeader = headers[@"X-Http-Status"];
if (statusCodeHeader) {
statusCode = [statusCodeHeader integerValue];
}
if (statusCode != 200) {
error =
[NSError errorWithDomain:@"JSServer"
code:statusCode
userInfo:userInfoForRawResponse([[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding])];
onComplete(error, nil);
return;
}
// Validate that the packager actually returned javascript.
NSString *contentType = headers[@"Content-Type"];
NSString *mimeType = [[contentType componentsSeparatedByString:@";"] firstObject];
if (![mimeType isEqualToString:@"application/javascript"] && ![mimeType isEqualToString:@"text/javascript"]) {
NSString *description = [NSString
stringWithFormat:@"Expected MIME-Type to be 'application/javascript' or 'text/javascript', but got '%@'.",
mimeType];
error = [NSError
errorWithDomain:@"JSServer"
code:NSURLErrorCannotParseResponse
userInfo:@{NSLocalizedDescriptionKey : description, @"headers" : headers, @"data" : data}];
onComplete(error, nil);
return;
}
RCTSource *source = RCTSourceCreate(scriptURL, data, data.length);
parseHeaders(headers, source);
onComplete(nil, source);
}
progressHandler:^(NSDictionary *headers, NSNumber *loaded, NSNumber *total) {
// Only care about download progress events for the javascript bundle part.
if ([headers[@"Content-Type"] isEqualToString:@"application/javascript"]) {
onProgress(progressEventFromDownloadProgress(loaded, total));
}
}];
[task startTask];
}
static NSURL *sanitizeURL(NSURL *url)
{
// Why we do this is lost to time. We probably shouldn't; passing a valid URL is the caller's responsibility not ours.
return [RCTConvert NSURL:url.absoluteString];
}
static RCTLoadingProgress *progressEventFromData(NSData *rawData)
{
NSString *text = [[NSString alloc] initWithData:rawData encoding:NSUTF8StringEncoding];
id info = RCTJSONParse(text, nil);
if (!info || ![info isKindOfClass:[NSDictionary class]]) {
return nil;
}
RCTLoadingProgress *progress = [RCTLoadingProgress new];
progress.status = info[@"status"];
progress.done = info[@"done"];
progress.total = info[@"total"];
return progress;
}
static RCTLoadingProgress *progressEventFromDownloadProgress(NSNumber *total, NSNumber *done)
{
RCTLoadingProgress *progress = [RCTLoadingProgress new];
progress.status = @"Downloading JavaScript bundle";
// Progress values are in bytes transform them to kilobytes for smaller numbers.
progress.done = done != nil ? @([done integerValue] / 1024) : nil;
progress.total = total != nil ? @([total integerValue] / 1024) : nil;
return progress;
}
static NSDictionary *userInfoForRawResponse(NSString *rawText)
{
NSDictionary *parsedResponse = RCTJSONParse(rawText, nil);
if (![parsedResponse isKindOfClass:[NSDictionary class]]) {
return @{NSLocalizedDescriptionKey : rawText};
}
NSArray *errors = parsedResponse[@"errors"];
if (![errors isKindOfClass:[NSArray class]]) {
return @{NSLocalizedDescriptionKey : rawText};
}
NSMutableArray<NSDictionary *> *fakeStack = [NSMutableArray new];
for (NSDictionary *err in errors) {
[fakeStack addObject:@{
@"methodName" : err[@"description"] ?: @"",
@"file" : err[@"filename"] ?: @"",
@"lineNumber" : err[@"lineNumber"] ?: @0
}];
}
return
@{NSLocalizedDescriptionKey : parsedResponse[@"message"] ?: @"No message provided", @"stack" : [fakeStack copy]};
}
@end

48
node_modules/react-native/React/Base/RCTKeyCommands.h generated vendored Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
@interface RCTKeyCommands : NSObject
+ (instancetype)sharedInstance;
/**
* Register a single-press keyboard command.
*/
- (void)registerKeyCommandWithInput:(NSString *)input
modifierFlags:(UIKeyModifierFlags)flags
action:(void (^)(UIKeyCommand *command))block;
/**
* Unregister a single-press keyboard command.
*/
- (void)unregisterKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags;
/**
* Check if a single-press command is registered.
*/
- (BOOL)isKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags;
/**
* Register a double-press keyboard command.
*/
- (void)registerDoublePressKeyCommandWithInput:(NSString *)input
modifierFlags:(UIKeyModifierFlags)flags
action:(void (^)(UIKeyCommand *command))block;
/**
* Unregister a double-press keyboard command.
*/
- (void)unregisterDoublePressKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags;
/**
* Check if a double-press command is registered.
*/
- (BOOL)isDoublePressKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags;
@end

329
node_modules/react-native/React/Base/RCTKeyCommands.m generated vendored Normal file
View File

@ -0,0 +1,329 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTKeyCommands.h"
#import <UIKit/UIKit.h>
#import "RCTDefines.h"
#import "RCTUtils.h"
#if RCT_DEV
@interface RCTKeyCommand : NSObject <NSCopying>
@property (nonatomic, strong) UIKeyCommand *keyCommand;
@property (nonatomic, copy) void (^block)(UIKeyCommand *);
@end
@implementation RCTKeyCommand
- (instancetype)initWithKeyCommand:(UIKeyCommand *)keyCommand block:(void (^)(UIKeyCommand *))block
{
if ((self = [super init])) {
_keyCommand = keyCommand;
_block = block;
}
return self;
}
RCT_NOT_IMPLEMENTED(-(instancetype)init)
- (id)copyWithZone:(__unused NSZone *)zone
{
return self;
}
- (NSUInteger)hash
{
return _keyCommand.input.hash ^ _keyCommand.modifierFlags;
}
- (BOOL)isEqual:(RCTKeyCommand *)object
{
if (![object isKindOfClass:[RCTKeyCommand class]]) {
return NO;
}
return [self matchesInput:object.keyCommand.input flags:object.keyCommand.modifierFlags];
}
- (BOOL)matchesInput:(NSString *)input flags:(UIKeyModifierFlags)flags
{
return [_keyCommand.input isEqual:input] && _keyCommand.modifierFlags == flags;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@:%p input=\"%@\" flags=%lld hasBlock=%@>",
[self class],
self,
_keyCommand.input,
(long long)_keyCommand.modifierFlags,
_block ? @"YES" : @"NO"];
}
@end
@interface RCTKeyCommands ()
@property (nonatomic, strong) NSMutableSet<RCTKeyCommand *> *commands;
@end
@implementation UIResponder (RCTKeyCommands)
+ (UIResponder *)RCT_getFirstResponder:(UIResponder *)view
{
UIResponder *firstResponder = nil;
if (view.isFirstResponder) {
return view;
} else if ([view isKindOfClass:[UIViewController class]]) {
if ([(UIViewController *)view parentViewController]) {
firstResponder = [UIResponder RCT_getFirstResponder:[(UIViewController *)view parentViewController]];
}
return firstResponder ? firstResponder : [UIResponder RCT_getFirstResponder:[(UIViewController *)view view]];
} else if ([view isKindOfClass:[UIView class]]) {
for (UIView *subview in [(UIView *)view subviews]) {
firstResponder = [UIResponder RCT_getFirstResponder:subview];
if (firstResponder) {
return firstResponder;
}
}
}
return firstResponder;
}
- (NSArray<UIKeyCommand *> *)RCT_keyCommands
{
NSSet<RCTKeyCommand *> *commands = [RCTKeyCommands sharedInstance].commands;
return [[commands valueForKeyPath:@"keyCommand"] allObjects];
}
/**
* Single Press Key Command Response
* Command + KeyEvent (Command + R/D, etc.)
*/
- (void)RCT_handleKeyCommand:(UIKeyCommand *)key
{
// NOTE: throttle the key handler because on iOS 9 the handleKeyCommand:
// method gets called repeatedly if the command key is held down.
static NSTimeInterval lastCommand = 0;
if (CACurrentMediaTime() - lastCommand > 0.5) {
for (RCTKeyCommand *command in [RCTKeyCommands sharedInstance].commands) {
if ([command.keyCommand.input isEqualToString:key.input] &&
command.keyCommand.modifierFlags == key.modifierFlags) {
if (command.block) {
command.block(key);
lastCommand = CACurrentMediaTime();
}
}
}
}
}
/**
* Double Press Key Command Response
* Double KeyEvent (Double R, etc.)
*/
- (void)RCT_handleDoublePressKeyCommand:(UIKeyCommand *)key
{
static BOOL firstPress = YES;
static NSTimeInterval lastCommand = 0;
static NSTimeInterval lastDoubleCommand = 0;
static NSString *lastInput = nil;
static UIKeyModifierFlags lastModifierFlags = 0;
if (firstPress) {
for (RCTKeyCommand *command in [RCTKeyCommands sharedInstance].commands) {
if ([command.keyCommand.input isEqualToString:key.input] &&
command.keyCommand.modifierFlags == key.modifierFlags && command.block) {
firstPress = NO;
lastCommand = CACurrentMediaTime();
lastInput = key.input;
lastModifierFlags = key.modifierFlags;
return;
}
}
} else {
// Second keyevent within 0.2 second,
// with the same key as the first one.
if (CACurrentMediaTime() - lastCommand < 0.2 && lastInput == key.input && lastModifierFlags == key.modifierFlags) {
for (RCTKeyCommand *command in [RCTKeyCommands sharedInstance].commands) {
if ([command.keyCommand.input isEqualToString:key.input] &&
command.keyCommand.modifierFlags == key.modifierFlags && command.block) {
// NOTE: throttle the key handler because on iOS 9 the handleKeyCommand:
// method gets called repeatedly if the command key is held down.
if (CACurrentMediaTime() - lastDoubleCommand > 0.5) {
command.block(key);
lastDoubleCommand = CACurrentMediaTime();
}
firstPress = YES;
return;
}
}
}
lastCommand = CACurrentMediaTime();
lastInput = key.input;
lastModifierFlags = key.modifierFlags;
}
}
@end
@implementation RCTKeyCommands
+ (void)initialize
{
// swizzle UIResponder
RCTSwapInstanceMethods([UIResponder class], @selector(keyCommands), @selector(RCT_keyCommands));
}
+ (instancetype)sharedInstance
{
static RCTKeyCommands *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self new];
});
return sharedInstance;
}
- (instancetype)init
{
if ((self = [super init])) {
_commands = [NSMutableSet new];
}
return self;
}
- (void)registerKeyCommandWithInput:(NSString *)input
modifierFlags:(UIKeyModifierFlags)flags
action:(void (^)(UIKeyCommand *))block
{
RCTAssertMainQueue();
UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:input
modifierFlags:flags
action:@selector(RCT_handleKeyCommand:)];
RCTKeyCommand *keyCommand = [[RCTKeyCommand alloc] initWithKeyCommand:command block:block];
[_commands removeObject:keyCommand];
[_commands addObject:keyCommand];
}
- (void)unregisterKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
{
RCTAssertMainQueue();
for (RCTKeyCommand *command in _commands.allObjects) {
if ([command matchesInput:input flags:flags]) {
[_commands removeObject:command];
break;
}
}
}
- (BOOL)isKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
{
RCTAssertMainQueue();
for (RCTKeyCommand *command in _commands) {
if ([command matchesInput:input flags:flags]) {
return YES;
}
}
return NO;
}
- (void)registerDoublePressKeyCommandWithInput:(NSString *)input
modifierFlags:(UIKeyModifierFlags)flags
action:(void (^)(UIKeyCommand *))block
{
RCTAssertMainQueue();
UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:input
modifierFlags:flags
action:@selector(RCT_handleDoublePressKeyCommand:)];
RCTKeyCommand *keyCommand = [[RCTKeyCommand alloc] initWithKeyCommand:command block:block];
[_commands removeObject:keyCommand];
[_commands addObject:keyCommand];
}
- (void)unregisterDoublePressKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
{
RCTAssertMainQueue();
for (RCTKeyCommand *command in _commands.allObjects) {
if ([command matchesInput:input flags:flags]) {
[_commands removeObject:command];
break;
}
}
}
- (BOOL)isDoublePressKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
{
RCTAssertMainQueue();
for (RCTKeyCommand *command in _commands) {
if ([command matchesInput:input flags:flags]) {
return YES;
}
}
return NO;
}
@end
#else
@implementation RCTKeyCommands
+ (instancetype)sharedInstance
{
return nil;
}
- (void)registerKeyCommandWithInput:(NSString *)input
modifierFlags:(UIKeyModifierFlags)flags
action:(void (^)(UIKeyCommand *))block
{
}
- (void)unregisterKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
{
}
- (BOOL)isKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
{
return NO;
}
- (void)registerDoublePressKeyCommandWithInput:(NSString *)input
modifierFlags:(UIKeyModifierFlags)flags
action:(void (^)(UIKeyCommand *))block
{
}
- (void)unregisterDoublePressKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
{
}
- (BOOL)isDoublePressKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
{
return NO;
}
@end
#endif

136
node_modules/react-native/React/Base/RCTLog.h generated vendored Normal file
View File

@ -0,0 +1,136 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTAssert.h>
#import <React/RCTDefines.h>
#import <React/RCTUtils.h>
#ifndef RCTLOG_ENABLED
#define RCTLOG_ENABLED 1
#endif
/**
* Thresholds for logs to display a redbox. You can override these values when debugging
* in order to tweak the default logging behavior.
*/
#ifndef RCTLOG_REDBOX_LEVEL
#define RCTLOG_REDBOX_LEVEL RCTLogLevelError
#endif
/**
* Logging macros. Use these to log information, warnings and errors in your
* own code.
*/
#define RCTLog(...) _RCTLog(RCTLogLevelInfo, __VA_ARGS__)
#define RCTLogTrace(...) _RCTLog(RCTLogLevelTrace, __VA_ARGS__)
#define RCTLogInfo(...) _RCTLog(RCTLogLevelInfo, __VA_ARGS__)
#define RCTLogAdvice(string, ...) RCTLogWarn([@"(ADVICE) " stringByAppendingString:(NSString *)string], __VA_ARGS__)
#define RCTLogWarn(...) _RCTLog(RCTLogLevelWarning, __VA_ARGS__)
#define RCTLogError(...) _RCTLog(RCTLogLevelError, __VA_ARGS__)
/**
* An enum representing the severity of the log message.
*/
typedef NS_ENUM(NSInteger, RCTLogLevel) {
RCTLogLevelTrace = 0,
RCTLogLevelInfo = 1,
RCTLogLevelWarning = 2,
RCTLogLevelError = 3,
RCTLogLevelFatal = 4
};
/**
* An enum representing the source of a log message.
*/
typedef NS_ENUM(NSInteger, RCTLogSource) { RCTLogSourceNative = 1, RCTLogSourceJavaScript = 2 };
/**
* A block signature to be used for custom logging functions. In most cases you
* will want to pass these arguments to the RCTFormatLog function in order to
* generate a string.
*/
typedef void (^RCTLogFunction)(
RCTLogLevel level,
RCTLogSource source,
NSString *fileName,
NSNumber *lineNumber,
NSString *message);
/**
* A method to generate a string from a collection of log data. To omit any
* particular data from the log, just pass nil or zero for the argument.
*/
RCT_EXTERN NSString *
RCTFormatLog(NSDate *timestamp, RCTLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message);
/**
* A method to generate a string RCTLogLevel
*/
RCT_EXTERN NSString *RCTFormatLogLevel(RCTLogLevel);
/**
* A method to generate a string from a RCTLogSource
*/
RCT_EXTERN NSString *RCTFormatLogSource(RCTLogSource);
/**
* The default logging function used by RCTLogXX.
*/
extern RCTLogFunction RCTDefaultLogFunction;
/**
* These methods get and set the global logging threshold. This is the level
* below which logs will be ignored. Default is RCTLogLevelInfo for debug and
* RCTLogLevelError for production.
*/
RCT_EXTERN void RCTSetLogThreshold(RCTLogLevel threshold);
RCT_EXTERN RCTLogLevel RCTGetLogThreshold(void);
/**
* These methods get and set the global logging function called by the RCTLogXX
* macros. You can use these to replace the standard behavior with custom log
* functionality.
*/
RCT_EXTERN void RCTSetLogFunction(RCTLogFunction logFunction);
RCT_EXTERN RCTLogFunction RCTGetLogFunction(void);
/**
* This appends additional code to the existing log function, without replacing
* the existing functionality. Useful if you just want to forward logs to an
* extra service without changing the default behavior.
*/
RCT_EXTERN void RCTAddLogFunction(RCTLogFunction logFunction);
/**
* This method temporarily overrides the log function while performing the
* specified block. This is useful for testing purposes (to detect if a given
* function logs something) or to suppress or override logging temporarily.
*/
RCT_EXTERN void RCTPerformBlockWithLogFunction(void (^block)(void), RCTLogFunction logFunction);
/**
* This method adds a conditional prefix to any messages logged within the scope
* of the passed block. This is useful for adding additional context to log
* messages. The block will be performed synchronously on the current thread.
*/
RCT_EXTERN void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix);
/**
* Private logging function - ignore this.
*/
#if RCTLOG_ENABLED
#define _RCTLog(lvl, ...) _RCTLogNativeInternal(lvl, __FILE__, __LINE__, __VA_ARGS__)
#else
#define _RCTLog(lvl, ...) \
do { \
} while (0)
#endif
RCT_EXTERN void _RCTLogNativeInternal(RCTLogLevel, const char *, int, NSString *, ...) NS_FORMAT_FUNCTION(4, 5);
RCT_EXTERN void _RCTLogJavaScriptInternal(RCTLogLevel, NSString *);

308
node_modules/react-native/React/Base/RCTLog.mm generated vendored Normal file
View File

@ -0,0 +1,308 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTLog.h"
#include <cxxabi.h>
#import <objc/message.h>
#import <os/log.h>
#import "RCTAssert.h"
#import "RCTBridge+Private.h"
#import "RCTBridge.h"
#import "RCTDefines.h"
#import "RCTRedBoxSetEnabled.h"
#import "RCTUtils.h"
static NSString *const RCTLogFunctionStack = @"RCTLogFunctionStack";
const char *RCTLogLevels[] = {
"trace",
"info",
"warn",
"error",
"fatal",
};
/* os log will discard debug and info messages if they are not needed */
static const RCTLogLevel RCTDefaultLogThreshold = (RCTLogLevel)(RCTLogLevelInfo - 1);
static RCTLogFunction RCTCurrentLogFunction;
static RCTLogLevel RCTCurrentLogThreshold = RCTDefaultLogThreshold;
RCTLogLevel RCTGetLogThreshold()
{
return RCTCurrentLogThreshold;
}
void RCTSetLogThreshold(RCTLogLevel threshold)
{
RCTCurrentLogThreshold = threshold;
}
static os_log_type_t RCTLogTypeForLogLevel(RCTLogLevel logLevel)
{
if (logLevel < RCTLogLevelInfo) {
return OS_LOG_TYPE_DEBUG;
} else if (logLevel <= RCTLogLevelWarning) {
return OS_LOG_TYPE_INFO;
} else {
return OS_LOG_TYPE_ERROR;
}
}
static os_log_t RCTLogForLogSource(RCTLogSource source)
{
switch (source) {
case RCTLogSourceNative: {
static os_log_t nativeLog;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
nativeLog = os_log_create("com.facebook.react.log", "native");
});
return nativeLog;
}
case RCTLogSourceJavaScript: {
static os_log_t javaScriptLog;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
javaScriptLog = os_log_create("com.facebook.react.log", "javascript");
});
return javaScriptLog;
}
}
}
RCTLogFunction RCTDefaultLogFunction =
^(RCTLogLevel level,
RCTLogSource source,
__unused NSString *fileName,
__unused NSNumber *lineNumber,
NSString *message) {
os_log_with_type(RCTLogForLogSource(source), RCTLogTypeForLogLevel(level), "%{public}s", message.UTF8String);
};
void RCTSetLogFunction(RCTLogFunction logFunction)
{
RCTCurrentLogFunction = logFunction;
}
RCTLogFunction RCTGetLogFunction()
{
if (!RCTCurrentLogFunction) {
RCTCurrentLogFunction = RCTDefaultLogFunction;
}
return RCTCurrentLogFunction;
}
void RCTAddLogFunction(RCTLogFunction logFunction)
{
RCTLogFunction existing = RCTGetLogFunction();
if (existing) {
RCTSetLogFunction(
^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
existing(level, source, fileName, lineNumber, message);
logFunction(level, source, fileName, lineNumber, message);
});
} else {
RCTSetLogFunction(logFunction);
}
}
/**
* returns the topmost stacked log function for the current thread, which
* may not be the same as the current value of RCTCurrentLogFunction.
*/
static RCTLogFunction RCTGetLocalLogFunction()
{
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
NSArray<RCTLogFunction> *functionStack = threadDictionary[RCTLogFunctionStack];
RCTLogFunction logFunction = functionStack.lastObject;
if (logFunction) {
return logFunction;
}
return RCTGetLogFunction();
}
void RCTPerformBlockWithLogFunction(void (^block)(void), RCTLogFunction logFunction)
{
NSMutableDictionary *threadDictionary = [NSThread currentThread].threadDictionary;
NSMutableArray<RCTLogFunction> *functionStack = threadDictionary[RCTLogFunctionStack];
if (!functionStack) {
functionStack = [NSMutableArray new];
threadDictionary[RCTLogFunctionStack] = functionStack;
}
[functionStack addObject:logFunction];
block();
[functionStack removeLastObject];
}
void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix)
{
RCTLogFunction logFunction = RCTGetLocalLogFunction();
if (logFunction) {
RCTPerformBlockWithLogFunction(
block, ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
logFunction(level, source, fileName, lineNumber, [prefix stringByAppendingString:message]);
});
}
}
NSString *
RCTFormatLog(NSDate *timestamp, RCTLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message)
{
NSMutableString *log = [NSMutableString new];
if (timestamp) {
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSDateFormatter new];
formatter.dateFormat = formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS ";
});
[log appendString:[formatter stringFromDate:timestamp]];
}
if (level) {
[log appendFormat:@"[%s]", RCTLogLevels[level]];
}
[log appendFormat:@"[tid:%@]", RCTCurrentThreadName()];
if (fileName) {
fileName = fileName.lastPathComponent;
if (lineNumber) {
[log appendFormat:@"[%@:%@]", fileName, lineNumber];
} else {
[log appendFormat:@"[%@]", fileName];
}
}
if (message) {
[log appendString:@" "];
[log appendString:message];
}
return log;
}
NSString *RCTFormatLogLevel(RCTLogLevel level)
{
NSDictionary *levelsToString = @{
@(RCTLogLevelTrace) : @"trace",
@(RCTLogLevelInfo) : @"info",
@(RCTLogLevelWarning) : @"warning",
@(RCTLogLevelFatal) : @"fatal",
@(RCTLogLevelError) : @"error"
};
return levelsToString[@(level)];
}
NSString *RCTFormatLogSource(RCTLogSource source)
{
NSDictionary *sourcesToString = @{@(RCTLogSourceNative) : @"native", @(RCTLogSourceJavaScript) : @"js"};
return sourcesToString[@(source)];
}
static NSRegularExpression *nativeStackFrameRegex()
{
static dispatch_once_t onceToken;
static NSRegularExpression *_regex;
dispatch_once(&onceToken, ^{
NSError *regexError;
_regex = [NSRegularExpression regularExpressionWithPattern:@"0x[0-9a-f]+ (.*) \\+ (\\d+)$"
options:0
error:&regexError];
if (regexError) {
RCTLogError(@"Failed to build regex: %@", [regexError localizedDescription]);
}
});
return _regex;
}
void _RCTLogNativeInternal(RCTLogLevel level, const char *fileName, int lineNumber, NSString *format, ...)
{
RCTLogFunction logFunction = RCTGetLocalLogFunction();
BOOL log = RCT_DEBUG || (logFunction != nil);
if (log && level >= RCTGetLogThreshold()) {
// Get message
va_list args;
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
// Call log function
if (logFunction) {
logFunction(
level, RCTLogSourceNative, fileName ? @(fileName) : nil, lineNumber > 0 ? @(lineNumber) : nil, message);
}
// Log to red box if one is configured.
if (RCTSharedApplication() && RCTRedBoxGetEnabled() && level >= RCTLOG_REDBOX_LEVEL) {
NSArray<NSString *> *stackSymbols = [NSThread callStackSymbols];
NSMutableArray<NSDictionary *> *stack = [NSMutableArray arrayWithCapacity:(stackSymbols.count - 1)];
[stackSymbols enumerateObjectsUsingBlock:^(NSString *frameSymbols, NSUInteger idx, __unused BOOL *stop) {
if (idx == 0) {
// don't include the current frame
return;
}
NSRange range = NSMakeRange(0, frameSymbols.length);
NSTextCheckingResult *match = [nativeStackFrameRegex() firstMatchInString:frameSymbols options:0 range:range];
if (!match) {
return;
}
NSString *methodName = [frameSymbols substringWithRange:[match rangeAtIndex:1]];
char *demangledName = abi::__cxa_demangle([methodName UTF8String], NULL, NULL, NULL);
if (demangledName) {
methodName = @(demangledName);
free(demangledName);
}
if (idx == 1 && fileName) {
NSString *file = [@(fileName) componentsSeparatedByString:@"/"].lastObject;
[stack addObject:@{@"methodName" : methodName, @"file" : file, @"lineNumber" : @(lineNumber)}];
} else {
[stack addObject:@{@"methodName" : methodName}];
}
}];
dispatch_async(dispatch_get_main_queue(), ^{
// red box is thread safe, but by deferring to main queue we avoid a startup
// race condition that causes the module to be accessed before it has loaded
id redbox = [[RCTBridge currentBridge] moduleForName:@"RedBox" lazilyLoadIfNecessary:YES];
if (redbox) {
void (*showErrorMessage)(id, SEL, NSString *, NSMutableArray<NSDictionary *> *) =
(__typeof__(showErrorMessage))objc_msgSend;
SEL showErrorMessageSEL = NSSelectorFromString(@"showErrorMessage:withStack:");
if ([redbox respondsToSelector:showErrorMessageSEL]) {
showErrorMessage(redbox, showErrorMessageSEL, message, stack);
}
}
});
}
#if RCT_DEBUG
if (!RCTRunningInTestEnvironment()) {
// Log to JS executor
[[RCTBridge currentBridge] logMessage:message level:level ? @(RCTLogLevels[level]) : @"info"];
}
#endif
}
}
void _RCTLogJavaScriptInternal(RCTLogLevel level, NSString *message)
{
RCTLogFunction logFunction = RCTGetLocalLogFunction();
BOOL log = RCT_DEBUG || (logFunction != nil);
if (log && level >= RCTGetLogThreshold()) {
if (logFunction) {
logFunction(level, RCTLogSourceJavaScript, nil, nil, message);
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#ifdef __cplusplus
#include <memory>
#import <Foundation/Foundation.h>
/**
* Type erased wrapper over any cxx value that can be passed as an argument
* to native method.
*/
@interface RCTManagedPointer : NSObject
@property (nonatomic, readonly) void *voidPointer;
- (instancetype)initWithPointer:(std::shared_ptr<void>)pointer;
@end
namespace facebook {
namespace react {
template <typename T, typename P>
RCTManagedPointer *managedPointer(P initializer)
{
auto ptr = std::shared_ptr<void>(new T(initializer));
return [[RCTManagedPointer alloc] initWithPointer:std::move(ptr)];
}
}
}
#endif

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTManagedPointer.h"
@implementation RCTManagedPointer {
std::shared_ptr<void> _pointer;
}
- (instancetype)initWithPointer:(std::shared_ptr<void>)pointer
{
if (self = [super init]) {
_pointer = std::move(pointer);
}
return self;
}
- (void *)voidPointer
{
return _pointer.get();
}
@end

96
node_modules/react-native/React/Base/RCTModuleData.h generated vendored Normal file
View File

@ -0,0 +1,96 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTInvalidating.h>
@protocol RCTBridgeMethod;
@protocol RCTBridgeModule;
@class RCTBridge;
typedef id<RCTBridgeModule> (^RCTBridgeModuleProvider)(void);
@interface RCTModuleData : NSObject <RCTInvalidating>
- (instancetype)initWithModuleClass:(Class)moduleClass bridge:(RCTBridge *)bridge;
- (instancetype)initWithModuleClass:(Class)moduleClass
moduleProvider:(RCTBridgeModuleProvider)moduleProvider
bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
/**
* Calls `constantsToExport` on the module and stores the result. Note that
* this will init the module if it has not already been created. This method
* can be called on any thread, but may block the main thread briefly if the
* module implements `constantsToExport`.
*/
- (void)gatherConstants;
@property (nonatomic, strong, readonly) Class moduleClass;
@property (nonatomic, copy, readonly) NSString *name;
/**
* Returns the module methods. Note that this will gather the methods the first
* time it is called and then memoize the results.
*/
@property (nonatomic, copy, readonly) NSArray<id<RCTBridgeMethod>> *methods;
/**
* Returns a map of the module methods. Note that this will gather the methods the first
* time it is called and then memoize the results.
*/
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id<RCTBridgeMethod>> *methodsByName;
/**
* Returns the module's constants, if it exports any
*/
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *exportedConstants;
/**
* Returns YES if module instance has already been initialized; NO otherwise.
*/
@property (nonatomic, assign, readonly) BOOL hasInstance;
/**
* Returns YES if module instance must be created on the main thread.
*/
@property (nonatomic, assign) BOOL requiresMainQueueSetup;
/**
* Returns YES if module has constants to export.
*/
@property (nonatomic, assign, readonly) BOOL hasConstantsToExport;
/**
* Returns the current module instance. Note that this will init the instance
* if it has not already been created. To check if the module instance exists
* without causing it to be created, use `hasInstance` instead.
*/
@property (nonatomic, strong, readwrite) id<RCTBridgeModule> instance;
/**
* Returns the module method dispatch queue. Note that this will init both the
* queue and the module itself if they have not already been created.
*/
@property (nonatomic, strong, readonly) dispatch_queue_t methodQueue;
/**
* Whether the receiver has a valid `instance` which implements -batchDidComplete.
*/
@property (nonatomic, assign, readonly) BOOL implementsBatchDidComplete;
/**
* Whether the receiver has a valid `instance` which implements
* -partialBatchDidFlush.
*/
@property (nonatomic, assign, readonly) BOOL implementsPartialBatchDidFlush;
@end

380
node_modules/react-native/React/Base/RCTModuleData.mm generated vendored Normal file
View File

@ -0,0 +1,380 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTModuleData.h"
#import <objc/runtime.h>
#include <mutex>
#import "RCTBridge+Private.h"
#import "RCTBridge.h"
#import "RCTLog.h"
#import "RCTModuleMethod.h"
#import "RCTProfile.h"
#import "RCTUtils.h"
@implementation RCTModuleData {
NSDictionary<NSString *, id> *_constantsToExport;
NSString *_queueName;
__weak RCTBridge *_bridge;
RCTBridgeModuleProvider _moduleProvider;
std::mutex _instanceLock;
BOOL _setupComplete;
}
@synthesize methods = _methods;
@synthesize methodsByName = _methodsByName;
@synthesize instance = _instance;
@synthesize methodQueue = _methodQueue;
- (void)setUp
{
_implementsBatchDidComplete = [_moduleClass instancesRespondToSelector:@selector(batchDidComplete)];
_implementsPartialBatchDidFlush = [_moduleClass instancesRespondToSelector:@selector(partialBatchDidFlush)];
// If a module overrides `constantsToExport` and doesn't implement `requiresMainQueueSetup`, then we must assume
// that it must be called on the main thread, because it may need to access UIKit.
_hasConstantsToExport = [_moduleClass instancesRespondToSelector:@selector(constantsToExport)];
const BOOL implementsRequireMainQueueSetup = [_moduleClass respondsToSelector:@selector(requiresMainQueueSetup)];
if (implementsRequireMainQueueSetup) {
_requiresMainQueueSetup = [_moduleClass requiresMainQueueSetup];
} else {
static IMP objectInitMethod;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
objectInitMethod = [NSObject instanceMethodForSelector:@selector(init)];
});
// If a module overrides `init` then we must assume that it expects to be
// initialized on the main thread, because it may need to access UIKit.
const BOOL hasCustomInit =
!_instance && [_moduleClass instanceMethodForSelector:@selector(init)] != objectInitMethod;
_requiresMainQueueSetup = _hasConstantsToExport || hasCustomInit;
if (_requiresMainQueueSetup) {
const char *methodName = "";
if (_hasConstantsToExport) {
methodName = "constantsToExport";
} else if (hasCustomInit) {
methodName = "init";
}
RCTLogWarn(
@"Module %@ requires main queue setup since it overrides `%s` but doesn't implement "
"`requiresMainQueueSetup`. In a future release React Native will default to initializing all native modules "
"on a background thread unless explicitly opted-out of.",
_moduleClass,
methodName);
}
}
}
- (instancetype)initWithModuleClass:(Class)moduleClass bridge:(RCTBridge *)bridge
{
return [self initWithModuleClass:moduleClass
moduleProvider:^id<RCTBridgeModule> {
return [moduleClass new];
}
bridge:bridge];
}
- (instancetype)initWithModuleClass:(Class)moduleClass
moduleProvider:(RCTBridgeModuleProvider)moduleProvider
bridge:(RCTBridge *)bridge
{
if (self = [super init]) {
_bridge = bridge;
_moduleClass = moduleClass;
_moduleProvider = [moduleProvider copy];
[self setUp];
}
return self;
}
- (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance bridge:(RCTBridge *)bridge
{
if (self = [super init]) {
_bridge = bridge;
_instance = instance;
_moduleClass = [instance class];
[self setUp];
}
return self;
}
RCT_NOT_IMPLEMENTED(-(instancetype)init);
#pragma mark - private setup methods
- (void)setUpInstanceAndBridge
{
RCT_PROFILE_BEGIN_EVENT(
RCTProfileTagAlways,
@"[RCTModuleData setUpInstanceAndBridge]",
@{@"moduleClass" : NSStringFromClass(_moduleClass)});
{
std::unique_lock<std::mutex> lock(_instanceLock);
if (!_setupComplete && _bridge.valid) {
if (!_instance) {
if (RCT_DEBUG && _requiresMainQueueSetup) {
RCTAssertMainQueue();
}
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData setUpInstanceAndBridge] Create module", nil);
_instance = _moduleProvider ? _moduleProvider() : nil;
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
if (!_instance) {
// Module init returned nil, probably because automatic instantiation
// of the module is not supported, and it is supposed to be passed in to
// the bridge constructor. Mark setup complete to avoid doing more work.
_setupComplete = YES;
RCTLogWarn(
@"The module %@ is returning nil from its constructor. You "
"may need to instantiate it yourself and pass it into the "
"bridge.",
_moduleClass);
}
}
if (_instance && RCTProfileIsProfiling()) {
RCTProfileHookInstance(_instance);
}
// Bridge must be set before methodQueue is set up, as methodQueue
// initialization requires it (View Managers get their queue by calling
// self.bridge.uiManager.methodQueue)
[self setBridgeForInstance];
}
[self setUpMethodQueue];
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
// This is called outside of the lock in order to prevent deadlock issues
// because the logic in `finishSetupForInstance` can cause
// `moduleData.instance` to be accessed re-entrantly.
if (_bridge.moduleSetupComplete) {
[self finishSetupForInstance];
} else {
// If we're here, then the module is completely initialized,
// except for what finishSetupForInstance does. When the instance
// method is called after moduleSetupComplete,
// finishSetupForInstance will run. If _requiresMainQueueSetup
// is true, getting the instance will block waiting for the main
// thread, which could take a while if the main thread is busy
// (I've seen 50ms in testing). So we clear that flag, since
// nothing in finishSetupForInstance needs to be run on the main
// thread.
_requiresMainQueueSetup = NO;
}
}
- (void)setBridgeForInstance
{
if ([_instance respondsToSelector:@selector(bridge)] && _instance.bridge != _bridge) {
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData setBridgeForInstance]", nil);
@try {
[(id)_instance setValue:_bridge forKey:@"bridge"];
} @catch (NSException *exception) {
RCTLogError(
@"%@ has no setter or ivar for its bridge, which is not "
"permitted. You must either @synthesize the bridge property, "
"or provide your own setter method.",
self.name);
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
}
- (void)finishSetupForInstance
{
if (!_setupComplete && _instance) {
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData finishSetupForInstance]", nil);
_setupComplete = YES;
[_bridge registerModuleForFrameUpdates:_instance withModuleData:self];
[[NSNotificationCenter defaultCenter]
postNotificationName:RCTDidInitializeModuleNotification
object:_bridge
userInfo:@{@"module" : _instance, @"bridge" : RCTNullIfNil(_bridge.parentBridge)}];
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
}
- (void)setUpMethodQueue
{
if (_instance && !_methodQueue && _bridge.valid) {
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData setUpMethodQueue]", nil);
BOOL implementsMethodQueue = [_instance respondsToSelector:@selector(methodQueue)];
if (implementsMethodQueue && _bridge.valid) {
_methodQueue = _instance.methodQueue;
}
if (!_methodQueue && _bridge.valid) {
// Create new queue (store queueName, as it isn't retained by dispatch_queue)
_queueName = [NSString stringWithFormat:@"com.facebook.react.%@Queue", self.name];
_methodQueue = dispatch_queue_create(_queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
// assign it to the module
if (implementsMethodQueue) {
@try {
[(id)_instance setValue:_methodQueue forKey:@"methodQueue"];
} @catch (NSException *exception) {
RCTLogError(
@"%@ is returning nil for its methodQueue, which is not "
"permitted. You must either return a pre-initialized "
"queue, or @synthesize the methodQueue to let the bridge "
"create a queue for you.",
self.name);
}
}
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
}
- (void)calculateMethods
{
if (_methods && _methodsByName) {
return;
}
NSMutableArray<id<RCTBridgeMethod>> *moduleMethods = [NSMutableArray new];
NSMutableDictionary<NSString *, id<RCTBridgeMethod>> *moduleMethodsByName = [NSMutableDictionary new];
if ([_moduleClass instancesRespondToSelector:@selector(methodsToExport)]) {
[moduleMethods addObjectsFromArray:[self.instance methodsToExport]];
}
unsigned int methodCount;
Class cls = _moduleClass;
while (cls && cls != [NSObject class] && cls != [NSProxy class]) {
Method *methods = class_copyMethodList(object_getClass(cls), &methodCount);
for (unsigned int i = 0; i < methodCount; i++) {
Method method = methods[i];
SEL selector = method_getName(method);
if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) {
IMP imp = method_getImplementation(method);
auto exportedMethod = ((const RCTMethodInfo *(*)(id, SEL))imp)(_moduleClass, selector);
id<RCTBridgeMethod> moduleMethod = [[RCTModuleMethod alloc] initWithExportedMethod:exportedMethod
moduleClass:_moduleClass];
NSString *str = [NSString stringWithUTF8String:moduleMethod.JSMethodName];
[moduleMethodsByName setValue:moduleMethod forKey:str];
[moduleMethods addObject:moduleMethod];
}
}
free(methods);
cls = class_getSuperclass(cls);
}
_methods = [moduleMethods copy];
_methodsByName = [moduleMethodsByName copy];
}
#pragma mark - public getters
- (BOOL)hasInstance
{
std::unique_lock<std::mutex> lock(_instanceLock);
return _instance != nil;
}
- (id<RCTBridgeModule>)instance
{
if (!_setupComplete) {
RCT_PROFILE_BEGIN_EVENT(
RCTProfileTagAlways, ([NSString stringWithFormat:@"[RCTModuleData instanceForClass:%@]", _moduleClass]), nil);
if (_requiresMainQueueSetup) {
// The chances of deadlock here are low, because module init very rarely
// calls out to other threads, however we can't control when a module might
// get accessed by client code during bridge setup, and a very low risk of
// deadlock is better than a fairly high risk of an assertion being thrown.
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"[RCTModuleData instance] main thread setup", nil);
if (!RCTIsMainQueue()) {
RCTLogWarn(@"RCTBridge required dispatch_sync to load %@. This may lead to deadlocks", _moduleClass);
}
RCTUnsafeExecuteOnMainQueueSync(^{
[self setUpInstanceAndBridge];
});
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
} else {
[self setUpInstanceAndBridge];
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
return _instance;
}
- (NSString *)name
{
return RCTBridgeModuleNameForClass(_moduleClass);
}
- (NSArray<id<RCTBridgeMethod>> *)methods
{
[self calculateMethods];
return _methods;
}
- (NSDictionary<NSString *, id<RCTBridgeMethod>> *)methodsByName
{
[self calculateMethods];
return _methodsByName;
}
- (void)gatherConstants
{
if (_hasConstantsToExport && !_constantsToExport) {
RCT_PROFILE_BEGIN_EVENT(
RCTProfileTagAlways, ([NSString stringWithFormat:@"[RCTModuleData gatherConstants] %@", _moduleClass]), nil);
(void)[self instance];
if (_requiresMainQueueSetup) {
if (!RCTIsMainQueue()) {
RCTLogWarn(@"Required dispatch_sync to load constants for %@. This may lead to deadlocks", _moduleClass);
}
RCTUnsafeExecuteOnMainQueueSync(^{
self->_constantsToExport = [self->_instance constantsToExport] ?: @{};
});
} else {
_constantsToExport = [_instance constantsToExport] ?: @{};
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
}
- (NSDictionary<NSString *, id> *)exportedConstants
{
[self gatherConstants];
NSDictionary<NSString *, id> *constants = _constantsToExport;
_constantsToExport = nil; // Not needed anymore
return constants;
}
- (dispatch_queue_t)methodQueue
{
if (_bridge.valid) {
id instance = self.instance;
RCTAssert(_methodQueue != nullptr, @"Module %@ has no methodQueue (instance: %@)", self, instance);
}
return _methodQueue;
}
- (void)invalidate
{
_methodQueue = nil;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; name=\"%@\">", [self class], self, self.name];
}
@end

34
node_modules/react-native/React/Base/RCTModuleMethod.h generated vendored Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTBridgeMethod.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTNullability.h>
@class RCTBridge;
@interface RCTMethodArgument : NSObject
@property (nonatomic, copy, readonly) NSString *type;
@property (nonatomic, readonly) RCTNullability nullability;
@property (nonatomic, readonly) BOOL unused;
@end
@interface RCTModuleMethod : NSObject <RCTBridgeMethod>
@property (nonatomic, readonly) Class moduleClass;
@property (nonatomic, readonly) SEL selector;
- (instancetype)initWithExportedMethod:(const RCTMethodInfo *)exportMethod
moduleClass:(Class)moduleClass NS_DESIGNATED_INITIALIZER;
@end
RCT_EXTERN NSString *RCTParseMethodSignature(const char *input, NSArray<RCTMethodArgument *> **arguments);

615
node_modules/react-native/React/Base/RCTModuleMethod.mm generated vendored Normal file
View File

@ -0,0 +1,615 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTModuleMethod.h"
#import <objc/message.h>
#import "RCTAssert.h"
#import "RCTBridge+Private.h"
#import "RCTBridge.h"
#import "RCTConvert.h"
#import "RCTCxxConvert.h"
#import "RCTLog.h"
#import "RCTManagedPointer.h"
#import "RCTParserUtils.h"
#import "RCTProfile.h"
#import "RCTUtils.h"
typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);
/**
* Get the converter function for the specified type
*/
static SEL selectorForType(NSString *type)
{
const char *input = type.UTF8String;
return NSSelectorFromString([RCTParseType(&input) stringByAppendingString:@":"]);
}
@implementation RCTMethodArgument
- (instancetype)initWithType:(NSString *)type nullability:(RCTNullability)nullability unused:(BOOL)unused
{
if (self = [super init]) {
_type = [type copy];
_nullability = nullability;
_unused = unused;
}
return self;
}
@end
@implementation RCTModuleMethod {
Class _moduleClass;
const RCTMethodInfo *_methodInfo;
NSString *_JSMethodName;
SEL _selector;
NSInvocation *_invocation;
NSArray<RCTArgumentBlock> *_argumentBlocks;
NSMutableArray *_retainedObjects;
}
static void RCTLogArgumentError(RCTModuleMethod *method, NSUInteger index, id valueOrType, const char *issue)
{
RCTLogError(
@"Argument %tu (%@) of %@.%s %s",
index,
valueOrType,
RCTBridgeModuleNameForClass(method->_moduleClass),
method.JSMethodName,
issue);
}
RCT_NOT_IMPLEMENTED(-(instancetype)init)
RCT_EXTERN_C_BEGIN
// returns YES if the selector ends in a colon (indicating that there is at
// least one argument, and maybe more selector parts) or NO if it doesn't.
static BOOL RCTParseSelectorPart(const char **input, NSMutableString *selector)
{
NSString *selectorPart;
if (RCTParseSelectorIdentifier(input, &selectorPart)) {
[selector appendString:selectorPart];
}
RCTSkipWhitespace(input);
if (RCTReadChar(input, ':')) {
[selector appendString:@":"];
RCTSkipWhitespace(input);
return YES;
}
return NO;
}
static BOOL RCTParseUnused(const char **input)
{
return RCTReadString(input, "__attribute__((unused))") || RCTReadString(input, "__attribute__((__unused__))") ||
RCTReadString(input, "__unused");
}
static RCTNullability RCTParseNullability(const char **input)
{
if (RCTReadString(input, "nullable")) {
return RCTNullable;
} else if (RCTReadString(input, "nonnull")) {
return RCTNonnullable;
}
return RCTNullabilityUnspecified;
}
static RCTNullability RCTParseNullabilityPostfix(const char **input)
{
if (RCTReadString(input, "_Nullable") || RCTReadString(input, "__nullable")) {
return RCTNullable;
} else if (RCTReadString(input, "_Nonnull") || RCTReadString(input, "__nonnull")) {
return RCTNonnullable;
}
return RCTNullabilityUnspecified;
}
// returns YES if execution is safe to proceed (enqueue callback invocation), NO if callback has already been invoked
#if RCT_DEBUG
static BOOL checkCallbackMultipleInvocations(BOOL *didInvoke)
{
if (*didInvoke) {
RCTFatal(RCTErrorWithMessage(
@"Illegal callback invocation from native module. This callback type only permits a single invocation from native code."));
return NO;
} else {
*didInvoke = YES;
return YES;
}
}
#endif
NSString *RCTParseMethodSignature(const char *input, NSArray<RCTMethodArgument *> **arguments)
{
RCTSkipWhitespace(&input);
NSMutableArray *args;
NSMutableString *selector = [NSMutableString new];
while (RCTParseSelectorPart(&input, selector)) {
if (!args) {
args = [NSMutableArray new];
}
// Parse type
if (RCTReadChar(&input, '(')) {
RCTSkipWhitespace(&input);
// 5 cases that both nullable and __unused exist
// 1: foo:(nullable __unused id)foo 2: foo:(nullable id __unused)foo
// 3: foo:(__unused id _Nullable)foo 4: foo:(id __unused _Nullable)foo
// 5: foo:(id _Nullable __unused)foo
RCTNullability nullability = RCTParseNullability(&input);
RCTSkipWhitespace(&input);
BOOL unused = RCTParseUnused(&input);
RCTSkipWhitespace(&input);
NSString *type = RCTParseType(&input);
RCTSkipWhitespace(&input);
if (nullability == RCTNullabilityUnspecified) {
nullability = RCTParseNullabilityPostfix(&input);
RCTSkipWhitespace(&input);
if (!unused) {
unused = RCTParseUnused(&input);
RCTSkipWhitespace(&input);
if (unused && nullability == RCTNullabilityUnspecified) {
nullability = RCTParseNullabilityPostfix(&input);
RCTSkipWhitespace(&input);
}
}
} else if (!unused) {
unused = RCTParseUnused(&input);
RCTSkipWhitespace(&input);
}
[args addObject:[[RCTMethodArgument alloc] initWithType:type nullability:nullability unused:unused]];
RCTSkipWhitespace(&input);
RCTReadChar(&input, ')');
RCTSkipWhitespace(&input);
} else {
// Type defaults to id if unspecified
[args addObject:[[RCTMethodArgument alloc] initWithType:@"id" nullability:RCTNullable unused:NO]];
}
// Argument name
RCTParseArgumentIdentifier(&input, NULL);
RCTSkipWhitespace(&input);
}
*arguments = [args copy];
return selector;
}
RCT_EXTERN_C_END
- (instancetype)initWithExportedMethod:(const RCTMethodInfo *)exportedMethod moduleClass:(Class)moduleClass
{
if (self = [super init]) {
_moduleClass = moduleClass;
_methodInfo = exportedMethod;
}
return self;
}
- (void)processMethodSignature
{
NSArray<RCTMethodArgument *> *arguments;
_selector = NSSelectorFromString(RCTParseMethodSignature(_methodInfo->objcName, &arguments));
RCTAssert(_selector, @"%s is not a valid selector", _methodInfo->objcName);
// Create method invocation
NSMethodSignature *methodSignature = [_moduleClass instanceMethodSignatureForSelector:_selector];
RCTAssert(methodSignature, @"%s is not a recognized Objective-C method.", sel_getName(_selector));
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.selector = _selector;
_invocation = invocation;
NSMutableArray *retainedObjects = [NSMutableArray array];
_retainedObjects = retainedObjects;
// Process arguments
NSUInteger numberOfArguments = methodSignature.numberOfArguments;
NSMutableArray<RCTArgumentBlock> *argumentBlocks = [[NSMutableArray alloc] initWithCapacity:numberOfArguments - 2];
#if RCT_DEBUG
__weak RCTModuleMethod *weakSelf = self;
#endif
#define RCT_RETAINED_ARG_BLOCK(_logic) \
[argumentBlocks addObject:^(__unused __weak RCTBridge * bridge, NSUInteger index, id json) { \
_logic [invocation setArgument:&value atIndex:(index) + 2]; \
if (value) { \
[retainedObjects addObject:value]; \
} \
return YES; \
}]
#define __PRIMITIVE_CASE(_type, _nullable) \
{ \
isNullableType = _nullable; \
_type (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; \
[argumentBlocks addObject:^(__unused RCTBridge * bridge, NSUInteger index, id json) { \
_type value = convert([RCTConvert class], selector, json); \
[invocation setArgument:&value atIndex:(index) + 2]; \
return YES; \
}]; \
break; \
}
#define PRIMITIVE_CASE(_type) __PRIMITIVE_CASE(_type, NO)
#define NULLABLE_PRIMITIVE_CASE(_type) __PRIMITIVE_CASE(_type, YES)
// Explicitly copy the block
#define __COPY_BLOCK(block...) \
id value = [block copy]; \
if (value) { \
[retainedObjects addObject:value]; \
}
#if RCT_DEBUG
#define BLOCK_CASE(_block_args, _block) \
RCT_RETAINED_ARG_BLOCK(if (json && ![json isKindOfClass:[NSNumber class]]) { \
RCTLogArgumentError(weakSelf, index, json, "should be a function"); \
return NO; \
} __block BOOL didInvoke = NO; \
__COPY_BLOCK(^_block_args { \
if (checkCallbackMultipleInvocations(&didInvoke)) \
_block \
});)
#else
#define BLOCK_CASE(_block_args, _block) \
RCT_RETAINED_ARG_BLOCK(__COPY_BLOCK(^_block_args{ \
_block});)
#endif
for (NSUInteger i = 2; i < numberOfArguments; i++) {
const char *objcType = [methodSignature getArgumentTypeAtIndex:i];
BOOL isNullableType = NO;
RCTMethodArgument *argument = arguments[i - 2];
NSString *typeName = argument.type;
SEL selector = selectorForType(typeName);
if ([RCTConvert respondsToSelector:selector]) {
switch (objcType[0]) {
// Primitives
case _C_CHR:
PRIMITIVE_CASE(char)
case _C_UCHR:
PRIMITIVE_CASE(unsigned char)
case _C_SHT:
PRIMITIVE_CASE(short)
case _C_USHT:
PRIMITIVE_CASE(unsigned short)
case _C_INT:
PRIMITIVE_CASE(int)
case _C_UINT:
PRIMITIVE_CASE(unsigned int)
case _C_LNG:
PRIMITIVE_CASE(long)
case _C_ULNG:
PRIMITIVE_CASE(unsigned long)
case _C_LNG_LNG:
PRIMITIVE_CASE(long long)
case _C_ULNG_LNG:
PRIMITIVE_CASE(unsigned long long)
case _C_FLT:
PRIMITIVE_CASE(float)
case _C_DBL:
PRIMITIVE_CASE(double)
case _C_BOOL:
PRIMITIVE_CASE(BOOL)
case _C_SEL:
NULLABLE_PRIMITIVE_CASE(SEL)
case _C_CHARPTR:
NULLABLE_PRIMITIVE_CASE(const char *)
case _C_PTR:
NULLABLE_PRIMITIVE_CASE(void *)
case _C_ID: {
isNullableType = YES;
id (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend;
RCT_RETAINED_ARG_BLOCK(id value = convert([RCTConvert class], selector, json););
break;
}
case _C_STRUCT_B: {
NSMethodSignature *typeSignature = [RCTConvert methodSignatureForSelector:selector];
NSInvocation *typeInvocation = [NSInvocation invocationWithMethodSignature:typeSignature];
typeInvocation.selector = selector;
typeInvocation.target = [RCTConvert class];
[argumentBlocks addObject:^(__unused RCTBridge *bridge, NSUInteger index, id json) {
void *returnValue = malloc(typeSignature.methodReturnLength);
if (!returnValue) {
// CWE - 391 : Unchecked error condition
// https://www.cvedetails.com/cwe-details/391/Unchecked-Error-Condition.html
// https://eli.thegreenplace.net/2009/10/30/handling-out-of-memory-conditions-in-c
abort();
}
[typeInvocation setArgument:&json atIndex:2];
[typeInvocation invoke];
[typeInvocation getReturnValue:returnValue];
[invocation setArgument:returnValue atIndex:index + 2];
free(returnValue);
return YES;
}];
break;
}
default: {
static const char *blockType = @encode(__typeof__(^{
}));
if (!strcmp(objcType, blockType)) {
BLOCK_CASE((NSArray * args), { [bridge enqueueCallback:json args:args]; });
} else {
RCTLogError(@"Unsupported argument type '%@' in method %@.", typeName, [self methodName]);
}
}
}
} else if ([typeName isEqualToString:@"RCTResponseSenderBlock"]) {
BLOCK_CASE((NSArray * args), { [bridge enqueueCallback:json args:args]; });
} else if ([typeName isEqualToString:@"RCTResponseErrorBlock"]) {
BLOCK_CASE((NSError * error), { [bridge enqueueCallback:json args:@[ RCTJSErrorFromNSError(error) ]]; });
} else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) {
RCTAssert(
i == numberOfArguments - 2,
@"The RCTPromiseResolveBlock must be the second to last parameter in %@",
[self methodName]);
BLOCK_CASE((id result), { [bridge enqueueCallback:json args:result ? @[ result ] : @[]]; });
} else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) {
RCTAssert(
i == numberOfArguments - 1, @"The RCTPromiseRejectBlock must be the last parameter in %@", [self methodName]);
BLOCK_CASE((NSString * code, NSString * message, NSError * error), {
NSDictionary *errorJSON = RCTJSErrorFromCodeMessageAndNSError(code, message, error);
[bridge enqueueCallback:json args:@[ errorJSON ]];
});
} else if ([typeName hasPrefix:@"JS::"]) {
NSString *selectorNameForCxxType =
[[typeName stringByReplacingOccurrencesOfString:@"::" withString:@"_"] stringByAppendingString:@":"];
selector = NSSelectorFromString(selectorNameForCxxType);
[argumentBlocks addObject:^(__unused RCTBridge *bridge, NSUInteger index, id json) {
RCTManagedPointer *(*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend;
RCTManagedPointer *box = convert([RCTCxxConvert class], selector, json);
void *pointer = box.voidPointer;
[invocation setArgument:&pointer atIndex:index + 2];
[retainedObjects addObject:box];
return YES;
}];
} else {
// Unknown argument type
RCTLogError(
@"Unknown argument type '%@' in method %@. Extend RCTConvert to support this type.",
typeName,
[self methodName]);
}
#if RCT_DEBUG
RCTNullability nullability = argument.nullability;
if (!isNullableType) {
if (nullability == RCTNullable) {
RCTLogArgumentError(
weakSelf,
i - 2,
typeName,
"is marked as "
"nullable, but is not a nullable type.");
}
nullability = RCTNonnullable;
}
/**
* Special case - Numbers are not nullable in Android, so we
* don't support this for now. In future we may allow it.
*/
if ([typeName isEqualToString:@"NSNumber"]) {
BOOL unspecified = (nullability == RCTNullabilityUnspecified);
if (!argument.unused && (nullability == RCTNullable || unspecified)) {
RCTLogArgumentError(
weakSelf,
i - 2,
typeName,
[unspecified ? @"has unspecified nullability" : @"is marked as nullable"
stringByAppendingString:@" but React requires that all NSNumber "
"arguments are explicitly marked as `nonnull` to ensure "
"compatibility with Android."]
.UTF8String);
}
nullability = RCTNonnullable;
}
if (nullability == RCTNonnullable) {
RCTArgumentBlock oldBlock = argumentBlocks[i - 2];
argumentBlocks[i - 2] = ^(RCTBridge *bridge, NSUInteger index, id json) {
if (json != nil) {
if (!oldBlock(bridge, index, json)) {
return NO;
}
if (isNullableType) {
// Check converted value wasn't null either, as method probably
// won't gracefully handle a nil value for a nonull argument
void *value;
[invocation getArgument:&value atIndex:index + 2];
if (value == NULL) {
return NO;
}
}
return YES;
}
RCTLogArgumentError(weakSelf, index, typeName, "must not be null");
return NO;
};
}
#endif
}
#if RCT_DEBUG
const char *objcType = _invocation.methodSignature.methodReturnType;
if (_methodInfo->isSync && objcType[0] != _C_ID) {
RCTLogError(
@"Return type of %@.%s should be (id) as the method is \"sync\"",
RCTBridgeModuleNameForClass(_moduleClass),
self.JSMethodName);
}
#endif
_argumentBlocks = argumentBlocks;
}
- (SEL)selector
{
if (_selector == NULL) {
RCT_PROFILE_BEGIN_EVENT(
RCTProfileTagAlways,
@"",
(@{@"module" : NSStringFromClass(_moduleClass), @"method" : @(_methodInfo->objcName)}));
[self processMethodSignature];
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
return _selector;
}
- (const char *)JSMethodName
{
NSString *methodName = _JSMethodName;
if (!methodName) {
const char *jsName = _methodInfo->jsName;
if (jsName && strlen(jsName) > 0) {
methodName = @(jsName);
} else {
methodName = @(_methodInfo->objcName);
NSRange colonRange = [methodName rangeOfString:@":"];
if (colonRange.location != NSNotFound) {
methodName = [methodName substringToIndex:colonRange.location];
}
methodName = [methodName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
RCTAssert(
methodName.length,
@"%s is not a valid JS function name, please"
" supply an alternative using RCT_REMAP_METHOD()",
_methodInfo->objcName);
}
_JSMethodName = methodName;
}
return methodName.UTF8String;
}
- (RCTFunctionType)functionType
{
if (strstr(_methodInfo->objcName, "RCTPromise") != NULL) {
RCTAssert(!_methodInfo->isSync, @"Promises cannot be used in sync functions");
return RCTFunctionTypePromise;
} else if (_methodInfo->isSync) {
return RCTFunctionTypeSync;
} else {
return RCTFunctionTypeNormal;
}
}
- (id)invokeWithBridge:(RCTBridge *)bridge module:(id)module arguments:(NSArray *)arguments
{
if (_argumentBlocks == nil) {
[self processMethodSignature];
}
#if RCT_DEBUG
// Sanity check
RCTAssert([module class] == _moduleClass, @"Attempted to invoke method \
%@ on a module of class %@", [self methodName], [module class]);
// Safety check
if (arguments.count != _argumentBlocks.count) {
NSInteger actualCount = arguments.count;
NSInteger expectedCount = _argumentBlocks.count;
// Subtract the implicit Promise resolver and rejecter functions for implementations of async functions
if (self.functionType == RCTFunctionTypePromise) {
actualCount -= 2;
expectedCount -= 2;
}
RCTLogError(
@"%@.%s was called with %lld arguments but expects %lld arguments. "
@"If you haven\'t changed this method yourself, this usually means that "
@"your versions of the native code and JavaScript code are out of sync. "
@"Updating both should make this error go away.",
RCTBridgeModuleNameForClass(_moduleClass),
self.JSMethodName,
(long long)actualCount,
(long long)expectedCount);
return nil;
}
#endif
// Set arguments
NSUInteger index = 0;
for (id json in arguments) {
RCTArgumentBlock block = _argumentBlocks[index];
if (!block(bridge, index, RCTNilIfNull(json))) {
// Invalid argument, abort
RCTLogArgumentError(self, index, json, "could not be processed. Aborting method call.");
return nil;
}
index++;
}
// Invoke method
#ifdef RCT_MAIN_THREAD_WATCH_DOG_THRESHOLD
if (RCTIsMainQueue()) {
CFTimeInterval start = CACurrentMediaTime();
[_invocation invokeWithTarget:module];
CFTimeInterval duration = CACurrentMediaTime() - start;
if (duration > RCT_MAIN_THREAD_WATCH_DOG_THRESHOLD) {
RCTLogWarn(
@"Main Thread Watchdog: Invocation of %@ blocked the main thread for %dms. "
"Consider using background-threaded modules and asynchronous calls "
"to spend less time on the main thread and keep the app's UI responsive.",
[self methodName],
(int)(duration * 1000));
}
} else {
[_invocation invokeWithTarget:module];
}
#else
[_invocation invokeWithTarget:module];
#endif
[_retainedObjects removeAllObjects];
if (_methodInfo->isSync) {
void *returnValue;
[_invocation getReturnValue:&returnValue];
return (__bridge id)returnValue;
}
return nil;
}
- (NSString *)methodName
{
if (!_selector) {
[self processMethodSignature];
}
return [NSString stringWithFormat:@"-[%@ %s]", _moduleClass, sel_getName(_selector)];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; exports %@ as %s(); type: %s>",
[self class],
self,
[self methodName],
self.JSMethodName,
RCTFunctionDescriptorFromType(self.functionType)];
}
@end

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTMultipartStreamReader.h>
typedef void (^RCTMultipartDataTaskCallback)(
NSInteger statusCode,
NSDictionary *headers,
NSData *content,
NSError *error,
BOOL done);
@interface RCTMultipartDataTask : NSObject
- (instancetype)initWithURL:(NSURL *)url
partHandler:(RCTMultipartDataTaskCallback)partHandler
progressHandler:(RCTMultipartProgressCallback)progressHandler;
- (void)startTask;
@end

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTMultipartDataTask.h"
@interface RCTMultipartDataTask () <NSURLSessionDataDelegate, NSURLSessionDataDelegate>
@end
@implementation RCTMultipartDataTask {
NSURL *_url;
RCTMultipartDataTaskCallback _partHandler;
RCTMultipartProgressCallback _progressHandler;
NSInteger _statusCode;
NSDictionary *_headers;
NSString *_boundary;
NSMutableData *_data;
}
- (instancetype)initWithURL:(NSURL *)url
partHandler:(RCTMultipartDataTaskCallback)partHandler
progressHandler:(RCTMultipartProgressCallback)progressHandler
{
if (self = [super init]) {
_url = url;
_partHandler = [partHandler copy];
_progressHandler = [progressHandler copy];
}
return self;
}
- (void)startTask
{
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self
delegateQueue:nil];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url];
[request addValue:@"multipart/mixed" forHTTPHeaderField:@"Accept"];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
[session finishTasksAndInvalidate];
}
- (void)URLSession:(__unused NSURLSession *)session
dataTask:(__unused NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
_headers = [httpResponse allHeaderFields];
_statusCode = [httpResponse statusCode];
NSString *contentType = @"";
for (NSString *key in [_headers keyEnumerator]) {
if ([[key lowercaseString] isEqualToString:@"content-type"]) {
contentType = [_headers valueForKey:key];
break;
}
}
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:@"multipart/mixed;.*boundary=\"([^\"]+)\""
options:0
error:nil];
NSTextCheckingResult *match = [regex firstMatchInString:contentType
options:0
range:NSMakeRange(0, contentType.length)];
if (match) {
_boundary = [contentType substringWithRange:[match rangeAtIndex:1]];
completionHandler(NSURLSessionResponseBecomeStream);
return;
}
}
// In case the server doesn't support multipart/mixed responses, fallback to normal download
_data = [[NSMutableData alloc] initWithCapacity:1024 * 1024];
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(__unused NSURLSession *)session
task:(__unused NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
if (_partHandler) {
_partHandler(_statusCode, _headers, _data, error, YES);
}
}
- (void)URLSession:(__unused NSURLSession *)session
dataTask:(__unused NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
[_data appendData:data];
}
- (void)URLSession:(__unused NSURLSession *)session
dataTask:(__unused NSURLSessionDataTask *)dataTask
didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask
{
[streamTask captureStreams];
}
- (void)URLSession:(__unused NSURLSession *)session
streamTask:(__unused NSURLSessionStreamTask *)streamTask
didBecomeInputStream:(NSInputStream *)inputStream
outputStream:(__unused NSOutputStream *)outputStream
{
RCTMultipartStreamReader *reader = [[RCTMultipartStreamReader alloc] initWithInputStream:inputStream
boundary:_boundary];
RCTMultipartDataTaskCallback partHandler = _partHandler;
_partHandler = nil;
NSInteger statusCode = _statusCode;
BOOL completed = [reader
readAllPartsWithCompletionCallback:^(NSDictionary *headers, NSData *content, BOOL done) {
partHandler(statusCode, headers, content, nil, done);
}
progressCallback:_progressHandler];
if (!completed) {
partHandler(
statusCode, nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:nil], YES);
}
}
@end

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
typedef void (^RCTMultipartCallback)(NSDictionary *headers, NSData *content, BOOL done);
typedef void (^RCTMultipartProgressCallback)(NSDictionary *headers, NSNumber *loaded, NSNumber *total);
// RCTMultipartStreamReader can be used to parse responses with Content-Type: multipart/mixed
// See https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
@interface RCTMultipartStreamReader : NSObject
- (instancetype)initWithInputStream:(NSInputStream *)stream boundary:(NSString *)boundary;
- (BOOL)readAllPartsWithCompletionCallback:(RCTMultipartCallback)callback
progressCallback:(RCTMultipartProgressCallback)progressCallback;
@end

View File

@ -0,0 +1,168 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTMultipartStreamReader.h"
#import <QuartzCore/CAAnimation.h>
#define CRLF @"\r\n"
@implementation RCTMultipartStreamReader {
__strong NSInputStream *_stream;
__strong NSString *_boundary;
CFTimeInterval _lastDownloadProgress;
}
- (instancetype)initWithInputStream:(NSInputStream *)stream boundary:(NSString *)boundary
{
if (self = [super init]) {
_stream = stream;
_boundary = boundary;
_lastDownloadProgress = CACurrentMediaTime();
}
return self;
}
- (NSDictionary *)parseHeaders:(NSData *)data
{
NSMutableDictionary *headers = [NSMutableDictionary new];
NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSArray<NSString *> *lines = [text componentsSeparatedByString:CRLF];
for (NSString *line in lines) {
NSUInteger location = [line rangeOfString:@":"].location;
if (location == NSNotFound) {
continue;
}
NSString *key = [line substringToIndex:location];
NSString *value = [[line substringFromIndex:location + 1]
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[headers setValue:value forKey:key];
}
return headers;
}
- (void)emitChunk:(NSData *)data headers:(NSDictionary *)headers callback:(RCTMultipartCallback)callback done:(BOOL)done
{
NSData *marker = [CRLF CRLF dataUsingEncoding:NSUTF8StringEncoding];
NSRange range = [data rangeOfData:marker options:0 range:NSMakeRange(0, data.length)];
if (range.location == NSNotFound) {
callback(nil, data, done);
} else if (headers != nil) {
// If headers were parsed already just use that to avoid doing it twice.
NSInteger bodyStart = range.location + marker.length;
NSData *bodyData = [data subdataWithRange:NSMakeRange(bodyStart, data.length - bodyStart)];
callback(headers, bodyData, done);
} else {
NSData *headersData = [data subdataWithRange:NSMakeRange(0, range.location)];
NSInteger bodyStart = range.location + marker.length;
NSData *bodyData = [data subdataWithRange:NSMakeRange(bodyStart, data.length - bodyStart)];
callback([self parseHeaders:headersData], bodyData, done);
}
}
- (void)emitProgress:(NSDictionary *)headers
contentLength:(NSUInteger)contentLength
final:(BOOL)final
callback:(RCTMultipartProgressCallback)callback
{
if (headers == nil) {
return;
}
// Throttle progress events so we don't send more that around 60 per second.
CFTimeInterval currentTime = CACurrentMediaTime();
NSInteger headersContentLength = headers[@"Content-Length"] != nil ? [headers[@"Content-Length"] integerValue] : 0;
if (callback && (currentTime - _lastDownloadProgress > 0.016 || final)) {
_lastDownloadProgress = currentTime;
callback(headers, @(headersContentLength), @(contentLength));
}
}
- (BOOL)readAllPartsWithCompletionCallback:(RCTMultipartCallback)callback
progressCallback:(RCTMultipartProgressCallback)progressCallback
{
NSInteger chunkStart = 0;
NSInteger bytesSeen = 0;
NSData *delimiter =
[[NSString stringWithFormat:@"%@--%@%@", CRLF, _boundary, CRLF] dataUsingEncoding:NSUTF8StringEncoding];
NSData *closeDelimiter =
[[NSString stringWithFormat:@"%@--%@--%@", CRLF, _boundary, CRLF] dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *content = [[NSMutableData alloc] initWithCapacity:1];
NSDictionary *currentHeaders = nil;
NSUInteger currentHeadersLength = 0;
const NSUInteger bufferLen = 4 * 1024;
uint8_t buffer[bufferLen];
[_stream open];
while (true) {
BOOL isCloseDelimiter = NO;
// Search only a subset of chunk that we haven't seen before + few bytes
// to allow for the edge case when the delimiter is cut by read call
NSInteger searchStart = MAX(bytesSeen - (NSInteger)closeDelimiter.length, chunkStart);
NSRange remainingBufferRange = NSMakeRange(searchStart, content.length - searchStart);
// Check for delimiters.
NSRange range = [content rangeOfData:delimiter options:0 range:remainingBufferRange];
if (range.location == NSNotFound) {
isCloseDelimiter = YES;
range = [content rangeOfData:closeDelimiter options:0 range:remainingBufferRange];
}
if (range.location == NSNotFound) {
if (currentHeaders == nil) {
// Check for the headers delimiter.
NSData *headersMarker = [CRLF CRLF dataUsingEncoding:NSUTF8StringEncoding];
NSRange headersRange = [content rangeOfData:headersMarker options:0 range:remainingBufferRange];
if (headersRange.location != NSNotFound) {
NSData *headersData = [content subdataWithRange:NSMakeRange(chunkStart, headersRange.location - chunkStart)];
currentHeadersLength = headersData.length;
currentHeaders = [self parseHeaders:headersData];
}
} else {
// When headers are loaded start sending progress callbacks.
[self emitProgress:currentHeaders
contentLength:content.length - currentHeadersLength
final:NO
callback:progressCallback];
}
bytesSeen = content.length;
NSInteger bytesRead = [_stream read:buffer maxLength:bufferLen];
if (bytesRead <= 0 || _stream.streamError) {
return NO;
}
[content appendBytes:buffer length:bytesRead];
continue;
}
NSInteger chunkEnd = range.location;
NSInteger length = chunkEnd - chunkStart;
bytesSeen = chunkEnd;
// Ignore preamble
if (chunkStart > 0) {
NSData *chunk = [content subdataWithRange:NSMakeRange(chunkStart, length)];
[self emitProgress:currentHeaders
contentLength:chunk.length - currentHeadersLength
final:YES
callback:progressCallback];
[self emitChunk:chunk headers:currentHeaders callback:callback done:isCloseDelimiter];
currentHeaders = nil;
currentHeadersLength = 0;
}
if (isCloseDelimiter) {
return YES;
}
chunkStart = chunkEnd + delimiter.length;
}
}
@end

14
node_modules/react-native/React/Base/RCTNullability.h generated vendored Normal file
View File

@ -0,0 +1,14 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSUInteger, RCTNullability) {
RCTNullabilityUnspecified,
RCTNullable,
RCTNonnullable,
};

30
node_modules/react-native/React/Base/RCTParserUtils.h generated vendored Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTDefines.h>
@interface RCTParserUtils : NSObject
/**
* Generic utility functions for parsing Objective-C source code.
*/
RCT_EXTERN BOOL RCTReadChar(const char **input, char c);
RCT_EXTERN BOOL RCTReadString(const char **input, const char *string);
RCT_EXTERN void RCTSkipWhitespace(const char **input);
RCT_EXTERN BOOL RCTParseSelectorIdentifier(const char **input, NSString **string);
RCT_EXTERN BOOL RCTParseArgumentIdentifier(const char **input, NSString **string);
/**
* Parse an Objective-C type into a form that can be used by RCTConvert.
* This doesn't really belong here, but it's used by both RCTConvert and
* RCTModuleMethod, which makes it difficult to find a better home for it.
*/
RCT_EXTERN NSString *RCTParseType(const char **input);
@end

137
node_modules/react-native/React/Base/RCTParserUtils.m generated vendored Normal file
View File

@ -0,0 +1,137 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTParserUtils.h"
#import "RCTLog.h"
@implementation RCTParserUtils
BOOL RCTReadChar(const char **input, char c)
{
if (**input == c) {
(*input)++;
return YES;
}
return NO;
}
BOOL RCTReadString(const char **input, const char *string)
{
int i;
for (i = 0; string[i] != 0; i++) {
if (string[i] != (*input)[i]) {
return NO;
}
}
*input += i;
return YES;
}
void RCTSkipWhitespace(const char **input)
{
while (isspace(**input)) {
(*input)++;
}
}
static BOOL RCTIsIdentifierHead(const char c)
{
return isalpha(c) || c == '_';
}
static BOOL RCTIsIdentifierTail(const char c)
{
return isalnum(c) || c == '_';
}
BOOL RCTParseArgumentIdentifier(const char **input, NSString **string)
{
const char *start = *input;
do {
if (!RCTIsIdentifierHead(**input)) {
return NO;
}
(*input)++;
while (RCTIsIdentifierTail(**input)) {
(*input)++;
}
// allow namespace resolution operator
} while (RCTReadString(input, "::"));
if (string) {
*string = [[NSString alloc] initWithBytes:start length:(NSInteger)(*input - start) encoding:NSASCIIStringEncoding];
}
return YES;
}
BOOL RCTParseSelectorIdentifier(const char **input, NSString **string)
{
const char *start = *input;
if (!RCTIsIdentifierHead(**input)) {
return NO;
}
(*input)++;
while (RCTIsIdentifierTail(**input)) {
(*input)++;
}
if (string) {
*string = [[NSString alloc] initWithBytes:start length:(NSInteger)(*input - start) encoding:NSASCIIStringEncoding];
}
return YES;
}
static BOOL RCTIsCollectionType(NSString *type)
{
static NSSet *collectionTypes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
collectionTypes = [[NSSet alloc] initWithObjects:@"NSArray", @"NSSet", @"NSDictionary", nil];
});
return [collectionTypes containsObject:type];
}
NSString *RCTParseType(const char **input)
{
NSString *type;
RCTParseArgumentIdentifier(input, &type);
RCTSkipWhitespace(input);
if (RCTReadChar(input, '<')) {
RCTSkipWhitespace(input);
NSString *subtype = RCTParseType(input);
if (RCTIsCollectionType(type)) {
if ([type isEqualToString:@"NSDictionary"]) {
// Dictionaries have both a key *and* value type, but the key type has
// to be a string for JSON, so we only care about the value type
if (RCT_DEBUG && ![subtype isEqualToString:@"NSString"]) {
RCTLogError(@"%@ is not a valid key type for a JSON dictionary", subtype);
}
RCTSkipWhitespace(input);
RCTReadChar(input, ',');
RCTSkipWhitespace(input);
subtype = RCTParseType(input);
}
if (![subtype isEqualToString:@"id"]) {
type = [type stringByReplacingCharactersInRange:(NSRange){0, 2 /* "NS" */} withString:subtype];
}
} else {
// It's a protocol rather than a generic collection - ignore it
}
RCTSkipWhitespace(input);
RCTReadChar(input, '>');
}
RCTSkipWhitespace(input);
if (!RCTReadChar(input, '*')) {
RCTReadChar(input, '&');
}
return type;
}
@end

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
// Keep this in sync with _labelsForTags
typedef NS_ENUM(NSUInteger, RCTPLTag) {
RCTPLScriptDownload = 0,
RCTPLScriptExecution,
RCTPLRAMBundleLoad,
RCTPLRAMStartupCodeSize,
RCTPLRAMStartupNativeRequires,
RCTPLRAMStartupNativeRequiresCount,
RCTPLRAMNativeRequires,
RCTPLRAMNativeRequiresCount,
RCTPLNativeModuleInit,
RCTPLNativeModuleMainThread,
RCTPLNativeModulePrepareConfig,
RCTPLNativeModuleMainThreadUsesCount,
RCTPLNativeModuleSetup,
RCTPLTurboModuleSetup,
RCTPLJSCWrapperOpenLibrary,
RCTPLBridgeStartup,
RCTPLTTI,
RCTPLBundleSize,
RCTPLSize // This is used to count the size
};
@interface RCTPerformanceLogger : NSObject
/**
* Starts measuring a metric with the given tag.
* Overrides previous value if the measurement has been already started.
* If RCTProfile is enabled it also begins appropriate async event.
* All work is scheduled on the background queue so this doesn't block current thread.
*/
- (void)markStartForTag:(RCTPLTag)tag;
/**
* Stops measuring a metric with given tag.
* Checks if RCTPerformanceLoggerStart() has been called before
* and doesn't do anything and log a message if it hasn't.
* If RCTProfile is enabled it also ends appropriate async event.
* All work is scheduled on the background queue so this doesn't block current thread.
*/
- (void)markStopForTag:(RCTPLTag)tag;
/**
* Sets given value for a metric with given tag.
* All work is scheduled on the background queue so this doesn't block current thread.
*/
- (void)setValue:(int64_t)value forTag:(RCTPLTag)tag;
/**
* Adds given value to the current value for a metric with given tag.
* All work is scheduled on the background queue so this doesn't block current thread.
*/
- (void)addValue:(int64_t)value forTag:(RCTPLTag)tag;
/**
* Starts an additional measurement for a metric with given tag.
* It doesn't override previous measurement, instead it'll append a new value
* to the old one.
* All work is scheduled on the background queue so this doesn't block current thread.
*/
- (void)appendStartForTag:(RCTPLTag)tag;
/**
* Stops measurement and appends the result to the metric with given tag.
* Checks if RCTPerformanceLoggerAppendStart() has been called before
* and doesn't do anything and log a message if it hasn't.
* All work is scheduled on the background queue so this doesn't block current thread.
*/
- (void)appendStopForTag:(RCTPLTag)tag;
/**
* Returns an array with values for all tags.
* Use RCTPLTag to go over the array, there's a pair of values
* for each tag: start and stop (with indexes 2 * tag and 2 * tag + 1).
*/
- (NSArray<NSNumber *> *)valuesForTags;
/**
* Returns a duration in ms (stop_time - start_time) for given RCTPLTag.
*/
- (int64_t)durationForTag:(RCTPLTag)tag;
/**
* Returns a value for given RCTPLTag.
*/
- (int64_t)valueForTag:(RCTPLTag)tag;
/**
* Returns an array with values for all tags.
* Use RCTPLTag to go over the array.
*/
- (NSArray<NSString *> *)labelsForTags;
@end

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <QuartzCore/QuartzCore.h>
#import "RCTLog.h"
#import "RCTPerformanceLogger.h"
#import "RCTProfile.h"
#import "RCTRootView.h"
@interface RCTPerformanceLogger () {
int64_t _data[RCTPLSize][2];
NSUInteger _cookies[RCTPLSize];
}
@property (nonatomic, copy) NSArray<NSString *> *labelsForTags;
@end
@implementation RCTPerformanceLogger
- (instancetype)init
{
if (self = [super init]) {
// Keep this in sync with RCTPLTag
_labelsForTags = @[
@"ScriptDownload",
@"ScriptExecution",
@"RAMBundleLoad",
@"RAMStartupCodeSize",
@"RAMStartupNativeRequires",
@"RAMStartupNativeRequiresCount",
@"RAMNativeRequires",
@"RAMNativeRequiresCount",
@"NativeModuleInit",
@"NativeModuleMainThread",
@"NativeModulePrepareConfig",
@"NativeModuleMainThreadUsesCount",
@"NativeModuleSetup",
@"TurboModuleSetup",
@"JSCWrapperOpenLibrary",
@"BridgeStartup",
@"RootViewTTI",
@"BundleSize",
];
}
return self;
}
- (void)markStartForTag:(RCTPLTag)tag
{
#if RCT_PROFILE
if (RCTProfileIsProfiling()) {
NSString *label = _labelsForTags[tag];
_cookies[tag] = RCTProfileBeginAsyncEvent(RCTProfileTagAlways, label, nil);
}
#endif
_data[tag][0] = CACurrentMediaTime() * 1000;
_data[tag][1] = 0;
}
- (void)markStopForTag:(RCTPLTag)tag
{
#if RCT_PROFILE
if (RCTProfileIsProfiling()) {
NSString *label = _labelsForTags[tag];
RCTProfileEndAsyncEvent(RCTProfileTagAlways, @"native", _cookies[tag], label, @"RCTPerformanceLogger");
}
#endif
if (_data[tag][0] != 0 && _data[tag][1] == 0) {
_data[tag][1] = CACurrentMediaTime() * 1000;
} else {
RCTLogInfo(@"Unbalanced calls start/end for tag %li", (unsigned long)tag);
}
}
- (void)setValue:(int64_t)value forTag:(RCTPLTag)tag
{
_data[tag][0] = 0;
_data[tag][1] = value;
}
- (void)addValue:(int64_t)value forTag:(RCTPLTag)tag
{
_data[tag][0] = 0;
_data[tag][1] += value;
}
- (void)appendStartForTag:(RCTPLTag)tag
{
_data[tag][0] = CACurrentMediaTime() * 1000;
}
- (void)appendStopForTag:(RCTPLTag)tag
{
if (_data[tag][0] != 0) {
_data[tag][1] += CACurrentMediaTime() * 1000 - _data[tag][0];
_data[tag][0] = 0;
} else {
RCTLogInfo(@"Unbalanced calls start/end for tag %li", (unsigned long)tag);
}
}
- (NSArray<NSNumber *> *)valuesForTags
{
NSMutableArray *result = [NSMutableArray array];
for (NSUInteger index = 0; index < RCTPLSize; index++) {
[result addObject:@(_data[index][0])];
[result addObject:@(_data[index][1])];
}
return result;
}
- (int64_t)durationForTag:(RCTPLTag)tag
{
return _data[tag][1] - _data[tag][0];
}
- (int64_t)valueForTag:(RCTPLTag)tag
{
return _data[tag][1];
}
@end

View File

@ -0,0 +1,14 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTDefines.h>
// In debug builds, the red box is enabled by default but it is further
// customizable using this method. However, this method only has an effect in
// builds where RCTRedBox is actually compiled in.
RCT_EXTERN void RCTRedBoxSetEnabled(BOOL enabled);
RCT_EXTERN BOOL RCTRedBoxGetEnabled(void);

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTRedBoxSetEnabled.h"
#if RCT_DEV
static BOOL redBoxEnabled = YES;
#else
static BOOL redBoxEnabled = NO;
#endif
void RCTRedBoxSetEnabled(BOOL enabled)
{
redBoxEnabled = enabled;
}
BOOL RCTRedBoxGetEnabled()
{
return redBoxEnabled;
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTDefines.h>
/**
* A protocol which should be conformed to in order to be notified of RN reload events. These events can be
* created by CMD+R or dev menu during development, or anywhere the trigger is exposed to JS.
* The listener must also register itself using the method below.
*/
@protocol RCTReloadListener
- (void)didReceiveReloadCommand;
@end
/**
* Registers a weakly-held observer of RN reload events.
*/
RCT_EXTERN void RCTRegisterReloadCommandListener(id<RCTReloadListener> listener);
/**
* Triggers a reload for all current listeners. Replaces [_bridge reload].
*/
RCT_EXTERN void RCTTriggerReloadCommandListeners(NSString *reason);
/**
* This notification fires anytime RCTTriggerReloadCommandListeners() is called.
*/
RCT_EXTERN NSString *const RCTTriggerReloadCommandNotification;
RCT_EXTERN NSString *const RCTTriggerReloadCommandReasonKey;
RCT_EXTERN NSString *const RCTTriggerReloadCommandBundleURLKey;
RCT_EXTERN void RCTReloadCommandSetBundleURL(NSURL *URL);

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTReloadCommand.h"
#import "RCTAssert.h"
#import "RCTKeyCommands.h"
#import "RCTUtils.h"
static NSHashTable<id<RCTReloadListener>> *listeners;
static NSLock *listenersLock;
static NSURL *bundleURL;
NSString *const RCTTriggerReloadCommandNotification = @"RCTTriggerReloadCommandNotification";
NSString *const RCTTriggerReloadCommandReasonKey = @"reason";
NSString *const RCTTriggerReloadCommandBundleURLKey = @"bundleURL";
void RCTRegisterReloadCommandListener(id<RCTReloadListener> listener)
{
if (!listenersLock) {
listenersLock = [NSLock new];
}
[listenersLock lock];
if (!listeners) {
listeners = [NSHashTable weakObjectsHashTable];
}
#if RCT_DEV
RCTAssertMainQueue(); // because registerKeyCommandWithInput: must be called on the main thread
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"r"
modifierFlags:UIKeyModifierCommand
action:^(__unused UIKeyCommand *command) {
RCTTriggerReloadCommandListeners(@"Command + R");
}];
});
#endif
[listeners addObject:listener];
[listenersLock unlock];
}
void RCTTriggerReloadCommandListeners(NSString *reason)
{
[listenersLock lock];
[[NSNotificationCenter defaultCenter] postNotificationName:RCTTriggerReloadCommandNotification
object:nil
userInfo:@{
RCTTriggerReloadCommandReasonKey : RCTNullIfNil(reason),
RCTTriggerReloadCommandBundleURLKey : RCTNullIfNil(bundleURL)
}];
for (id<RCTReloadListener> l in [listeners allObjects]) {
[l didReceiveReloadCommand];
}
[listenersLock unlock];
}
void RCTReloadCommandSetBundleURL(NSURL *URL)
{
bundleURL = URL;
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTInvalidating.h>
#import <React/RCTRootView.h>
#import <React/RCTView.h>
@class RCTBridge;
@class RCTTouchHandler;
@interface RCTRootContentView : RCTView <RCTInvalidating>
@property (nonatomic, readonly, weak) RCTBridge *bridge;
@property (nonatomic, readonly, assign) BOOL contentHasAppeared;
@property (nonatomic, readonly, strong) RCTTouchHandler *touchHandler;
@property (nonatomic, readonly, assign) CGSize availableSize;
@property (nonatomic, assign) BOOL passThroughTouches;
@property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility;
- (instancetype)initWithFrame:(CGRect)frame
bridge:(RCTBridge *)bridge
reactTag:(NSNumber *)reactTag
sizeFlexiblity:(RCTRootViewSizeFlexibility)sizeFlexibility NS_DESIGNATED_INITIALIZER;
@end

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTRootContentView.h"
#import "RCTBridge.h"
#import "RCTPerformanceLogger.h"
#import "RCTRootView.h"
#import "RCTRootViewInternal.h"
#import "RCTTouchHandler.h"
#import "RCTUIManager.h"
#import "UIView+React.h"
@implementation RCTRootContentView
- (instancetype)initWithFrame:(CGRect)frame
bridge:(RCTBridge *)bridge
reactTag:(NSNumber *)reactTag
sizeFlexiblity:(RCTRootViewSizeFlexibility)sizeFlexibility
{
if ((self = [super initWithFrame:frame])) {
_bridge = bridge;
self.reactTag = reactTag;
_sizeFlexibility = sizeFlexibility;
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
[_touchHandler attachToView:self];
[_bridge.uiManager registerRootView:self];
}
return self;
}
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (nonnull NSCoder *)aDecoder)
- (void)layoutSubviews
{
[super layoutSubviews];
[self updateAvailableSize];
}
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
{
[super insertReactSubview:subview atIndex:atIndex];
[_bridge.performanceLogger markStopForTag:RCTPLTTI];
dispatch_async(dispatch_get_main_queue(), ^{
if (!self->_contentHasAppeared) {
self->_contentHasAppeared = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:RCTContentDidAppearNotification object:self.superview];
}
});
}
- (void)setSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
{
if (_sizeFlexibility == sizeFlexibility) {
return;
}
_sizeFlexibility = sizeFlexibility;
[self setNeedsLayout];
}
- (CGSize)availableSize
{
CGSize size = self.bounds.size;
return CGSizeMake(
_sizeFlexibility & RCTRootViewSizeFlexibilityWidth ? INFINITY : size.width,
_sizeFlexibility & RCTRootViewSizeFlexibilityHeight ? INFINITY : size.height);
}
- (void)updateAvailableSize
{
if (!self.reactTag || !_bridge.isValid) {
return;
}
[_bridge.uiManager setAvailableSize:self.availableSize forRootView:self];
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
// The root content view itself should never receive touches
UIView *hitView = [super hitTest:point withEvent:event];
if (_passThroughTouches && hitView == self) {
return nil;
}
return hitView;
}
- (void)invalidate
{
if (self.userInteractionEnabled) {
self.userInteractionEnabled = NO;
[(RCTRootView *)self.superview contentViewInvalidated];
[_bridge enqueueJSCall:@"AppRegistry"
method:@"unmountApplicationComponentAtRootTag"
args:@[ self.reactTag ]
completion:NULL];
}
}
@end

165
node_modules/react-native/React/Base/RCTRootView.h generated vendored Normal file
View File

@ -0,0 +1,165 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTBridge.h>
@protocol RCTRootViewDelegate;
/**
* This enum is used to define size flexibility type of the root view.
* If a dimension is flexible, the view will recalculate that dimension
* so the content fits. Recalculations are performed when the root's frame,
* size flexibility mode or content size changes. After a recalculation,
* rootViewDidChangeIntrinsicSize method of the RCTRootViewDelegate will be called.
*/
typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
RCTRootViewSizeFlexibilityNone = 0,
RCTRootViewSizeFlexibilityWidth = 1 << 0,
RCTRootViewSizeFlexibilityHeight = 1 << 1,
RCTRootViewSizeFlexibilityWidthAndHeight = RCTRootViewSizeFlexibilityWidth | RCTRootViewSizeFlexibilityHeight,
};
/**
* This notification is sent when the first subviews are added to the root view
* after the application has loaded. This is used to hide the `loadingView`, and
* is a good indicator that the application is ready to use.
*/
#if defined(__cplusplus)
extern "C"
#else
extern
#endif
NS_ASSUME_NONNULL_BEGIN
NSString *const RCTContentDidAppearNotification;
/**
* Native view used to host React-managed views within the app. Can be used just
* like any ordinary UIView. You can have multiple RCTRootViews on screen at
* once, all controlled by the same JavaScript application.
*/
@interface RCTRootView : UIView
/**
* - Designated initializer -
*/
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(nullable NSDictionary *)initialProperties NS_DESIGNATED_INITIALIZER;
/**
* - Convenience initializer -
* A bridge will be created internally.
* This initializer is intended to be used when the app has a single RCTRootView,
* otherwise create an `RCTBridge` and pass it in via `initWithBridge:moduleName:`
* to all the instances.
*/
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleName:(NSString *)moduleName
initialProperties:(nullable NSDictionary *)initialProperties
launchOptions:(nullable NSDictionary *)launchOptions;
/**
* The name of the JavaScript module to execute within the
* specified scriptURL (required). Setting this will not have
* any immediate effect, but it must be done prior to loading
* the script.
*/
@property (nonatomic, copy, readonly) NSString *moduleName;
/**
* The bridge used by the root view. Bridges can be shared between multiple
* root views, so you can use this property to initialize another RCTRootView.
*/
@property (nonatomic, strong, readonly) RCTBridge *bridge;
/**
* The properties to apply to the view. Use this property to update
* application properties and rerender the view. Initialized with
* initialProperties argument of the initializer.
*
* Set this property only on the main thread.
*/
@property (nonatomic, copy, readwrite, nullable) NSDictionary *appProperties;
/**
* The size flexibility mode of the root view.
*/
@property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility;
/*
* The minimum size of the root view, defaults to CGSizeZero.
*/
@property (nonatomic, assign) CGSize minimumSize;
/**
* The delegate that handles intrinsic size updates.
*/
@property (nonatomic, weak, nullable) id<RCTRootViewDelegate> delegate;
/**
* The backing view controller of the root view.
*/
@property (nonatomic, weak, nullable) UIViewController *reactViewController;
/**
* The React-managed contents view of the root view.
*/
@property (nonatomic, strong, readonly) UIView *contentView;
/**
* A view to display while the JavaScript is loading, so users aren't presented
* with a blank screen. By default this is nil, but you can override it with
* (for example) a UIActivityIndicatorView or a placeholder image.
*/
@property (nonatomic, strong, nullable) UIView *loadingView;
/**
* When set, any touches on the RCTRootView that are not matched up to any of the child
* views will be passed to siblings of the RCTRootView. See -[UIView hitTest:withEvent:]
* for details on iOS hit testing.
*
* Enable this to support a semi-transparent RN view that occupies the whole screen but
* has visible content below it that the user can interact with.
*
* The default value is NO.
*/
@property (nonatomic, assign) BOOL passThroughTouches;
/**
* Timings for hiding the loading view after the content has loaded. Both of
* these values default to 0.25 seconds.
*/
@property (nonatomic, assign) NSTimeInterval loadingViewFadeDelay;
@property (nonatomic, assign) NSTimeInterval loadingViewFadeDuration;
@end
@interface RCTRootView (Deprecated)
/**
* The intrinsic size of the root view's content. This is set right before the
* `rootViewDidChangeIntrinsicSize` method of `RCTRootViewDelegate` is called.
* This property is deprecated and will be removed in next releases.
* Use UIKit `intrinsicContentSize` property instead.
*/
@property (readonly, nonatomic, assign) CGSize intrinsicSize __deprecated_msg("Use `intrinsicContentSize` instead.");
/**
* This methods is deprecated and will be removed soon.
* To interrupt a React Native gesture recognizer, use the standard
* `UIGestureRecognizer` negotiation process.
* See `UIGestureRecognizerDelegate` for more details.
*/
- (void)cancelTouches;
@end
NS_ASSUME_NONNULL_END

411
node_modules/react-native/React/Base/RCTRootView.m generated vendored Normal file
View File

@ -0,0 +1,411 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTRootView.h"
#import "RCTRootViewDelegate.h"
#import "RCTRootViewInternal.h"
#import <objc/runtime.h>
#import "RCTAssert.h"
#import "RCTBridge+Private.h"
#import "RCTBridge.h"
#import "RCTConstants.h"
#import "RCTEventDispatcher.h"
#import "RCTKeyCommands.h"
#import "RCTLog.h"
#import "RCTPerformanceLogger.h"
#import "RCTProfile.h"
#import "RCTRootContentView.h"
#import "RCTRootShadowView.h"
#import "RCTTouchHandler.h"
#import "RCTUIManager.h"
#import "RCTUIManagerUtils.h"
#import "RCTUtils.h"
#import "RCTView.h"
#import "UIView+React.h"
#if TARGET_OS_TV
#import "RCTTVNavigationEventEmitter.h"
#import "RCTTVRemoteHandler.h"
#endif
NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification";
@interface RCTUIManager (RCTRootView)
- (NSNumber *)allocateRootTag;
@end
@implementation RCTRootView {
RCTBridge *_bridge;
NSString *_moduleName;
RCTRootContentView *_contentView;
BOOL _passThroughTouches;
CGSize _intrinsicContentSize;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
{
RCTAssertMainQueue();
RCTAssert(bridge, @"A bridge instance is required to create an RCTRootView");
RCTAssert(moduleName, @"A moduleName is required to create an RCTRootView");
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTRootView init]", nil);
if (!bridge.isLoading) {
[bridge.performanceLogger markStartForTag:RCTPLTTI];
}
if (self = [super initWithFrame:CGRectZero]) {
self.backgroundColor = [UIColor whiteColor];
_bridge = bridge;
_moduleName = moduleName;
_appProperties = [initialProperties copy];
_loadingViewFadeDelay = 0.25;
_loadingViewFadeDuration = 0.25;
_sizeFlexibility = RCTRootViewSizeFlexibilityNone;
_minimumSize = CGSizeZero;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(bridgeDidReload)
name:RCTJavaScriptWillStartLoadingNotification
object:_bridge];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(javaScriptDidLoad:)
name:RCTJavaScriptDidLoadNotification
object:_bridge];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(hideLoadingView)
name:RCTContentDidAppearNotification
object:self];
#if TARGET_OS_TV
self.tvRemoteHandler = [RCTTVRemoteHandler new];
for (NSString *key in [self.tvRemoteHandler.tvRemoteGestureRecognizers allKeys]) {
[self addGestureRecognizer:self.tvRemoteHandler.tvRemoteGestureRecognizers[key]];
}
#endif
[self showLoadingView];
// Immediately schedule the application to be started.
// (Sometimes actual `_bridge` is already batched bridge here.)
[self bundleFinishedLoading:([_bridge batchedBridge] ?: _bridge)];
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
return self;
}
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
launchOptions:(NSDictionary *)launchOptions
{
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL moduleProvider:nil launchOptions:launchOptions];
return [self initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
}
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
#if TARGET_OS_TV
- (UIView *)preferredFocusedView
{
if (self.reactPreferredFocusedView) {
return self.reactPreferredFocusedView;
}
return [super preferredFocusedView];
}
#endif
#pragma mark - passThroughTouches
- (BOOL)passThroughTouches
{
return _contentView.passThroughTouches;
}
- (void)setPassThroughTouches:(BOOL)passThroughTouches
{
_passThroughTouches = passThroughTouches;
_contentView.passThroughTouches = passThroughTouches;
}
#pragma mark - Layout
- (CGSize)sizeThatFits:(CGSize)size
{
CGSize fitSize = _intrinsicContentSize;
CGSize currentSize = self.bounds.size;
// Following the current `size` and current `sizeFlexibility` policy.
fitSize = CGSizeMake(
_sizeFlexibility & RCTRootViewSizeFlexibilityWidth ? fitSize.width : currentSize.width,
_sizeFlexibility & RCTRootViewSizeFlexibilityHeight ? fitSize.height : currentSize.height);
// Following the given size constraints.
fitSize = CGSizeMake(MIN(size.width, fitSize.width), MIN(size.height, fitSize.height));
return fitSize;
}
- (void)layoutSubviews
{
[super layoutSubviews];
_contentView.frame = self.bounds;
_loadingView.center = (CGPoint){CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)};
}
- (void)setMinimumSize:(CGSize)minimumSize
{
if (CGSizeEqualToSize(_minimumSize, minimumSize)) {
return;
}
_minimumSize = minimumSize;
__block NSNumber *tag = self.reactTag;
__weak typeof(self) weakSelf = self;
RCTExecuteOnUIManagerQueue(^{
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf && strongSelf->_bridge.isValid) {
RCTRootShadowView *shadowView = (RCTRootShadowView *)[strongSelf->_bridge.uiManager shadowViewForReactTag:tag];
shadowView.minimumSize = minimumSize;
}
});
}
- (UIViewController *)reactViewController
{
return _reactViewController ?: [super reactViewController];
}
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (void)setLoadingView:(UIView *)loadingView
{
_loadingView = loadingView;
if (!_contentView.contentHasAppeared) {
[self showLoadingView];
}
}
- (void)showLoadingView
{
if (_loadingView && !_contentView.contentHasAppeared) {
_loadingView.hidden = NO;
[self addSubview:_loadingView];
}
}
- (void)hideLoadingView
{
if (_loadingView.superview == self && _contentView.contentHasAppeared) {
if (_loadingViewFadeDuration > 0) {
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_loadingViewFadeDelay * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
[UIView transitionWithView:self
duration:self->_loadingViewFadeDuration
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self->_loadingView.hidden = YES;
}
completion:^(__unused BOOL finished) {
[self->_loadingView removeFromSuperview];
}];
});
} else {
_loadingView.hidden = YES;
[_loadingView removeFromSuperview];
}
}
}
- (NSNumber *)reactTag
{
RCTAssertMainQueue();
if (!super.reactTag) {
/**
* Every root view that is created must have a unique react tag.
* Numbering of these tags goes from 1, 11, 21, 31, etc
*
* NOTE: Since the bridge persists, the RootViews might be reused, so the
* react tag must be re-assigned every time a new UIManager is created.
*/
self.reactTag = RCTAllocateRootViewTag();
}
return super.reactTag;
}
- (void)bridgeDidReload
{
RCTAssertMainQueue();
// Clear the reactTag so it can be re-assigned
self.reactTag = nil;
}
- (void)javaScriptDidLoad:(NSNotification *)notification
{
RCTAssertMainQueue();
// Use the (batched) bridge that's sent in the notification payload, so the
// RCTRootContentView is scoped to the right bridge
RCTBridge *bridge = notification.userInfo[@"bridge"];
if (bridge != _contentView.bridge) {
[self bundleFinishedLoading:bridge];
}
}
- (void)bundleFinishedLoading:(RCTBridge *)bridge
{
RCTAssert(bridge != nil, @"Bridge cannot be nil");
if (!bridge.valid) {
return;
}
[_contentView removeFromSuperview];
_contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds
bridge:bridge
reactTag:self.reactTag
sizeFlexiblity:_sizeFlexibility];
[self runApplication:bridge];
_contentView.passThroughTouches = _passThroughTouches;
[self insertSubview:_contentView atIndex:0];
if (_sizeFlexibility == RCTRootViewSizeFlexibilityNone) {
self.intrinsicContentSize = self.bounds.size;
}
}
- (void)runApplication:(RCTBridge *)bridge
{
NSString *moduleName = _moduleName ?: @"";
NSDictionary *appParameters = @{
@"rootTag" : _contentView.reactTag,
@"initialProps" : _appProperties ?: @{},
};
RCTLogInfo(@"Running application %@ (%@)", moduleName, appParameters);
[bridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[ moduleName, appParameters ] completion:NULL];
}
- (void)setSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
{
if (_sizeFlexibility == sizeFlexibility) {
return;
}
_sizeFlexibility = sizeFlexibility;
[self setNeedsLayout];
_contentView.sizeFlexibility = _sizeFlexibility;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
// The root view itself should never receive touches
UIView *hitView = [super hitTest:point withEvent:event];
if (self.passThroughTouches && hitView == self) {
return nil;
}
return hitView;
}
- (void)setAppProperties:(NSDictionary *)appProperties
{
RCTAssertMainQueue();
if ([_appProperties isEqualToDictionary:appProperties]) {
return;
}
_appProperties = [appProperties copy];
if (_contentView && _bridge.valid && !_bridge.loading) {
[self runApplication:_bridge];
}
}
- (void)setIntrinsicContentSize:(CGSize)intrinsicContentSize
{
BOOL oldSizeHasAZeroDimension = _intrinsicContentSize.height == 0 || _intrinsicContentSize.width == 0;
BOOL newSizeHasAZeroDimension = intrinsicContentSize.height == 0 || intrinsicContentSize.width == 0;
BOOL bothSizesHaveAZeroDimension = oldSizeHasAZeroDimension && newSizeHasAZeroDimension;
BOOL sizesAreEqual = CGSizeEqualToSize(_intrinsicContentSize, intrinsicContentSize);
_intrinsicContentSize = intrinsicContentSize;
// Don't notify the delegate if the content remains invisible or its size has not changed
if (bothSizesHaveAZeroDimension || sizesAreEqual) {
return;
}
[self invalidateIntrinsicContentSize];
[self.superview setNeedsLayout];
[_delegate rootViewDidChangeIntrinsicSize:self];
}
- (CGSize)intrinsicContentSize
{
return _intrinsicContentSize;
}
- (void)contentViewInvalidated
{
[_contentView removeFromSuperview];
_contentView = nil;
[self showLoadingView];
}
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
[super traitCollectionDidChange:previousTraitCollection];
[[NSNotificationCenter defaultCenter]
postNotificationName:RCTUserInterfaceStyleDidChangeNotification
object:self
userInfo:@{
RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey : self.traitCollection,
}];
}
- (void)dealloc
{
[_contentView invalidate];
}
@end
@implementation RCTRootView (Deprecated)
- (CGSize)intrinsicSize
{
RCTLogWarn(@"Calling deprecated `[-RCTRootView intrinsicSize]`.");
return self.intrinsicContentSize;
}
- (void)cancelTouches
{
RCTLogWarn(@"`-[RCTRootView cancelTouches]` is deprecated and will be deleted soon.");
[[_contentView touchHandler] cancel];
}
@end

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@class RCTRootView;
@protocol RCTRootViewDelegate <NSObject>
/**
* Called after the root view's intrinsic content size is changed.
*
* The method is not called when both old size and new size have
* a dimension that equals to zero.
*
* The delegate can use this callback to appropriately resize
* the root view's frame to fit the new intrinsic content view size,
* but usually it is not necessary because the root view will also call
* `setNeedsLayout` for its superview which in its turn will trigger relayout.
*
* The new intrinsic content size is available via the `intrinsicContentSize`
* property of the root view. The view will not resize itself.
*/
- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView;
@end

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTRootView.h>
@class RCTTVRemoteHandler;
/**
* The interface provides a set of functions that allow other internal framework
* classes to change the RCTRootViews's internal state.
*/
@interface RCTRootView ()
/**
* This setter should be used only by RCTUIManager on react root view
* intrinsic content size update.
*/
@property (readwrite, nonatomic, assign) CGSize intrinsicContentSize;
/**
* TV remote gesture recognizers
*/
#if TARGET_OS_TV
@property (nonatomic, strong) RCTTVRemoteHandler *tvRemoteHandler;
@property (nonatomic, strong) UIView *reactPreferredFocusedView;
#endif
- (void)contentViewInvalidated;
@end

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
extern NSString *const RCTTVRemoteEventMenu;
extern NSString *const RCTTVRemoteEventPlayPause;
extern NSString *const RCTTVRemoteEventSelect;
extern NSString *const RCTTVRemoteEventLongPlayPause;
extern NSString *const RCTTVRemoteEventLongSelect;
extern NSString *const RCTTVRemoteEventLeft;
extern NSString *const RCTTVRemoteEventRight;
extern NSString *const RCTTVRemoteEventUp;
extern NSString *const RCTTVRemoteEventDown;
extern NSString *const RCTTVRemoteEventSwipeLeft;
extern NSString *const RCTTVRemoteEventSwipeRight;
extern NSString *const RCTTVRemoteEventSwipeUp;
extern NSString *const RCTTVRemoteEventSwipeDown;
@interface RCTTVRemoteHandler : NSObject
@property (nonatomic, copy, readonly) NSDictionary *tvRemoteGestureRecognizers;
@end

View File

@ -0,0 +1,233 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTVRemoteHandler.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#import "RCTAssert.h"
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import "RCTLog.h"
#import "RCTRootView.h"
#import "RCTTVNavigationEventEmitter.h"
#import "RCTUIManager.h"
#import "RCTUtils.h"
#import "RCTView.h"
#import "UIView+React.h"
#if __has_include("RCTDevMenu.h")
#import "RCTDevMenu.h"
#endif
NSString *const RCTTVRemoteEventMenu = @"menu";
NSString *const RCTTVRemoteEventPlayPause = @"playPause";
NSString *const RCTTVRemoteEventSelect = @"select";
NSString *const RCTTVRemoteEventLongPlayPause = @"longPlayPause";
NSString *const RCTTVRemoteEventLongSelect = @"longSelect";
NSString *const RCTTVRemoteEventLeft = @"left";
NSString *const RCTTVRemoteEventRight = @"right";
NSString *const RCTTVRemoteEventUp = @"up";
NSString *const RCTTVRemoteEventDown = @"down";
NSString *const RCTTVRemoteEventSwipeLeft = @"swipeLeft";
NSString *const RCTTVRemoteEventSwipeRight = @"swipeRight";
NSString *const RCTTVRemoteEventSwipeUp = @"swipeUp";
NSString *const RCTTVRemoteEventSwipeDown = @"swipeDown";
@implementation RCTTVRemoteHandler {
NSMutableDictionary<NSString *, UIGestureRecognizer *> *_tvRemoteGestureRecognizers;
}
- (instancetype)init
{
if ((self = [super init])) {
_tvRemoteGestureRecognizers = [NSMutableDictionary dictionary];
// Recognizers for Apple TV remote buttons
// Play/Pause
[self addTapGestureRecognizerWithSelector:@selector(playPausePressed:)
pressType:UIPressTypePlayPause
name:RCTTVRemoteEventPlayPause];
// Menu
[self addTapGestureRecognizerWithSelector:@selector(menuPressed:)
pressType:UIPressTypeMenu
name:RCTTVRemoteEventMenu];
// Select
[self addTapGestureRecognizerWithSelector:@selector(selectPressed:)
pressType:UIPressTypeSelect
name:RCTTVRemoteEventSelect];
// Up
[self addTapGestureRecognizerWithSelector:@selector(tappedUp:)
pressType:UIPressTypeUpArrow
name:RCTTVRemoteEventUp];
// Down
[self addTapGestureRecognizerWithSelector:@selector(tappedDown:)
pressType:UIPressTypeDownArrow
name:RCTTVRemoteEventDown];
// Left
[self addTapGestureRecognizerWithSelector:@selector(tappedLeft:)
pressType:UIPressTypeLeftArrow
name:RCTTVRemoteEventLeft];
// Right
[self addTapGestureRecognizerWithSelector:@selector(tappedRight:)
pressType:UIPressTypeRightArrow
name:RCTTVRemoteEventRight];
// Recognizers for long button presses
// We don't intercept long menu press -- that's used by the system to go to the home screen
[self addLongPressGestureRecognizerWithSelector:@selector(longPlayPausePressed:)
pressType:UIPressTypePlayPause
name:RCTTVRemoteEventLongPlayPause];
[self addLongPressGestureRecognizerWithSelector:@selector(longSelectPressed:)
pressType:UIPressTypeSelect
name:RCTTVRemoteEventLongSelect];
// Recognizers for Apple TV remote trackpad swipes
// Up
[self addSwipeGestureRecognizerWithSelector:@selector(swipedUp:)
direction:UISwipeGestureRecognizerDirectionUp
name:RCTTVRemoteEventSwipeUp];
// Down
[self addSwipeGestureRecognizerWithSelector:@selector(swipedDown:)
direction:UISwipeGestureRecognizerDirectionDown
name:RCTTVRemoteEventSwipeDown];
// Left
[self addSwipeGestureRecognizerWithSelector:@selector(swipedLeft:)
direction:UISwipeGestureRecognizerDirectionLeft
name:RCTTVRemoteEventSwipeLeft];
// Right
[self addSwipeGestureRecognizerWithSelector:@selector(swipedRight:)
direction:UISwipeGestureRecognizerDirectionRight
name:RCTTVRemoteEventSwipeRight];
}
return self;
}
- (void)playPausePressed:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventPlayPause toView:r.view];
}
- (void)menuPressed:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventMenu toView:r.view];
}
- (void)selectPressed:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventSelect toView:r.view];
}
- (void)longPlayPausePressed:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventLongPlayPause toView:r.view];
#if __has_include("RCTDevMenu.h") && RCT_DEV
// If shake to show is enabled on device, use long play/pause event to show dev menu
[[NSNotificationCenter defaultCenter] postNotificationName:RCTShowDevMenuNotification object:nil];
#endif
}
- (void)longSelectPressed:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventLongSelect toView:r.view];
}
- (void)swipedUp:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventSwipeUp toView:r.view];
}
- (void)swipedDown:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventSwipeDown toView:r.view];
}
- (void)swipedLeft:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventSwipeLeft toView:r.view];
}
- (void)swipedRight:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventSwipeRight toView:r.view];
}
- (void)tappedUp:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventUp toView:r.view];
}
- (void)tappedDown:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventDown toView:r.view];
}
- (void)tappedLeft:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventLeft toView:r.view];
}
- (void)tappedRight:(UIGestureRecognizer *)r
{
[self sendAppleTVEvent:RCTTVRemoteEventRight toView:r.view];
}
#pragma mark -
- (void)addLongPressGestureRecognizerWithSelector:(nonnull SEL)selector
pressType:(UIPressType)pressType
name:(NSString *)name
{
UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:selector];
recognizer.allowedPressTypes = @[ @(pressType) ];
_tvRemoteGestureRecognizers[name] = recognizer;
}
- (void)addTapGestureRecognizerWithSelector:(nonnull SEL)selector pressType:(UIPressType)pressType name:(NSString *)name
{
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:selector];
recognizer.allowedPressTypes = @[ @(pressType) ];
_tvRemoteGestureRecognizers[name] = recognizer;
}
- (void)addSwipeGestureRecognizerWithSelector:(nonnull SEL)selector
direction:(UISwipeGestureRecognizerDirection)direction
name:(NSString *)name
{
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:selector];
recognizer.direction = direction;
_tvRemoteGestureRecognizers[name] = recognizer;
}
- (void)sendAppleTVEvent:(NSString *)eventType toView:(__unused UIView *)v
{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTTVNavigationEventNotification
object:@{@"eventType" : eventType}];
}
@end

23
node_modules/react-native/React/Base/RCTTouchEvent.h generated vendored Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTEventDispatcher.h>
/**
* Represents a touch event, which may be composed of several touches (one for every finger).
* For more information on contents of passed data structures see RCTTouchHandler.
*/
@interface RCTTouchEvent : NSObject <RCTEvent>
- (instancetype)initWithEventName:(NSString *)eventName
reactTag:(NSNumber *)reactTag
reactTouches:(NSArray<NSDictionary *> *)reactTouches
changedIndexes:(NSArray<NSNumber *> *)changedIndexes
coalescingKey:(uint16_t)coalescingKey NS_DESIGNATED_INITIALIZER;
@end

107
node_modules/react-native/React/Base/RCTTouchEvent.m generated vendored Normal file
View File

@ -0,0 +1,107 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTouchEvent.h"
#import "RCTAssert.h"
@implementation RCTTouchEvent {
NSArray<NSDictionary *> *_reactTouches;
NSArray<NSNumber *> *_changedIndexes;
uint16_t _coalescingKey;
}
@synthesize eventName = _eventName;
@synthesize viewTag = _viewTag;
- (instancetype)initWithEventName:(NSString *)eventName
reactTag:(NSNumber *)reactTag
reactTouches:(NSArray<NSDictionary *> *)reactTouches
changedIndexes:(NSArray<NSNumber *> *)changedIndexes
coalescingKey:(uint16_t)coalescingKey
{
if (self = [super init]) {
_viewTag = reactTag;
_eventName = eventName;
_reactTouches = reactTouches;
_changedIndexes = changedIndexes;
_coalescingKey = coalescingKey;
}
return self;
}
RCT_NOT_IMPLEMENTED(-(instancetype)init)
#pragma mark - RCTEvent
- (BOOL)canCoalesce
{
return [_eventName isEqual:@"touchMove"];
}
// We coalesce only move events, while holding some assumptions that seem reasonable but there are no explicit
// guarantees about them.
- (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent
{
RCTAssert(
[newEvent isKindOfClass:[RCTTouchEvent class]],
@"Touch event cannot be coalesced with any other type of event, such as provided %@",
newEvent);
RCTTouchEvent *newTouchEvent = (RCTTouchEvent *)newEvent;
RCTAssert(
[_reactTouches count] == [newTouchEvent->_reactTouches count],
@"Touch events have different number of touches. %@ %@",
self,
newEvent);
BOOL newEventIsMoreRecent = NO;
BOOL oldEventIsMoreRecent = NO;
NSInteger count = _reactTouches.count;
for (int i = 0; i < count; i++) {
NSDictionary *touch = _reactTouches[i];
NSDictionary *newTouch = newTouchEvent->_reactTouches[i];
RCTAssert(
[touch[@"identifier"] isEqual:newTouch[@"identifier"]],
@"Touch events doesn't have touches in the same order. %@ %@",
touch,
newTouch);
if ([touch[@"timestamp"] doubleValue] > [newTouch[@"timestamp"] doubleValue]) {
oldEventIsMoreRecent = YES;
} else {
newEventIsMoreRecent = YES;
}
}
RCTAssert(
!(oldEventIsMoreRecent && newEventIsMoreRecent),
@"Neither touch event is exclusively more recent than the other one. %@ %@",
_reactTouches,
newTouchEvent->_reactTouches);
return newEventIsMoreRecent ? newEvent : self;
}
+ (NSString *)moduleDotMethod
{
return @"RCTEventEmitter.receiveTouches";
}
- (NSArray *)arguments
{
return @[ RCTNormalizeInputEventName(_eventName), _reactTouches, _changedIndexes ];
}
- (uint16_t)coalescingKey
{
return _coalescingKey;
}
- (NSString *)description
{
return [NSString
stringWithFormat:@"<%@: %p; name = %@; coalescing key = %hu>", [self class], self, _eventName, _coalescingKey];
}
@end

23
node_modules/react-native/React/Base/RCTTouchHandler.h generated vendored Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTFrameUpdate.h>
@class RCTBridge;
@interface RCTTouchHandler : UIGestureRecognizer
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
- (void)attachToView:(UIView *)view;
- (void)detachFromView:(UIView *)view;
- (void)cancel;
@end

374
node_modules/react-native/React/Base/RCTTouchHandler.m generated vendored Normal file
View File

@ -0,0 +1,374 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTouchHandler.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#import "RCTAssert.h"
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import "RCTLog.h"
#import "RCTSurfaceView.h"
#import "RCTTouchEvent.h"
#import "RCTUIManager.h"
#import "RCTUtils.h"
#import "UIView+React.h"
@interface RCTTouchHandler () <UIGestureRecognizerDelegate>
@end
// TODO: this class behaves a lot like a module, and could be implemented as a
// module if we were to assume that modules and RootViews had a 1:1 relationship
@implementation RCTTouchHandler {
__weak RCTEventDispatcher *_eventDispatcher;
/**
* Arrays managed in parallel tracking native touch object along with the
* native view that was touched, and the React touch data dictionary.
* These must be kept track of because `UIKit` destroys the touch targets
* if touches are canceled, and we have no other way to recover this info.
*/
NSMutableOrderedSet<UITouch *> *_nativeTouches;
NSMutableArray<NSMutableDictionary *> *_reactTouches;
NSMutableArray<UIView *> *_touchViews;
__weak UIView *_cachedRootView;
uint16_t _coalescingKey;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
{
RCTAssertParam(bridge);
if ((self = [super initWithTarget:nil action:NULL])) {
_eventDispatcher = [bridge moduleForClass:[RCTEventDispatcher class]];
_nativeTouches = [NSMutableOrderedSet new];
_reactTouches = [NSMutableArray new];
_touchViews = [NSMutableArray new];
// `cancelsTouchesInView` and `delaysTouches*` are needed in order to be used as a top level
// event delegated recognizer. Otherwise, lower-level components not built
// using RCT, will fail to recognize gestures.
self.cancelsTouchesInView = NO;
self.delaysTouchesBegan = NO; // This is default value.
self.delaysTouchesEnded = NO;
self.delegate = self;
}
return self;
}
RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)action)
- (void)attachToView:(UIView *)view
{
RCTAssert(self.view == nil, @"RCTTouchHandler already has attached view.");
[view addGestureRecognizer:self];
}
- (void)detachFromView:(UIView *)view
{
RCTAssertParam(view);
RCTAssert(self.view == view, @"RCTTouchHandler attached to another view.");
[view removeGestureRecognizer:self];
}
#pragma mark - Bookkeeping for touch indices
- (void)_recordNewTouches:(NSSet<UITouch *> *)touches
{
for (UITouch *touch in touches) {
RCTAssert(![_nativeTouches containsObject:touch], @"Touch is already recorded. This is a critical bug.");
// Find closest React-managed touchable view
UIView *targetView = touch.view;
while (targetView) {
if (targetView.reactTag && targetView.userInteractionEnabled) {
break;
}
targetView = targetView.superview;
}
NSNumber *reactTag = [targetView reactTagAtPoint:[touch locationInView:targetView]];
if (!reactTag || !targetView.userInteractionEnabled) {
continue;
}
// Get new, unique touch identifier for the react touch
const NSUInteger RCTMaxTouches = 11; // This is the maximum supported by iDevices
NSInteger touchID = ([_reactTouches.lastObject[@"identifier"] integerValue] + 1) % RCTMaxTouches;
for (NSDictionary *reactTouch in _reactTouches) {
NSInteger usedID = [reactTouch[@"identifier"] integerValue];
if (usedID == touchID) {
// ID has already been used, try next value
touchID++;
} else if (usedID > touchID) {
// If usedID > touchID, touchID must be unique, so we can stop looking
break;
}
}
// Create touch
NSMutableDictionary *reactTouch = [[NSMutableDictionary alloc] initWithCapacity:RCTMaxTouches];
reactTouch[@"target"] = reactTag;
reactTouch[@"identifier"] = @(touchID);
// Add to arrays
[_touchViews addObject:targetView];
[_nativeTouches addObject:touch];
[_reactTouches addObject:reactTouch];
}
}
- (void)_recordRemovedTouches:(NSSet<UITouch *> *)touches
{
for (UITouch *touch in touches) {
NSUInteger index = [_nativeTouches indexOfObject:touch];
if (index == NSNotFound) {
continue;
}
[_touchViews removeObjectAtIndex:index];
[_nativeTouches removeObjectAtIndex:index];
[_reactTouches removeObjectAtIndex:index];
}
}
- (void)_updateReactTouchAtIndex:(NSInteger)touchIndex
{
UITouch *nativeTouch = _nativeTouches[touchIndex];
CGPoint windowLocation = [nativeTouch locationInView:nativeTouch.window];
RCTAssert(_cachedRootView, @"We were unable to find a root view for the touch");
CGPoint rootViewLocation = [nativeTouch.window convertPoint:windowLocation toView:_cachedRootView];
UIView *touchView = _touchViews[touchIndex];
CGPoint touchViewLocation = [nativeTouch.window convertPoint:windowLocation toView:touchView];
NSMutableDictionary *reactTouch = _reactTouches[touchIndex];
reactTouch[@"pageX"] = @(RCTSanitizeNaNValue(rootViewLocation.x, @"touchEvent.pageX"));
reactTouch[@"pageY"] = @(RCTSanitizeNaNValue(rootViewLocation.y, @"touchEvent.pageY"));
reactTouch[@"locationX"] = @(RCTSanitizeNaNValue(touchViewLocation.x, @"touchEvent.locationX"));
reactTouch[@"locationY"] = @(RCTSanitizeNaNValue(touchViewLocation.y, @"touchEvent.locationY"));
reactTouch[@"timestamp"] = @(nativeTouch.timestamp * 1000); // in ms, for JS
// TODO: force for a 'normal' touch is usually 1.0;
// should we expose a `normalTouchForce` constant somewhere (which would
// have a value of `1.0 / nativeTouch.maximumPossibleForce`)?
if (RCTForceTouchAvailable()) {
reactTouch[@"force"] = @(RCTZeroIfNaN(nativeTouch.force / nativeTouch.maximumPossibleForce));
}
}
/**
* Constructs information about touch events to send across the serialized
* boundary. This data should be compliant with W3C `Touch` objects. This data
* alone isn't sufficient to construct W3C `Event` objects. To construct that,
* there must be a simple receiver on the other side of the bridge that
* organizes the touch objects into `Event`s.
*
* We send the data as an array of `Touch`es, the type of action
* (start/end/move/cancel) and the indices that represent "changed" `Touch`es
* from that array.
*/
- (void)_updateAndDispatchTouches:(NSSet<UITouch *> *)touches eventName:(NSString *)eventName
{
// Update touches
NSMutableArray<NSNumber *> *changedIndexes = [NSMutableArray new];
for (UITouch *touch in touches) {
NSInteger index = [_nativeTouches indexOfObject:touch];
if (index == NSNotFound) {
continue;
}
[self _updateReactTouchAtIndex:index];
[changedIndexes addObject:@(index)];
}
if (changedIndexes.count == 0) {
return;
}
// Deep copy the touches because they will be accessed from another thread
// TODO: would it be safer to do this in the bridge or executor, rather than trusting caller?
NSMutableArray<NSDictionary *> *reactTouches = [[NSMutableArray alloc] initWithCapacity:_reactTouches.count];
for (NSDictionary *touch in _reactTouches) {
[reactTouches addObject:[touch copy]];
}
BOOL canBeCoalesced = [eventName isEqualToString:@"touchMove"];
// We increment `_coalescingKey` twice here just for sure that
// this `_coalescingKey` will not be reused by another (preceding or following) event
// (yes, even if coalescing only happens (and makes sense) on events of the same type).
if (!canBeCoalesced) {
_coalescingKey++;
}
RCTTouchEvent *event = [[RCTTouchEvent alloc] initWithEventName:eventName
reactTag:self.view.reactTag
reactTouches:reactTouches
changedIndexes:changedIndexes
coalescingKey:_coalescingKey];
if (!canBeCoalesced) {
_coalescingKey++;
}
[_eventDispatcher sendEvent:event];
}
/***
* To ensure compatibility when using UIManager.measure and RCTTouchHandler, we have to adopt
* UIManager.measure's behavior in finding a "root view".
* Usually RCTTouchHandler is already attached to a root view but in some cases (e.g. Modal),
* we are instead attached to some RCTView subtree. This is also the case when embedding some RN
* views inside a separate ViewController not controlled by RN.
* This logic will either find the nearest rootView, or go all the way to the UIWindow.
* While this is not optimal, it is exactly what UIManager.measure does, and what Touchable.js
* relies on.
* We cache it here so that we don't have to repeat it for every touch in the gesture.
*/
- (void)_cacheRootView
{
UIView *rootView = self.view;
while (rootView.superview && ![rootView isReactRootView] && ![rootView isKindOfClass:[RCTSurfaceView class]]) {
rootView = rootView.superview;
}
_cachedRootView = rootView;
}
#pragma mark - Gesture Recognizer Delegate Callbacks
static BOOL RCTAllTouchesAreCancelledOrEnded(NSSet<UITouch *> *touches)
{
for (UITouch *touch in touches) {
if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved || touch.phase == UITouchPhaseStationary) {
return NO;
}
}
return YES;
}
static BOOL RCTAnyTouchesChanged(NSSet<UITouch *> *touches)
{
for (UITouch *touch in touches) {
if (touch.phase == UITouchPhaseBegan || touch.phase == UITouchPhaseMoved) {
return YES;
}
}
return NO;
}
#pragma mark - `UIResponder`-ish touch-delivery methods
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[self _cacheRootView];
// "start" has to record new touches *before* extracting the event.
// "end"/"cancel" needs to remove the touch *after* extracting the event.
[self _recordNewTouches:touches];
[self _updateAndDispatchTouches:touches eventName:@"touchStart"];
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateBegan;
} else if (self.state == UIGestureRecognizerStateBegan) {
self.state = UIGestureRecognizerStateChanged;
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
[self _updateAndDispatchTouches:touches eventName:@"touchMove"];
self.state = UIGestureRecognizerStateChanged;
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[self _updateAndDispatchTouches:touches eventName:@"touchEnd"];
if (RCTAllTouchesAreCancelledOrEnded(event.allTouches)) {
self.state = UIGestureRecognizerStateEnded;
} else if (RCTAnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;
}
[self _recordRemovedTouches:touches];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
[self _updateAndDispatchTouches:touches eventName:@"touchCancel"];
if (RCTAllTouchesAreCancelledOrEnded(event.allTouches)) {
self.state = UIGestureRecognizerStateCancelled;
} else if (RCTAnyTouchesChanged(event.allTouches)) {
self.state = UIGestureRecognizerStateChanged;
}
[self _recordRemovedTouches:touches];
}
- (BOOL)canPreventGestureRecognizer:(__unused UIGestureRecognizer *)preventedGestureRecognizer
{
return NO;
}
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
{
// We fail in favour of other external gesture recognizers.
// iOS will ask `delegate`'s opinion about this gesture recognizer little bit later.
return ![preventingGestureRecognizer.view isDescendantOfView:self.view];
}
- (void)reset
{
if (_nativeTouches.count != 0) {
[self _updateAndDispatchTouches:_nativeTouches.set eventName:@"touchCancel"];
[_nativeTouches removeAllObjects];
[_reactTouches removeAllObjects];
[_touchViews removeAllObjects];
_cachedRootView = nil;
}
}
#pragma mark - Other
- (void)cancel
{
self.enabled = NO;
self.enabled = YES;
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(__unused UIGestureRecognizer *)gestureRecognizer
shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
// Same condition for `failure of` as for `be prevented by`.
return [self canBePreventedByGestureRecognizer:otherGestureRecognizer];
}
@end

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
/**
* An abstract interface used by request handler modules to send
* data back over the bridge back to JS.
*/
@protocol RCTURLRequestDelegate <NSObject>
/**
* Call this when you send request data to the server. This is used to track
* upload progress, so should be called multiple times for large request bodies.
*/
- (void)URLRequest:(id)requestToken didSendDataWithProgress:(int64_t)bytesSent;
/**
* Call this when you first receives a response from the server. This should
* include response headers, etc.
*/
- (void)URLRequest:(id)requestToken didReceiveResponse:(NSURLResponse *)response;
/**
* Call this when you receive data from the server. This can be called multiple
* times with partial data chunks, or just once with the full data packet.
*/
- (void)URLRequest:(id)requestToken didReceiveData:(NSData *)data;
/**
* Call this when the request is complete and/or if an error is encountered.
* For a successful request, the error parameter should be nil.
*/
- (void)URLRequest:(id)requestToken didCompleteWithError:(NSError *)error;
@end

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTBridgeModule.h>
#import <React/RCTURLRequestDelegate.h>
/**
* Provides the interface needed to register a request handler. Request handlers
* are also bridge modules, so should be registered using RCT_EXPORT_MODULE().
*/
@protocol RCTURLRequestHandler <RCTBridgeModule>
/**
* Indicates whether this handler is capable of processing the specified
* request. Typically the handler would examine the scheme/protocol of the
* request URL (and possibly the HTTP method and/or headers) to determine this.
*/
- (BOOL)canHandleRequest:(NSURLRequest *)request;
/**
* Send a network request and call the delegate with the response data. The
* method should return a token, which can be anything, including the request
* itself. This will be used later to refer to the request in callbacks. The
* `sendRequest:withDelegate:` method *must* return before calling any of the
* delegate methods, or the delegate won't recognize the token.
* Following common Objective-C pattern, `delegate` will not be retained.
*/
- (id)sendRequest:(NSURLRequest *)request withDelegate:(id<RCTURLRequestDelegate>)delegate;
@optional
/**
* Not all request types can be cancelled, but this method can be implemented
* for ones that can. It should be used to free up any resources on ongoing
* processes associated with the request.
*/
- (void)cancelRequest:(id)requestToken;
/**
* If more than one RCTURLRequestHandler responds YES to `canHandleRequest:`
* then `handlerPriority` is used to determine which one to use. The handler
* with the highest priority will be selected. Default priority is zero. If
* two or more valid handlers have the same priority, the selection order is
* undefined.
*/
- (float)handlerPriority;
@end

180
node_modules/react-native/React/Base/RCTUtils.h generated vendored Normal file
View File

@ -0,0 +1,180 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <tgmath.h>
#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <React/RCTAssert.h>
#import <React/RCTDefines.h>
NS_ASSUME_NONNULL_BEGIN
// JSON serialization/deserialization
RCT_EXTERN NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSError **error);
RCT_EXTERN id __nullable RCTJSONParse(NSString *__nullable jsonString, NSError **error);
RCT_EXTERN id __nullable RCTJSONParseMutable(NSString *__nullable jsonString, NSError **error);
// Sanitize a JSON object by stripping invalid types and/or NaN values
RCT_EXTERN id RCTJSONClean(id object);
// Get MD5 hash of a string
RCT_EXTERN NSString *RCTMD5Hash(NSString *string);
// Check if we are currently on the main queue (not to be confused with
// the main thread, which is not necessarily the same thing)
// https://twitter.com/olebegemann/status/738656134731599872
RCT_EXTERN BOOL RCTIsMainQueue(void);
// Execute the specified block on the main queue. Unlike dispatch_async()
// this will execute immediately if we're already on the main queue.
RCT_EXTERN void RCTExecuteOnMainQueue(dispatch_block_t block);
// Legacy function to execute the specified block on the main queue synchronously.
// Please do not use this unless you know what you're doing.
RCT_EXTERN void RCTUnsafeExecuteOnMainQueueSync(dispatch_block_t block);
// Get screen metrics in a thread-safe way
RCT_EXTERN CGFloat RCTScreenScale(void);
RCT_EXTERN CGSize RCTScreenSize(void);
// Round float coordinates to nearest whole screen pixel (not point)
RCT_EXTERN CGFloat RCTRoundPixelValue(CGFloat value);
RCT_EXTERN CGFloat RCTCeilPixelValue(CGFloat value);
RCT_EXTERN CGFloat RCTFloorPixelValue(CGFloat value);
// Convert a size in points to pixels, rounded up to the nearest integral size
RCT_EXTERN CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale);
// Method swizzling
RCT_EXTERN void RCTSwapClassMethods(Class cls, SEL original, SEL replacement);
RCT_EXTERN void RCTSwapInstanceMethods(Class cls, SEL original, SEL replacement);
// Module subclass support
RCT_EXTERN BOOL RCTClassOverridesClassMethod(Class cls, SEL selector);
RCT_EXTERN BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector);
// Creates a standardized error object to return in callbacks
RCT_EXTERN NSDictionary<NSString *, id>
*RCTMakeError(NSString *message, id __nullable toStringify, NSDictionary<NSString *, id> *__nullable extraData);
RCT_EXTERN NSDictionary<NSString *, id> *
RCTMakeAndLogError(NSString *message, id __nullable toStringify, NSDictionary<NSString *, id> *__nullable extraData);
RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromNSError(NSError *error);
RCT_EXTERN NSDictionary<NSString *, id>
*RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *__nullable error);
// The default error code to use as the `code` property for callback error objects
RCT_EXTERN NSString *const RCTErrorUnspecified;
// Returns YES if React is running in a test environment
RCT_EXTERN BOOL RCTRunningInTestEnvironment(void);
// Returns YES if React is running in an iOS App Extension
RCT_EXTERN BOOL RCTRunningInAppExtension(void);
// Returns the shared UIApplication instance, or nil if running in an App Extension
RCT_EXTERN UIApplication *__nullable RCTSharedApplication(void);
// Returns the current main window, useful if you need to access the root view
// or view controller
RCT_EXTERN UIWindow *__nullable RCTKeyWindow(void);
// Returns the presented view controller, useful if you need
// e.g. to present a modal view controller or alert over it
RCT_EXTERN UIViewController *__nullable RCTPresentedViewController(void);
// Does this device support force touch (aka 3D Touch)?
RCT_EXTERN BOOL RCTForceTouchAvailable(void);
// Create an NSError in the RCTErrorDomain
RCT_EXTERN NSError *RCTErrorWithMessage(NSString *message);
// Convert nil values to NSNull, and vice-versa
#define RCTNullIfNil(value) ((value) ?: (id)kCFNull)
#define RCTNilIfNull(value) \
({ \
__typeof__(value) t = (value); \
(id) t == (id)kCFNull ? (__typeof(value))nil : t; \
})
// Convert NaN or infinite values to zero, as these aren't JSON-safe
RCT_EXTERN double RCTZeroIfNaN(double value);
// Returns `0` and log special warning if value is NaN or INF.
RCT_EXTERN double RCTSanitizeNaNValue(double value, NSString *property);
// Convert data to a Base64-encoded data URL
RCT_EXTERN NSURL *RCTDataURL(NSString *mimeType, NSData *data);
// Gzip functionality - compression level in range 0 - 1 (-1 for default)
RCT_EXTERN NSData *__nullable RCTGzipData(NSData *__nullable data, float level);
// Returns the relative path within the main bundle for an absolute URL
// (or nil, if the URL does not specify a path within the main bundle)
RCT_EXTERN NSString *__nullable RCTBundlePathForURL(NSURL *__nullable URL);
// Returns the Path of Library directory
RCT_EXTERN NSString *__nullable RCTLibraryPath(void);
// Returns the relative path within the library for an absolute URL
// (or nil, if the URL does not specify a path within the Library directory)
RCT_EXTERN NSString *__nullable RCTLibraryPathForURL(NSURL *__nullable URL);
// Determines if a given image URL refers to a image in bundle
RCT_EXTERN BOOL RCTIsBundleAssetURL(NSURL *__nullable imageURL);
// Determines if a given image URL refers to a image in library
RCT_EXTERN BOOL RCTIsLibraryAssetURL(NSURL *__nullable imageURL);
// Determines if a given image URL refers to a local image
RCT_EXTERN BOOL RCTIsLocalAssetURL(NSURL *__nullable imageURL);
// Returns an UIImage for a local image asset. Returns nil if the URL
// does not correspond to a local asset.
RCT_EXTERN UIImage *__nullable RCTImageFromLocalAssetURL(NSURL *imageURL);
// Only used in case when RCTImageFromLocalAssetURL fails to get an image
// This method basically checks for the image in the bundle location, instead
// of the CodePush location
RCT_EXTERN UIImage *__nullable RCTImageFromLocalBundleAssetURL(NSURL *imageURL);
// Creates a new, unique temporary file path with the specified extension
RCT_EXTERN NSString *__nullable RCTTempFilePath(NSString *__nullable extension, NSError **error);
// Get RGBA components of CGColor
RCT_EXTERN void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[_Nonnull 4]);
// Converts a CGColor to a hex string
RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
// Get standard localized string (if it exists)
RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string);
// Get a human readable type string from an NSObject. For example NSString becomes string
RCT_EXTERN NSString *RCTHumanReadableType(NSObject *obj);
// URL manipulation
RCT_EXTERN NSString *__nullable RCTGetURLQueryParam(NSURL *__nullable URL, NSString *param);
RCT_EXTERN NSURL *__nullable
RCTURLByReplacingQueryParam(NSURL *__nullable URL, NSString *param, NSString *__nullable value);
// Given a string, drop common RN prefixes (RCT, RK, etc.)
RCT_EXTERN NSString *RCTDropReactPrefixes(NSString *s);
RCT_EXTERN BOOL RCTUIManagerTypeForTagIsFabric(NSNumber *reactTag);
RCT_EXTERN BOOL RCTValidateTypeOfViewCommandArgument(
NSObject *obj,
id expectedClass,
NSString const *expectedType,
NSString const *componentName,
NSString const *commandName,
NSString const *argPos);
NS_ASSUME_NONNULL_END

1005
node_modules/react-native/React/Base/RCTUtils.m generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
@interface RCTUtilsUIOverride : NSObject
/**
Set the global presented view controller instance override.
*/
+ (void)setPresentedViewController:(UIViewController *)presentedViewController;
+ (UIViewController *)presentedViewController;
+ (BOOL)hasPresentedViewController;
@end

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTUtilsUIOverride.h"
@implementation RCTUtilsUIOverride
static UIViewController *_presentedViewController = nil;
+ (void)setPresentedViewController:(UIViewController *)presentedViewController
{
_presentedViewController = presentedViewController;
}
+ (UIViewController *)presentedViewController
{
return _presentedViewController;
}
+ (BOOL)hasPresentedViewController
{
return _presentedViewController != nil;
}
@end

17
node_modules/react-native/React/Base/RCTVersion.h generated vendored Normal file
View File

@ -0,0 +1,17 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTDefines.h>
RCT_EXTERN NSString *const RCTVersionMajor;
RCT_EXTERN NSString *const RCTVersionMinor;
RCT_EXTERN NSString *const RCTVersionPatch;
RCT_EXTERN NSString *const RCTVersionPrerelease;
RCT_EXTERN NSDictionary *RCTGetReactNativeVersion(void);

31
node_modules/react-native/React/Base/RCTVersion.m generated vendored Normal file
View File

@ -0,0 +1,31 @@
/**
* @generated by scripts/bump-oss-version.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTVersion.h"
NSString* const RCTVersionMajor = @"major";
NSString* const RCTVersionMinor = @"minor";
NSString* const RCTVersionPatch = @"patch";
NSString* const RCTVersionPrerelease = @"prerelease";
NSDictionary* RCTGetReactNativeVersion(void)
{
static NSDictionary* __rnVersion;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^(void){
__rnVersion = @{
RCTVersionMajor: @(0),
RCTVersionMinor: @(63),
RCTVersionPatch: @(4),
RCTVersionPrerelease: [NSNull null],
};
});
return __rnVersion;
}

16
node_modules/react-native/React/Base/RCTWeakProxy.h generated vendored Normal file
View File

@ -0,0 +1,16 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@interface RCTWeakProxy : NSObject
@property (nonatomic, weak, readonly) id target;
+ (instancetype)weakProxyWithTarget:(id)target;
@end

30
node_modules/react-native/React/Base/RCTWeakProxy.m generated vendored Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTWeakProxy.h"
@implementation RCTWeakProxy
- (instancetype)initWithTarget:(id)target
{
if (self = [super init]) {
_target = target;
}
return self;
}
+ (instancetype)weakProxyWithTarget:(id)target
{
return [[RCTWeakProxy alloc] initWithTarget:target];
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return _target;
}
@end

View File

@ -0,0 +1,141 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTSurfaceStage.h>
NS_ASSUME_NONNULL_BEGIN
@class RCTBridge;
@class RCTSurfaceView;
@protocol RCTSurfaceDelegate;
/**
* RCTSurface instance represents React Native-powered piece of a user interface
* which can be a full-screen app, separate modal view controller,
* or even small widget.
* It is called "Surface".
*
* The RCTSurface instance is completely thread-safe by design;
* it can be created on any thread, and any its method can be called from
* any thread (if the opposite is not mentioned explicitly).
*
* The primary goals of the RCTSurface are:
* * ability to measure and layout the surface in a thread-safe
* and synchronous manner;
* * ability to create a UIView instance on demand (later);
* * ability to communicate the current stage of the surface granularly.
*/
@interface RCTSurface : NSObject
@property (atomic, readonly) RCTSurfaceStage stage;
@property (atomic, readonly) NSString *moduleName;
@property (atomic, readonly) NSNumber *rootViewTag;
@property (atomic, readwrite, weak, nullable) id<RCTSurfaceDelegate> delegate;
@property (atomic, copy, readwrite) NSDictionary *properties;
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties;
#pragma mark - Dealing with UIView representation, the Main thread only access
/**
* Creates (if needed) and returns `UIView` instance which represents the Surface.
* The Surface will cache and *retain* this object.
* Returning the UIView instance does not mean that the Surface is ready
* to execute and layout. It can be just a handler which Surface will use later
* to mount the actual views.
* RCTSurface does not control (or influence in any way) the size or origin
* of this view. Some superview (or another owner) must use other methods
* of this class to setup proper layout and interop interactions with UIKit
* or another UI framework.
* This method must be called only from the main queue.
*/
- (RCTSurfaceView *)view;
#pragma mark - Layout: Setting the size constrains
/**
* Sets `minimumSize` and `maximumSize` layout constraints for the Surface.
*/
- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize;
/**
* Previously set `minimumSize` layout constraint.
* Defaults to `{0, 0}`.
*/
@property (atomic, assign, readonly) CGSize minimumSize;
/**
* Previously set `maximumSize` layout constraint.
* Defaults to `{CGFLOAT_MAX, CGFLOAT_MAX}`.
*/
@property (atomic, assign, readonly) CGSize maximumSize;
/**
* Simple shortcut to `-[RCTSurface setMinimumSize:size maximumSize:size]`.
*/
- (void)setSize:(CGSize)size;
#pragma mark - Layout: Measuring
/**
* Measures the Surface with given constraints.
* This method does not cause any side effects on the surface object.
*/
- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize;
/**
* Return the current size of the root view based on (but not clamp by) current
* size constraints.
*/
@property (atomic, assign, readonly) CGSize intrinsicSize;
#pragma mark - Synchronous waiting
/**
* Synchronously blocks the current thread up to given `timeout` until
* the Surface reaches `stage`.
* Limitations:
* - Do nothing, if called on `UIManager` queue.
* - Calling on the main queue with `RCTSurfaceStageSurfaceDidInitialMounting`
* stage temporary is not supported; in this case the stage will be
* downgraded to `RCTSurfaceStageSurfaceDidInitialLayout`.
*/
- (BOOL)synchronouslyWaitForStage:(RCTSurfaceStage)stage timeout:(NSTimeInterval)timeout;
#pragma mark - Start & Stop
/**
* Starts or stops the Surface.
* Those methods are a no-op for regular RCTSurface (for now), but all call sites must call them appropriately.
*/
- (BOOL)start;
- (BOOL)stop;
#pragma mark - Mounting/Unmounting of React components
/**
* Mount the React component specified by the given moduleName. This is typically
* calling runApplication.js from the native side.
*/
- (void)mountReactComponentWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
params:(NSDictionary *)params;
/**
* Unmount the React component specified by the given rootViewTag, called from native.
*/
- (void)unmountReactComponentWithBridge:(RCTBridge *)bridge rootViewTag:(NSNumber *)rootViewTag;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,592 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSurface.h"
#import "RCTSurfaceView+Internal.h"
#import <mutex>
#import <stdatomic.h>
#import "RCTAssert.h"
#import "RCTBridge+Private.h"
#import "RCTBridge.h"
#import "RCTShadowView+Layout.h"
#import "RCTSurfaceDelegate.h"
#import "RCTSurfaceRootShadowView.h"
#import "RCTSurfaceRootShadowViewDelegate.h"
#import "RCTSurfaceRootView.h"
#import "RCTSurfaceView.h"
#import "RCTTouchHandler.h"
#import "RCTUIManager.h"
#import "RCTUIManagerObserverCoordinator.h"
#import "RCTUIManagerUtils.h"
@interface RCTSurface () <RCTSurfaceRootShadowViewDelegate, RCTUIManagerObserver>
@end
@implementation RCTSurface {
// Immutable
RCTBridge *_bridge;
NSString *_moduleName;
NSNumber *_rootViewTag;
// Protected by the `_mutex`
std::mutex _mutex;
RCTBridge *_batchedBridge;
RCTSurfaceStage _stage;
NSDictionary *_properties;
CGSize _minimumSize;
CGSize _maximumSize;
CGSize _intrinsicSize;
RCTUIManagerMountingBlock _mountingBlock;
// The Main thread only
RCTSurfaceView *_Nullable _view;
RCTTouchHandler *_Nullable _touchHandler;
// Semaphores
dispatch_semaphore_t _rootShadowViewDidStartRenderingSemaphore;
dispatch_semaphore_t _rootShadowViewDidStartLayingOutSemaphore;
dispatch_semaphore_t _uiManagerDidPerformMountingSemaphore;
// Atomics
atomic_bool _waitingForMountingStageOnMainQueue;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
{
RCTAssert(bridge.valid, @"Valid bridge is required to instantiate `RCTSurface`.");
if (self = [super init]) {
_bridge = bridge;
_batchedBridge = [_bridge batchedBridge] ?: _bridge;
_moduleName = moduleName;
_properties = [initialProperties copy];
_rootViewTag = RCTAllocateRootViewTag();
_rootShadowViewDidStartRenderingSemaphore = dispatch_semaphore_create(0);
_rootShadowViewDidStartLayingOutSemaphore = dispatch_semaphore_create(0);
_uiManagerDidPerformMountingSemaphore = dispatch_semaphore_create(0);
_minimumSize = CGSizeZero;
_maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleBridgeWillLoadJavaScriptNotification:)
name:RCTJavaScriptWillStartLoadingNotification
object:_bridge];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleBridgeDidLoadJavaScriptNotification:)
name:RCTJavaScriptDidLoadNotification
object:_bridge];
_stage = RCTSurfaceStageSurfaceDidInitialize;
if (!bridge.loading) {
_stage = _stage | RCTSurfaceStageBridgeDidLoad;
}
[_bridge.uiManager.observerCoordinator addObserver:self];
[self _registerRootView];
[self _run];
}
return self;
}
- (void)dealloc
{
[self _stop];
}
#pragma mark - Immutable Properties (no need to enforce synchronization)
- (RCTBridge *)bridge
{
return _bridge;
}
- (NSString *)moduleName
{
return _moduleName;
}
- (NSNumber *)rootViewTag
{
return _rootViewTag;
}
#pragma mark - Convenience Internal Thread-Safe Properties
- (RCTBridge *)_batchedBridge
{
std::lock_guard<std::mutex> lock(_mutex);
return _batchedBridge;
}
- (RCTUIManager *)_uiManager
{
return self._batchedBridge.uiManager;
}
#pragma mark - Main-Threaded Routines
- (RCTSurfaceView *)view
{
RCTAssertMainQueue();
if (!_view) {
_view = [[RCTSurfaceView alloc] initWithSurface:self];
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:self.bridge];
[_touchHandler attachToView:_view];
[self _mountRootViewIfNeeded];
}
return _view;
}
- (void)_mountRootViewIfNeeded
{
RCTAssertMainQueue();
RCTSurfaceView *view = self->_view;
if (!view) {
return;
}
RCTSurfaceRootView *rootView = (RCTSurfaceRootView *)[self._uiManager viewForReactTag:self->_rootViewTag];
if (!rootView) {
return;
}
RCTAssert(
[rootView isKindOfClass:[RCTSurfaceRootView class]],
@"Received root view is not an instance of `RCTSurfaceRootView`.");
if (rootView.superview != view) {
view.rootView = rootView;
}
}
#pragma mark - Bridge Events
- (void)handleBridgeWillLoadJavaScriptNotification:(__unused NSNotification *)notification
{
RCTAssertMainQueue();
// Reset states because the bridge is reloading. This is similar to initialization phase.
_stage = RCTSurfaceStageSurfaceDidInitialize;
_view = nil;
_touchHandler = nil;
[self _setStage:RCTSurfaceStageBridgeDidLoad];
}
- (void)handleBridgeDidLoadJavaScriptNotification:(NSNotification *)notification
{
RCTAssertMainQueue();
[self _setStage:RCTSurfaceStageModuleDidLoad];
RCTBridge *bridge = notification.userInfo[@"bridge"];
BOOL isRerunNeeded = NO;
{
std::lock_guard<std::mutex> lock(_mutex);
if (bridge != _batchedBridge) {
_batchedBridge = bridge;
isRerunNeeded = YES;
}
}
if (isRerunNeeded) {
[self _registerRootView];
[self _run];
}
}
#pragma mark - Stage management
- (RCTSurfaceStage)stage
{
std::lock_guard<std::mutex> lock(_mutex);
return _stage;
}
- (void)_setStage:(RCTSurfaceStage)stage
{
RCTSurfaceStage updatedStage;
{
std::lock_guard<std::mutex> lock(_mutex);
if (_stage & stage) {
return;
}
updatedStage = (RCTSurfaceStage)(_stage | stage);
_stage = updatedStage;
}
[self _propagateStageChange:updatedStage];
}
- (void)_propagateStageChange:(RCTSurfaceStage)stage
{
// Updating the `view`
RCTExecuteOnMainQueue(^{
self->_view.stage = stage;
});
// Notifying the `delegate`
id<RCTSurfaceDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(surface:didChangeStage:)]) {
[delegate surface:self didChangeStage:stage];
}
}
#pragma mark - Properties Management
- (NSDictionary *)properties
{
std::lock_guard<std::mutex> lock(_mutex);
return _properties;
}
- (void)setProperties:(NSDictionary *)properties
{
{
std::lock_guard<std::mutex> lock(_mutex);
if ([properties isEqualToDictionary:_properties]) {
return;
}
_properties = [properties copy];
}
[self _run];
}
#pragma mark - Running
- (void)_run
{
RCTBridge *batchedBridge;
NSDictionary *properties;
{
std::lock_guard<std::mutex> lock(_mutex);
batchedBridge = _batchedBridge;
properties = _properties;
}
if (!batchedBridge.valid) {
return;
}
NSDictionary *applicationParameters = @{
@"rootTag" : _rootViewTag,
@"initialProps" : properties,
};
RCTLogInfo(@"Running surface %@ (%@)", _moduleName, applicationParameters);
[self mountReactComponentWithBridge:batchedBridge moduleName:_moduleName params:applicationParameters];
[self _setStage:RCTSurfaceStageSurfaceDidRun];
}
- (void)_stop
{
[self unmountReactComponentWithBridge:self._batchedBridge rootViewTag:self->_rootViewTag];
}
- (void)_registerRootView
{
RCTBridge *batchedBridge;
CGSize minimumSize;
CGSize maximumSize;
{
std::lock_guard<std::mutex> lock(_mutex);
batchedBridge = _batchedBridge;
minimumSize = _minimumSize;
maximumSize = _maximumSize;
}
RCTUIManager *uiManager = batchedBridge.uiManager;
// If we are on the main queue now, we have to proceed synchronously.
// Otherwise, we cannot perform synchronous waiting for some stages later.
(RCTIsMainQueue() ? RCTUnsafeExecuteOnUIManagerQueueSync : RCTExecuteOnUIManagerQueue)(^{
[uiManager registerRootViewTag:self->_rootViewTag];
RCTSurfaceRootShadowView *rootShadowView =
(RCTSurfaceRootShadowView *)[uiManager shadowViewForReactTag:self->_rootViewTag];
RCTAssert(
[rootShadowView isKindOfClass:[RCTSurfaceRootShadowView class]],
@"Received shadow view is not an instance of `RCTSurfaceRootShadowView`.");
[rootShadowView setMinimumSize:minimumSize maximumSize:maximumSize];
rootShadowView.delegate = self;
});
}
#pragma mark - Layout
- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize
{
RCTUIManager *uiManager = self._uiManager;
__block CGSize fittingSize;
RCTUnsafeExecuteOnUIManagerQueueSync(^{
RCTSurfaceRootShadowView *rootShadowView =
(RCTSurfaceRootShadowView *)[uiManager shadowViewForReactTag:self->_rootViewTag];
RCTAssert(
[rootShadowView isKindOfClass:[RCTSurfaceRootShadowView class]],
@"Received shadow view is not an instance of `RCTSurfaceRootShadowView`.");
fittingSize = [rootShadowView sizeThatFitsMinimumSize:minimumSize maximumSize:maximumSize];
});
return fittingSize;
}
#pragma mark - Size Constraints
- (void)setSize:(CGSize)size
{
[self setMinimumSize:size maximumSize:size];
}
- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize
{
{
std::lock_guard<std::mutex> lock(_mutex);
if (CGSizeEqualToSize(minimumSize, _minimumSize) && CGSizeEqualToSize(maximumSize, _maximumSize)) {
return;
}
_maximumSize = maximumSize;
_minimumSize = minimumSize;
}
RCTUIManager *uiManager = self._uiManager;
RCTUnsafeExecuteOnUIManagerQueueSync(^{
RCTSurfaceRootShadowView *rootShadowView =
(RCTSurfaceRootShadowView *)[uiManager shadowViewForReactTag:self->_rootViewTag];
RCTAssert(
[rootShadowView isKindOfClass:[RCTSurfaceRootShadowView class]],
@"Received shadow view is not an instance of `RCTSurfaceRootShadowView`.");
[rootShadowView setMinimumSize:minimumSize maximumSize:maximumSize];
[uiManager setNeedsLayout];
});
}
- (CGSize)minimumSize
{
std::lock_guard<std::mutex> lock(_mutex);
return _minimumSize;
}
- (CGSize)maximumSize
{
std::lock_guard<std::mutex> lock(_mutex);
return _maximumSize;
}
#pragma mark - intrinsicSize
- (void)setIntrinsicSize:(CGSize)intrinsicSize
{
{
std::lock_guard<std::mutex> lock(_mutex);
if (CGSizeEqualToSize(intrinsicSize, _intrinsicSize)) {
return;
}
_intrinsicSize = intrinsicSize;
}
// Notifying `delegate`
id<RCTSurfaceDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(surface:didChangeIntrinsicSize:)]) {
[delegate surface:self didChangeIntrinsicSize:intrinsicSize];
}
}
- (CGSize)intrinsicSize
{
std::lock_guard<std::mutex> lock(_mutex);
return _intrinsicSize;
}
#pragma mark - Synchronous Waiting
- (BOOL)synchronouslyWaitForStage:(RCTSurfaceStage)stage timeout:(NSTimeInterval)timeout
{
if (RCTIsUIManagerQueue()) {
RCTLogInfo(@"Synchronous waiting is not supported on UIManager queue.");
return NO;
}
if (RCTIsMainQueue() && (stage & RCTSurfaceStageSurfaceDidInitialMounting)) {
// All main-threaded execution (especially mounting process) has to be
// intercepted, captured and performed synchronously at the end of this method
// right after the semaphore signals.
// Atomic variant of `_waitingForMountingStageOnMainQueue = YES;`
atomic_fetch_or(&_waitingForMountingStageOnMainQueue, 1);
}
dispatch_semaphore_t semaphore;
switch (stage) {
case RCTSurfaceStageSurfaceDidInitialLayout:
semaphore = _rootShadowViewDidStartLayingOutSemaphore;
break;
case RCTSurfaceStageSurfaceDidInitialRendering:
semaphore = _rootShadowViewDidStartRenderingSemaphore;
break;
case RCTSurfaceStageSurfaceDidInitialMounting:
semaphore = _uiManagerDidPerformMountingSemaphore;
break;
default:
RCTAssert(
NO,
@"Only waiting for `RCTSurfaceStageSurfaceDidInitialRendering`, `RCTSurfaceStageSurfaceDidInitialLayout` and `RCTSurfaceStageSurfaceDidInitialMounting` stages are supported.");
}
BOOL timeoutOccurred = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_SEC));
// Atomic equivalent of `_waitingForMountingStageOnMainQueue = NO;`.
atomic_fetch_and(&_waitingForMountingStageOnMainQueue, 0);
if (!timeoutOccurred) {
// Balancing the semaphore.
// Note: `dispatch_semaphore_wait` reverts the decrement in case when timeout occurred.
dispatch_semaphore_signal(semaphore);
}
if (RCTIsMainQueue() && (stage & RCTSurfaceStageSurfaceDidInitialMounting)) {
// Time to apply captured mounting block.
RCTUIManagerMountingBlock mountingBlock;
{
std::lock_guard<std::mutex> lock(_mutex);
mountingBlock = _mountingBlock;
_mountingBlock = nil;
}
if (mountingBlock) {
mountingBlock();
[self _mountRootViewIfNeeded];
}
}
return !timeoutOccurred;
}
#pragma mark - RCTSurfaceRootShadowViewDelegate
- (void)rootShadowView:(__unused RCTRootShadowView *)rootShadowView didChangeIntrinsicSize:(CGSize)intrinsicSize
{
self.intrinsicSize = intrinsicSize;
}
- (void)rootShadowViewDidStartRendering:(__unused RCTSurfaceRootShadowView *)rootShadowView
{
[self _setStage:RCTSurfaceStageSurfaceDidInitialRendering];
dispatch_semaphore_signal(_rootShadowViewDidStartRenderingSemaphore);
}
- (void)rootShadowViewDidStartLayingOut:(__unused RCTSurfaceRootShadowView *)rootShadowView
{
[self _setStage:RCTSurfaceStageSurfaceDidInitialLayout];
dispatch_semaphore_signal(_rootShadowViewDidStartLayingOutSemaphore);
RCTExecuteOnMainQueue(^{
// Rendering is happening, let's mount `rootView` into `view` if we already didn't do this.
[self _mountRootViewIfNeeded];
});
}
#pragma mark - RCTUIManagerObserver
- (BOOL)uiManager:(__unused RCTUIManager *)manager performMountingWithBlock:(RCTUIManagerMountingBlock)block
{
if (atomic_load(&_waitingForMountingStageOnMainQueue) && (self.stage & RCTSurfaceStageSurfaceDidInitialLayout)) {
// Atomic equivalent of `_waitingForMountingStageOnMainQueue = NO;`.
atomic_fetch_and(&_waitingForMountingStageOnMainQueue, 0);
{
std::lock_guard<std::mutex> lock(_mutex);
_mountingBlock = block;
}
return YES;
}
return NO;
}
- (void)uiManagerDidPerformMounting:(__unused RCTUIManager *)manager
{
if (self.stage & RCTSurfaceStageSurfaceDidInitialLayout) {
[self _setStage:RCTSurfaceStageSurfaceDidInitialMounting];
dispatch_semaphore_signal(_uiManagerDidPerformMountingSemaphore);
// No need to listen to UIManager anymore.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[self->_bridge.uiManager.observerCoordinator removeObserver:self];
});
}
}
- (BOOL)start
{
// Does nothing.
// The Start&Stop feature is not implemented for regular Surface yet.
return YES;
}
- (BOOL)stop
{
// Does nothing.
// The Start&Stop feature is not implemented for regular Surface yet.
return YES;
}
#pragma mark - Mounting/Unmounting of React components
- (void)mountReactComponentWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
params:(NSDictionary *)params
{
[bridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[ moduleName, params ] completion:NULL];
}
- (void)unmountReactComponentWithBridge:(RCTBridge *)bridge rootViewTag:(NSNumber *)rootViewTag
{
[bridge enqueueJSCall:@"AppRegistry"
method:@"unmountApplicationComponentAtRootTag"
args:@[ rootViewTag ]
completion:NULL];
}
@end

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTSurfaceStage.h>
NS_ASSUME_NONNULL_BEGIN
@class RCTSurface;
@protocol RCTSurfaceDelegate <NSObject>
@optional
/**
* Notifies a receiver that a surface transitioned to a new stage.
* See `RCTSurfaceStage` for more details.
*/
- (void)surface:(RCTSurface *)surface didChangeStage:(RCTSurfaceStage)stage;
/**
* Notifies a receiver that root view got a new (intrinsic) size during the last
* layout pass.
*/
- (void)surface:(RCTSurface *)surface didChangeIntrinsicSize:(CGSize)intrinsicSize;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTShadowView.h>
#import <React/RCTSurfaceRootShadowViewDelegate.h>
#import <yoga/YGEnums.h>
@interface RCTSurfaceRootShadowView : RCTShadowView
@property (nonatomic, assign, readonly) CGSize minimumSize;
@property (nonatomic, assign, readonly) CGSize maximumSize;
- (void)setMinimumSize:(CGSize)size maximumSize:(CGSize)maximumSize;
@property (nonatomic, assign, readonly) CGSize intrinsicSize;
@property (nonatomic, weak) id<RCTSurfaceRootShadowViewDelegate> delegate;
/**
* Layout direction (LTR or RTL) inherited from native environment and
* is using as a base direction value in layout engine.
* Defaults to value inferred from current locale.
*/
@property (nonatomic, assign) YGDirection baseDirection;
- (void)layoutWithAffectedShadowViews:(NSHashTable<RCTShadowView *> *)affectedShadowViews;
@end

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSurfaceRootShadowView.h"
#import "RCTI18nUtil.h"
#import "RCTShadowView+Layout.h"
#import "RCTUIManagerUtils.h"
@implementation RCTSurfaceRootShadowView {
CGSize _intrinsicSize;
BOOL _isRendered;
BOOL _isLaidOut;
}
- (instancetype)init
{
if (self = [super init]) {
self.viewName = @"RCTSurfaceRootView";
_baseDirection = [[RCTI18nUtil sharedInstance] isRTL] ? YGDirectionRTL : YGDirectionLTR;
_minimumSize = CGSizeZero;
_maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
self.alignSelf = YGAlignStretch;
self.flex = 1;
}
return self;
}
- (void)insertReactSubview:(RCTShadowView *)subview atIndex:(NSInteger)atIndex
{
[super insertReactSubview:subview atIndex:atIndex];
if (!_isRendered) {
[_delegate rootShadowViewDidStartRendering:self];
_isRendered = YES;
}
}
- (void)layoutWithAffectedShadowViews:(NSHashTable<RCTShadowView *> *)affectedShadowViews
{
NSHashTable<NSString *> *other = [NSHashTable new];
RCTLayoutContext layoutContext = {};
layoutContext.absolutePosition = CGPointZero;
layoutContext.affectedShadowViews = affectedShadowViews;
layoutContext.other = other;
[self layoutWithMinimumSize:_minimumSize
maximumSize:_maximumSize
layoutDirection:RCTUIKitLayoutDirectionFromYogaLayoutDirection(_baseDirection)
layoutContext:layoutContext];
self.intrinsicSize = self.layoutMetrics.frame.size;
if (_isRendered && !_isLaidOut) {
[_delegate rootShadowViewDidStartLayingOut:self];
_isLaidOut = YES;
}
}
- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize
{
if (CGSizeEqualToSize(minimumSize, _minimumSize) && CGSizeEqualToSize(maximumSize, _maximumSize)) {
return;
}
_maximumSize = maximumSize;
_minimumSize = minimumSize;
}
- (void)setIntrinsicSize:(CGSize)intrinsicSize
{
if (CGSizeEqualToSize(_intrinsicSize, intrinsicSize)) {
return;
}
_intrinsicSize = intrinsicSize;
[_delegate rootShadowView:self didChangeIntrinsicSize:intrinsicSize];
}
- (CGSize)intrinsicSize
{
return _intrinsicSize;
}
@end

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class RCTSurfaceRootShadowView;
@protocol RCTSurfaceRootShadowViewDelegate <NSObject>
- (void)rootShadowView:(RCTSurfaceRootShadowView *)rootShadowView didChangeIntrinsicSize:(CGSize)instrinsicSize;
- (void)rootShadowViewDidStartRendering:(RCTSurfaceRootShadowView *)rootShadowView;
- (void)rootShadowViewDidStartLayingOut:(RCTSurfaceRootShadowView *)rootShadowView;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTView.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Internal class represents Surface's root view.
*/
@interface RCTSurfaceRootView : RCTView
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSurfaceRootView.h"
#import "RCTDefines.h"
@implementation RCTSurfaceRootView
RCT_NOT_IMPLEMENTED(-(nullable instancetype)initWithCoder : (NSCoder *)coder)
@end

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTDefines.h>
/**
* The stage of the Surface
*/
typedef NS_OPTIONS(NSInteger, RCTSurfaceStage) {
RCTSurfaceStageSurfaceDidInitialize = 1 << 0, // Surface object was created
RCTSurfaceStageBridgeDidLoad = 1 << 1, // Bridge was loaded
RCTSurfaceStageModuleDidLoad = 1 << 2, // Module (JavaScript code) was loaded
RCTSurfaceStageSurfaceDidRun = 1 << 3, // Module (JavaScript code) was run
RCTSurfaceStageSurfaceDidInitialRendering = 1 << 4, // UIManager created the first shadow views
RCTSurfaceStageSurfaceDidInitialLayout = 1 << 5, // UIManager completed the first layout pass
RCTSurfaceStageSurfaceDidInitialMounting = 1 << 6, // UIManager completed the first mounting pass
RCTSurfaceStageSurfaceDidStop = 1 << 7, // Surface stopped
// Most of the previously existed stages make no sense in the new architecture;
// now Surface exposes only three simple stages:
//
// Surface object was constructed and still valid.
RCTSurfaceStageInitialized = RCTSurfaceStageSurfaceDidInitialize,
// Surface was started.
RCTSurfaceStageStarted = 1 << 8,
// All off-main-thread work is done; we are ready to mount the UI.
RCTSurfaceStagePrepared = RCTSurfaceStageBridgeDidLoad | RCTSurfaceStageModuleDidLoad | RCTSurfaceStageSurfaceDidRun |
RCTSurfaceStageSurfaceDidInitialRendering | RCTSurfaceStageSurfaceDidInitialLayout,
// All main-thread work is done, the UI was mounted.
RCTSurfaceStageMounted = RCTSurfaceStageSurfaceDidInitialMounting,
};
/**
* Returns `YES` if the stage is suitable for displaying normal React Native app.
*/
RCT_EXTERN BOOL RCTSurfaceStageIsRunning(RCTSurfaceStage stage);
/**
* Returns `YES` if the stage is suitable for displaying activity indicator.
*/
RCT_EXTERN BOOL RCTSurfaceStageIsPreparing(RCTSurfaceStage stage);

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSurfaceStage.h"
BOOL RCTSurfaceStageIsRunning(RCTSurfaceStage stage)
{
return (stage & RCTSurfaceStageSurfaceDidInitialLayout) && !(stage & RCTSurfaceStageSurfaceDidStop);
}
BOOL RCTSurfaceStageIsPreparing(RCTSurfaceStage stage)
{
return !(stage & RCTSurfaceStageSurfaceDidInitialLayout) && !(stage & RCTSurfaceStageSurfaceDidStop);
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTSurfaceStage.h>
#import <React/RCTSurfaceView.h>
@class RCTSurfaceRootView;
NS_ASSUME_NONNULL_BEGIN
@interface RCTSurfaceView (Internal)
@property (nonatomic, strong) RCTSurfaceRootView *rootView;
@property (nonatomic, assign) RCTSurfaceStage stage;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class RCTSurface;
/**
* UIView instance which represents the Surface
*/
@interface RCTSurfaceView : UIView
- (instancetype)initWithSurface:(RCTSurface *)surface NS_DESIGNATED_INITIALIZER;
@property (nonatomic, weak, readonly, nullable) RCTSurface *surface;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSurfaceView.h"
#import "RCTSurfaceView+Internal.h"
#import "RCTDefines.h"
#import "RCTSurface.h"
#import "RCTSurfaceRootView.h"
@implementation RCTSurfaceView {
RCTSurfaceRootView *_Nullable _rootView;
RCTSurfaceStage _stage;
}
RCT_NOT_IMPLEMENTED(-(instancetype)init)
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
RCT_NOT_IMPLEMENTED(-(nullable instancetype)initWithCoder : (NSCoder *)coder)
- (instancetype)initWithSurface:(RCTSurface *)surface
{
if (self = [super initWithFrame:CGRectZero]) {
_stage = surface.stage;
_surface = surface;
}
return self;
}
#pragma mark - Internal Interface
- (void)setRootView:(RCTSurfaceRootView *)rootView
{
if (_rootView == rootView) {
return;
}
[_rootView removeFromSuperview];
_rootView = rootView;
[self _updateStage];
}
- (RCTSurfaceRootView *)rootView
{
return _rootView;
}
#pragma mark - stage
- (void)setStage:(RCTSurfaceStage)stage
{
if (stage == _stage) {
return;
}
_stage = stage;
[self _updateStage];
}
- (RCTSurfaceStage)stage
{
return _stage;
}
#pragma mark - Private
- (void)_updateStage
{
if (RCTSurfaceStageIsRunning(_stage)) {
if (_rootView.superview != self) {
[self addSubview:_rootView];
}
} else {
[_rootView removeFromSuperview];
}
}
@end

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTRootView.h>
#import "RCTSurfaceHostingView.h"
NS_ASSUME_NONNULL_BEGIN
/**
* This is a RCTRootView-compatible implementation of RCTSurfaceHostingView.
* Use this class to replace all usages of RCTRootView in the app for easier migration
* to RCTSurfaceHostingView.
*
* WARNING: In the future, RCTRootView will be deprecated in favor of RCTSurfaceHostingView.
*/
@interface RCTSurfaceHostingProxyRootView : RCTSurfaceHostingView
#pragma mark RCTRootView compatibility - keep these sync'ed with RCTRootView.h
@property (nonatomic, copy, readonly) NSString *moduleName;
@property (nonatomic, strong, readonly) RCTBridge *bridge;
@property (nonatomic, copy, readwrite) NSDictionary *appProperties;
@property (nonatomic, assign) RCTRootViewSizeFlexibility sizeFlexibility;
@property (nonatomic, weak) id<RCTRootViewDelegate> delegate;
@property (nonatomic, weak) UIViewController *reactViewController;
@property (nonatomic, strong, readonly) UIView *contentView;
@property (nonatomic, strong) UIView *loadingView;
@property (nonatomic, assign) BOOL passThroughTouches;
@property (nonatomic, assign) NSTimeInterval loadingViewFadeDelay;
@property (nonatomic, assign) NSTimeInterval loadingViewFadeDuration;
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
launchOptions:(NSDictionary *)launchOptions;
- (instancetype)initWithSurface:(RCTSurface *)surface
sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode NS_UNAVAILABLE;
- (void)cancelTouches;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,182 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSurfaceHostingProxyRootView.h"
#import <objc/runtime.h>
#import "RCTAssert.h"
#import "RCTBridge.h"
#import "RCTLog.h"
#import "RCTPerformanceLogger.h"
#import "RCTProfile.h"
#import "RCTRootContentView.h"
#import "RCTRootViewDelegate.h"
#import "RCTSurface.h"
#import "UIView+React.h"
static RCTSurfaceSizeMeasureMode convertToSurfaceSizeMeasureMode(RCTRootViewSizeFlexibility sizeFlexibility)
{
switch (sizeFlexibility) {
case RCTRootViewSizeFlexibilityWidthAndHeight:
return RCTSurfaceSizeMeasureModeWidthUndefined | RCTSurfaceSizeMeasureModeHeightUndefined;
case RCTRootViewSizeFlexibilityWidth:
return RCTSurfaceSizeMeasureModeWidthUndefined | RCTSurfaceSizeMeasureModeHeightExact;
case RCTRootViewSizeFlexibilityHeight:
return RCTSurfaceSizeMeasureModeWidthExact | RCTSurfaceSizeMeasureModeHeightUndefined;
case RCTRootViewSizeFlexibilityNone:
return RCTSurfaceSizeMeasureModeWidthExact | RCTSurfaceSizeMeasureModeHeightExact;
}
}
static RCTRootViewSizeFlexibility convertToRootViewSizeFlexibility(RCTSurfaceSizeMeasureMode sizeMeasureMode)
{
switch (sizeMeasureMode) {
case RCTSurfaceSizeMeasureModeWidthUndefined | RCTSurfaceSizeMeasureModeHeightUndefined:
return RCTRootViewSizeFlexibilityWidthAndHeight;
case RCTSurfaceSizeMeasureModeWidthUndefined | RCTSurfaceSizeMeasureModeHeightExact:
return RCTRootViewSizeFlexibilityWidth;
case RCTSurfaceSizeMeasureModeWidthExact | RCTSurfaceSizeMeasureModeHeightUndefined:
return RCTRootViewSizeFlexibilityHeight;
case RCTSurfaceSizeMeasureModeWidthExact | RCTSurfaceSizeMeasureModeHeightExact:
default:
return RCTRootViewSizeFlexibilityNone;
}
}
@implementation RCTSurfaceHostingProxyRootView
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
{
RCTAssertMainQueue();
RCTAssert(bridge, @"A bridge instance is required to create an RCTSurfaceHostingProxyRootView");
RCTAssert(moduleName, @"A moduleName is required to create an RCTSurfaceHostingProxyRootView");
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTSurfaceHostingProxyRootView init]", nil);
_bridge = bridge;
if (!bridge.isLoading) {
[bridge.performanceLogger markStartForTag:RCTPLTTI];
}
// `RCTRootViewSizeFlexibilityNone` is the RCTRootView's default.
RCTSurfaceSizeMeasureMode sizeMeasureMode = convertToSurfaceSizeMeasureMode(RCTRootViewSizeFlexibilityNone);
RCTSurface *surface = [[self class] createSurfaceWithBridge:bridge
moduleName:moduleName
initialProperties:initialProperties];
[surface start];
if (self = [super initWithSurface:surface sizeMeasureMode:sizeMeasureMode]) {
self.backgroundColor = [UIColor whiteColor];
}
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
return self;
}
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
launchOptions:(NSDictionary *)launchOptions
{
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:bundleURL moduleProvider:nil launchOptions:launchOptions];
return [self initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
}
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
#pragma mark proxy methods to RCTSurfaceHostingView
- (NSString *)moduleName
{
return super.surface.moduleName;
}
- (UIView *)contentView
{
return self;
}
- (NSNumber *)reactTag
{
return super.surface.rootViewTag;
}
- (RCTRootViewSizeFlexibility)sizeFlexibility
{
return convertToRootViewSizeFlexibility(super.sizeMeasureMode);
}
- (void)setSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility
{
super.sizeMeasureMode = convertToSurfaceSizeMeasureMode(sizeFlexibility);
}
- (NSDictionary *)appProperties
{
return super.surface.properties;
}
- (void)setAppProperties:(NSDictionary *)appProperties
{
[super.surface setProperties:appProperties];
}
- (UIView *)loadingView
{
return super.activityIndicatorViewFactory ? super.activityIndicatorViewFactory() : nil;
}
- (void)setLoadingView:(UIView *)loadingView
{
super.activityIndicatorViewFactory = ^UIView *(void)
{
return loadingView;
};
}
#pragma mark RCTSurfaceDelegate proxying
- (void)surface:(RCTSurface *)surface didChangeStage:(RCTSurfaceStage)stage
{
[super surface:surface didChangeStage:stage];
if (RCTSurfaceStageIsRunning(stage)) {
[_bridge.performanceLogger markStopForTag:RCTPLTTI];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:RCTContentDidAppearNotification object:self];
});
}
}
- (void)surface:(RCTSurface *)surface didChangeIntrinsicSize:(CGSize)intrinsicSize
{
[super surface:surface didChangeIntrinsicSize:intrinsicSize];
[_delegate rootViewDidChangeIntrinsicSize:(RCTRootView *)self];
}
#pragma mark legacy
- (UIViewController *)reactViewController
{
return _reactViewController ?: [super reactViewController];
}
#pragma mark unsupported
- (void)cancelTouches
{
// Not supported.
}
@end

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTSurfaceDelegate.h>
#import <React/RCTSurfaceSizeMeasureMode.h>
#import <React/RCTSurfaceStage.h>
@class RCTBridge;
@class RCTSurface;
typedef UIView *_Nullable (^RCTSurfaceHostingViewActivityIndicatorViewFactory)(void);
NS_ASSUME_NONNULL_BEGIN
/**
* UIView subclass which providers interoperability between UIKit and
* Surface regarding layout and life-cycle.
* This class can be used as easy-to-use general purpose integration point
* of ReactNative-powered experiences in UIKit based apps.
*/
@interface RCTSurfaceHostingView : UIView <RCTSurfaceDelegate>
/**
* Create an instance of RCTSurface to be hosted.
*/
+ (RCTSurface *)createSurfaceWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties;
/**
* Designated initializer.
* Instanciates a view with given Surface object.
* Note: The view retains the surface object.
*/
- (instancetype)initWithSurface:(RCTSurface *)surface
sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode NS_DESIGNATED_INITIALIZER;
/**
* Convenience initializer.
* Instanciates a Surface object with given `bridge`, `moduleName`, and
* `initialProperties`, and then use it to instanciate a view.
*/
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode;
/**
* Surface object which is currently using to power the view.
* Read-only.
*/
@property (nonatomic, strong, readonly) RCTSurface *surface;
/**
* Size measure mode which are defining relationship between UIKit and ReactNative
* layout approaches.
* Defaults to `RCTSurfaceSizeMeasureModeWidthAtMost | RCTSurfaceSizeMeasureModeHeightAtMost`.
*/
@property (nonatomic, assign) RCTSurfaceSizeMeasureMode sizeMeasureMode;
/**
* Activity indicator factory.
* A hosting view may use this block to instantiate and display custom activity
* (loading) indicator (aka "spinner") when it needed.
* Defaults to `nil` (no activity indicator).
*/
@property (nonatomic, copy, nullable) RCTSurfaceHostingViewActivityIndicatorViewFactory activityIndicatorViewFactory;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,247 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSurfaceHostingView.h"
#import "RCTConstants.h"
#import "RCTDefines.h"
#import "RCTSurface.h"
#import "RCTSurfaceDelegate.h"
#import "RCTSurfaceView.h"
#import "RCTUtils.h"
@interface RCTSurfaceHostingView ()
@property (nonatomic, assign) BOOL isActivityIndicatorViewVisible;
@property (nonatomic, assign) BOOL isSurfaceViewVisible;
@end
@implementation RCTSurfaceHostingView {
UIView *_Nullable _activityIndicatorView;
UIView *_Nullable _surfaceView;
RCTSurfaceStage _stage;
}
+ (RCTSurface *)createSurfaceWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
{
return [[RCTSurface alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProperties];
}
RCT_NOT_IMPLEMENTED(-(instancetype)init)
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
RCT_NOT_IMPLEMENTED(-(nullable instancetype)initWithCoder : (NSCoder *)coder)
- (instancetype)initWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initialProperties:(NSDictionary *)initialProperties
sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode
{
RCTSurface *surface = [[self class] createSurfaceWithBridge:bridge
moduleName:moduleName
initialProperties:initialProperties];
[surface start];
return [self initWithSurface:surface sizeMeasureMode:sizeMeasureMode];
}
- (instancetype)initWithSurface:(RCTSurface *)surface sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode
{
if (self = [super initWithFrame:CGRectZero]) {
_surface = surface;
_sizeMeasureMode = sizeMeasureMode;
_surface.delegate = self;
_stage = surface.stage;
[self _updateViews];
}
return self;
}
- (void)dealloc
{
[_surface stop];
}
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
CGSize minimumSize;
CGSize maximumSize;
RCTSurfaceMinimumSizeAndMaximumSizeFromSizeAndSizeMeasureMode(
self.bounds.size, _sizeMeasureMode, &minimumSize, &maximumSize);
[_surface setMinimumSize:minimumSize maximumSize:maximumSize];
}
- (CGSize)intrinsicContentSize
{
if (RCTSurfaceStageIsPreparing(_stage)) {
if (_activityIndicatorView) {
return _activityIndicatorView.intrinsicContentSize;
}
return CGSizeZero;
}
return _surface.intrinsicSize;
}
- (CGSize)sizeThatFits:(CGSize)size
{
if (RCTSurfaceStageIsPreparing(_stage)) {
if (_activityIndicatorView) {
return [_activityIndicatorView sizeThatFits:size];
}
return CGSizeZero;
}
CGSize minimumSize;
CGSize maximumSize;
RCTSurfaceMinimumSizeAndMaximumSizeFromSizeAndSizeMeasureMode(size, _sizeMeasureMode, &minimumSize, &maximumSize);
return [_surface sizeThatFitsMinimumSize:minimumSize maximumSize:maximumSize];
}
- (void)setStage:(RCTSurfaceStage)stage
{
if (stage == _stage) {
return;
}
BOOL shouldInvalidateLayout = RCTSurfaceStageIsRunning(stage) != RCTSurfaceStageIsRunning(_stage) ||
RCTSurfaceStageIsPreparing(stage) != RCTSurfaceStageIsPreparing(_stage);
_stage = stage;
if (shouldInvalidateLayout) {
[self _invalidateLayout];
[self _updateViews];
}
}
- (void)setSizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode
{
if (sizeMeasureMode == _sizeMeasureMode) {
return;
}
_sizeMeasureMode = sizeMeasureMode;
[self _invalidateLayout];
}
#pragma mark - isActivityIndicatorViewVisible
- (void)setIsActivityIndicatorViewVisible:(BOOL)visible
{
if (_isActivityIndicatorViewVisible == visible) {
return;
}
_isActivityIndicatorViewVisible = visible;
if (visible) {
if (_activityIndicatorViewFactory) {
_activityIndicatorView = _activityIndicatorViewFactory();
_activityIndicatorView.frame = self.bounds;
_activityIndicatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:_activityIndicatorView];
}
} else {
[_activityIndicatorView removeFromSuperview];
_activityIndicatorView = nil;
}
}
#pragma mark - isSurfaceViewVisible
- (void)setIsSurfaceViewVisible:(BOOL)visible
{
if (_isSurfaceViewVisible == visible) {
return;
}
_isSurfaceViewVisible = visible;
if (visible) {
_surfaceView = _surface.view;
_surfaceView.frame = self.bounds;
_surfaceView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:_surfaceView];
} else {
[_surfaceView removeFromSuperview];
_surfaceView = nil;
}
}
#pragma mark - activityIndicatorViewFactory
- (void)setActivityIndicatorViewFactory:(RCTSurfaceHostingViewActivityIndicatorViewFactory)activityIndicatorViewFactory
{
_activityIndicatorViewFactory = activityIndicatorViewFactory;
if (_isActivityIndicatorViewVisible) {
self.isActivityIndicatorViewVisible = NO;
self.isActivityIndicatorViewVisible = YES;
}
}
#pragma mark - UITraitCollection updates
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
[super traitCollectionDidChange:previousTraitCollection];
[[NSNotificationCenter defaultCenter]
postNotificationName:RCTUserInterfaceStyleDidChangeNotification
object:self
userInfo:@{
RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey : self.traitCollection,
}];
}
#pragma mark - Private stuff
- (void)_invalidateLayout
{
[self invalidateIntrinsicContentSize];
[self.superview setNeedsLayout];
}
- (void)_updateViews
{
self.isSurfaceViewVisible = RCTSurfaceStageIsRunning(_stage);
self.isActivityIndicatorViewVisible = RCTSurfaceStageIsPreparing(_stage);
}
- (void)didMoveToWindow
{
[super didMoveToWindow];
[self _updateViews];
}
#pragma mark - RCTSurfaceDelegate
- (void)surface:(__unused RCTSurface *)surface didChangeStage:(RCTSurfaceStage)stage
{
RCTExecuteOnMainQueue(^{
[self setStage:stage];
});
}
- (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused CGSize)intrinsicSize
{
RCTExecuteOnMainQueue(^{
[self _invalidateLayout];
});
}
@end

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTDefines.h>
/**
* Bitmask defines how size constrains from `-[UIView sizeThatFits:]`
* are translated to `-[RCTSurface sizeThatFitsMinimumSize:maximumSize:]`.
*/
typedef NS_OPTIONS(NSInteger, RCTSurfaceSizeMeasureMode) {
RCTSurfaceSizeMeasureModeWidthUndefined = 0 << 0,
RCTSurfaceSizeMeasureModeWidthExact = 1 << 0,
RCTSurfaceSizeMeasureModeWidthAtMost = 2 << 0,
RCTSurfaceSizeMeasureModeHeightUndefined = 0 << 2,
RCTSurfaceSizeMeasureModeHeightExact = 1 << 2,
RCTSurfaceSizeMeasureModeHeightAtMost = 2 << 2,
};
/**
* Returns size constraints based on `size` and `sizeMeasureMode`.
*/
RCT_EXTERN void RCTSurfaceMinimumSizeAndMaximumSizeFromSizeAndSizeMeasureMode(
CGSize size,
RCTSurfaceSizeMeasureMode sizeMeasureMode,
CGSize *minimumSize,
CGSize *maximumSize);

Some files were not shown because too many files have changed in this diff Show More