diff --git a/Examples/SampleApp/SampleApp.xcodeproj/project.pbxproj b/Examples/SampleApp/SampleApp.xcodeproj/project.pbxproj index 5b716c3c0..2ea052a2e 100644 --- a/Examples/SampleApp/SampleApp.xcodeproj/project.pbxproj +++ b/Examples/SampleApp/SampleApp.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 00481BE81AC0C86700671115 /* libRCTWebSocketDebugger.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00481BE61AC0C7FA00671115 /* libRCTWebSocketDebugger.a */; }; - 00481BEA1AC0C89D00671115 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 00481BE91AC0C89D00671115 /* libicucore.dylib */; }; 008F07F31AC5B25A0029DE68 /* main.jsbundle in Resources */ = {isa = PBXBuildFile; fileRef = 008F07F21AC5B25A0029DE68 /* main.jsbundle */; }; 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; 00C302E61ABCBA2D00DB3ED1 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302B41ABCB8E700DB3ED1 /* libRCTAdSupport.a */; }; @@ -116,7 +115,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 00481BEA1AC0C89D00671115 /* libicucore.dylib in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, 00481BE81AC0C86700671115 /* libRCTWebSocketDebugger.a in Frameworks */, 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj index 030e2576c..348d04f0d 100644 --- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj +++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ 004D28A31AAF61C70097A701 /* UIExplorerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 004D28A21AAF61C70097A701 /* UIExplorerTests.m */; }; 00D2771A1AB8C3E100DC1E48 /* libRCTWebSocketDebugger.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00D277131AB8C2C700DC1E48 /* libRCTWebSocketDebugger.a */; }; - 00D2771C1AB8C55500DC1E48 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 00D2771B1AB8C55500DC1E48 /* libicucore.dylib */; }; 13417FE91AA91432003F314A /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FE81AA91428003F314A /* libRCTImage.a */; }; 134180011AA9153C003F314A /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FEF1AA914B8003F314A /* libRCTText.a */; }; 1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; }; @@ -118,7 +117,6 @@ 004D28A11AAF61C70097A701 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 004D28A21AAF61C70097A701 /* UIExplorerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIExplorerTests.m; sourceTree = ""; }; 00D2770E1AB8C2C700DC1E48 /* RCTWebSocketDebugger.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocketDebugger.xcodeproj; path = ../../Libraries/RCTWebSocketDebugger/RCTWebSocketDebugger.xcodeproj; sourceTree = ""; }; - 00D2771B1AB8C55500DC1E48 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; }; 13417FE31AA91428003F314A /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; 13417FEA1AA914B8003F314A /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; 134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; @@ -150,7 +148,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 00D2771C1AB8C55500DC1E48 /* libicucore.dylib in Frameworks */, 14AADF051AC3DBB1002390C9 /* libReact.a in Frameworks */, 00D2771A1AB8C3E100DC1E48 /* libRCTWebSocketDebugger.a in Frameworks */, 58005BF21ABA80A60062E044 /* libRCTTest.a in Frameworks */, @@ -207,7 +204,6 @@ 13417FEA1AA914B8003F314A /* RCTText.xcodeproj */, 00D2770E1AB8C2C700DC1E48 /* RCTWebSocketDebugger.xcodeproj */, D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */, - 00D2771B1AB8C55500DC1E48 /* libicucore.dylib */, ); name = Libraries; sourceTree = ""; diff --git a/Libraries/ActionSheetIOS/RCTActionSheetManager.m b/Libraries/ActionSheetIOS/RCTActionSheetManager.m index b388a4cc8..89ea4e852 100644 --- a/Libraries/ActionSheetIOS/RCTActionSheetManager.m +++ b/Libraries/ActionSheetIOS/RCTActionSheetManager.m @@ -15,10 +15,13 @@ @end -@implementation RCTActionSheetManager { +@implementation RCTActionSheetManager +{ NSMutableDictionary *_callbacks; } +RCT_EXPORT_MODULE() + - (instancetype)init { if ((self = [super init])) { diff --git a/Libraries/AdSupport/RCTAdSupport.m b/Libraries/AdSupport/RCTAdSupport.m index e6be96f6c..3dc1ba641 100644 --- a/Libraries/AdSupport/RCTAdSupport.m +++ b/Libraries/AdSupport/RCTAdSupport.m @@ -11,6 +11,8 @@ @implementation RCTAdSupport +RCT_EXPORT_MODULE() + - (void)getAdvertisingId:(RCTResponseSenderBlock)callback withErrorCallback:(RCTResponseSenderBlock)errorCallback { RCT_EXPORT(); diff --git a/Libraries/Animation/RCTAnimationExperimentalManager.m b/Libraries/Animation/RCTAnimationExperimentalManager.m index b7c76c9f5..8cc180112 100644 --- a/Libraries/Animation/RCTAnimationExperimentalManager.m +++ b/Libraries/Animation/RCTAnimationExperimentalManager.m @@ -25,6 +25,8 @@ RCTSparseArray *_animationRegistry; // Main thread only; animation tag -> view tag } +RCT_EXPORT_MODULE() + @synthesize bridge = _bridge; - (instancetype)init diff --git a/Libraries/Geolocation/RCTLocationObserver.m b/Libraries/Geolocation/RCTLocationObserver.m index d1182bbe6..bdad54189 100644 --- a/Libraries/Geolocation/RCTLocationObserver.m +++ b/Libraries/Geolocation/RCTLocationObserver.m @@ -99,6 +99,8 @@ static NSDictionary *RCTPositionError(RCTPositionErrorCode code, NSString *msg / RCTLocationOptions _observerOptions; } +RCT_EXPORT_MODULE() + @synthesize bridge = _bridge; #pragma mark - Lifecycle diff --git a/Libraries/Image/RCTCameraRollManager.m b/Libraries/Image/RCTCameraRollManager.m index b0734b1bd..92254c26b 100644 --- a/Libraries/Image/RCTCameraRollManager.m +++ b/Libraries/Image/RCTCameraRollManager.m @@ -19,6 +19,8 @@ @implementation RCTCameraRollManager +RCT_EXPORT_MODULE() + - (void)saveImageWithTag:(NSString *)imageTag successCallback:(RCTResponseSenderBlock)successCallback errorCallback:(RCTResponseSenderBlock)errorCallback { RCT_EXPORT(); diff --git a/Libraries/Image/RCTNetworkImageViewManager.m b/Libraries/Image/RCTNetworkImageViewManager.m index 22268e8c0..005b726cf 100644 --- a/Libraries/Image/RCTNetworkImageViewManager.m +++ b/Libraries/Image/RCTNetworkImageViewManager.m @@ -18,6 +18,8 @@ @implementation RCTNetworkImageViewManager +RCT_EXPORT_MODULE() + - (UIView *)view { RCTNetworkImageView *view = [[RCTNetworkImageView alloc] initWithFrame:CGRectZero imageDownloader:[RCTImageDownloader sharedInstance]]; diff --git a/Libraries/Image/RCTStaticImageManager.m b/Libraries/Image/RCTStaticImageManager.m index 7668613bd..2d80117e4 100644 --- a/Libraries/Image/RCTStaticImageManager.m +++ b/Libraries/Image/RCTStaticImageManager.m @@ -18,6 +18,8 @@ @implementation RCTStaticImageManager +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTStaticImage alloc] init]; diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m index 565469c5d..fcde00055 100644 --- a/Libraries/LinkingIOS/RCTLinkingManager.m +++ b/Libraries/LinkingIOS/RCTLinkingManager.m @@ -16,6 +16,8 @@ NSString *const RCTOpenURLNotification = @"RCTOpenURLNotification"; @implementation RCTLinkingManager +RCT_EXPORT_MODULE() + @synthesize bridge = _bridge; - (instancetype)init diff --git a/Libraries/Network/RCTDataManager.m b/Libraries/Network/RCTDataManager.m index 13e3c37ac..f678f17cd 100644 --- a/Libraries/Network/RCTDataManager.m +++ b/Libraries/Network/RCTDataManager.m @@ -15,6 +15,8 @@ @implementation RCTDataManager +RCT_EXPORT_MODULE() + /** * Executes a network request. * The responseSender block won't be called on same thread as called. diff --git a/Libraries/Network/RCTReachability.m b/Libraries/Network/RCTReachability.m index 2dec4f812..d234addfb 100644 --- a/Libraries/Network/RCTReachability.m +++ b/Libraries/Network/RCTReachability.m @@ -23,6 +23,8 @@ static NSString *const RCTReachabilityStateCell = @"cell"; NSString *_status; } +RCT_EXPORT_MODULE() + @synthesize bridge = _bridge; static void RCTReachabilityCallback(__unused SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m index 6a54e457c..14dd97c82 100644 --- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m +++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m @@ -19,6 +19,8 @@ NSString *const RCTRemoteNotificationReceived = @"RemoteNotificationReceived"; NSDictionary *_initialNotification; } +RCT_EXPORT_MODULE() + @synthesize bridge = _bridge; - (instancetype)init diff --git a/Libraries/RCTTest/RCTTestModule.m b/Libraries/RCTTest/RCTTestModule.m index 88bbe0ee6..eccd27f3d 100644 --- a/Libraries/RCTTest/RCTTestModule.m +++ b/Libraries/RCTTest/RCTTestModule.m @@ -13,12 +13,15 @@ #import "RCTAssert.h" #import "RCTLog.h" -@implementation RCTTestModule { +@implementation RCTTestModule +{ __weak FBSnapshotTestController *_snapshotController; __weak UIView *_view; NSMutableDictionary *_snapshotCounter; } +RCT_EXPORT_MODULE() + - (instancetype)initWithSnapshotController:(FBSnapshotTestController *)controller view:(UIView *)view { if ((self = [super init])) { diff --git a/Libraries/RCTWebSocketDebugger/SRWebSocket.m b/Libraries/RCTWebSocketDebugger/SRWebSocket.m index 8cf5b4d74..3fd675103 100644 --- a/Libraries/RCTWebSocketDebugger/SRWebSocket.m +++ b/Libraries/RCTWebSocketDebugger/SRWebSocket.m @@ -19,9 +19,12 @@ #import -#if TARGET_OS_IPHONE -#define HAS_ICU -#endif +//NOTE: libicucore ins't actually needed for the socket to function +//and by commenting this out, we avoid the need to import it into every app. + +//#if TARGET_OS_IPHONE +//#define HAS_ICU +//#endif #ifdef HAS_ICU #import diff --git a/Libraries/Text/RCTRawTextManager.m b/Libraries/Text/RCTRawTextManager.m index ab856d049..221b8daeb 100644 --- a/Libraries/Text/RCTRawTextManager.m +++ b/Libraries/Text/RCTRawTextManager.m @@ -13,6 +13,8 @@ @implementation RCTRawTextManager +RCT_EXPORT_MODULE() + - (UIView *)view { return nil; diff --git a/Libraries/Text/RCTTextManager.m b/Libraries/Text/RCTTextManager.m index d19dfa71e..b8dabcf2c 100644 --- a/Libraries/Text/RCTTextManager.m +++ b/Libraries/Text/RCTTextManager.m @@ -20,6 +20,8 @@ @implementation RCTTextManager +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTText alloc] init]; diff --git a/Libraries/Vibration/RCTVibration.m b/Libraries/Vibration/RCTVibration.m index 0680860b1..a59990d12 100644 --- a/Libraries/Vibration/RCTVibration.m +++ b/Libraries/Vibration/RCTVibration.m @@ -13,6 +13,8 @@ @implementation RCTVibration +RCT_EXPORT_MODULE() + - (void)vibrate { RCT_EXPORT(); diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h index 3f0ad735e..f5c21bb3c 100644 --- a/React/Base/RCTBridge.h +++ b/React/Base/RCTBridge.h @@ -26,8 +26,6 @@ */ typedef NSArray *(^RCTBridgeModuleProviderBlock)(void); -extern NSString *const RCTReloadBridge; - /** * This function returns the module name for a given class. */ @@ -38,8 +36,6 @@ extern NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass); */ @interface RCTBridge : NSObject -@property (nonatomic, assign, readonly, getter=isLoaded) BOOL loaded; - /** * The designated initializer. This creates a new bridge on top of the specified * executor. The bridge should then be used for all subsequent communication @@ -55,16 +51,31 @@ extern NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass); /** * 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. + * with the JavaScript code. Method should be regsitered using the + * RCT_IMPORT_METHOD macro below. Attempting to call a method that has not been + * registered will result in an error. */ - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args; +/** + * This macro is used to register a JS method to be called via the enqueueJSCall + * bridge method. You should place this macro inside any file that uses the + * imported method. If a method has already been registered by another class, it + * is not necessary to register it again, but it is good practice. Registering + * the same method more than once will not result in an error. + */ +#define RCT_IMPORT_METHOD(module, method) \ +__attribute__((used, section("__DATA,RCTImport"))) \ +static const char *__rct_import_##module##_##method##__ = #module"."#method; + /** * This method is used to execute a new application script. It is called * internally whenever a JS application bundle is loaded/reloaded, but should * probably not be used at any other time. */ -- (void)enqueueApplicationScript:(NSString *)script url:(NSURL *)url onComplete:(RCTJavaScriptCompleteBlock)onComplete; +- (void)enqueueApplicationScript:(NSString *)script + url:(NSURL *)url + onComplete:(RCTJavaScriptCompleteBlock)onComplete; @property (nonatomic, strong) Class executorClass; @@ -86,14 +97,19 @@ extern NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass); */ @property (nonatomic, readonly) dispatch_queue_t shadowQueue; +/** + * 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=isLoaded) BOOL loaded; /** - * Method to check that a valid executor exists with which to log + * Reload the bundle and reset executor and modules. */ -+ (BOOL)hasValidJSExecutor; - - (void)reload; @end diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m index fafe34bb2..837950cef 100644 --- a/React/Base/RCTBridge.m +++ b/React/Base/RCTBridge.m @@ -39,11 +39,32 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) { RCTBridgeFieldFlushDateMillis }; -NSString *const RCTReloadBridge = @"RCTReloadBridge"; +#ifdef __LP64__ +typedef uint64_t RCTHeaderValue; +typedef struct section_64 RCTHeaderSection; +#define RCTGetSectByNameFromHeader getsectbynamefromheader_64 +#else +typedef uint32_t RCTHeaderValue; +typedef struct section RCTHeaderSection; +#define RCTGetSectByNameFromHeader getsectbynamefromheader +#endif +/** + * This function returns the module name for a given class. + */ NSString *RCTBridgeModuleNameForClass(Class cls) { - return [cls respondsToSelector:@selector(moduleName)] ? [cls moduleName] : NSStringFromClass(cls); + NSString *name = nil; + if ([cls respondsToSelector:@selector(moduleName)]) { + name = [cls valueForKey:@"moduleName"]; + } + if ([name length] == 0) { + name = NSStringFromClass(cls); + } + if ([name hasPrefix:@"RK"]) { + name = [name stringByReplacingCharactersInRange:(NSRange){0,@"RK".length} withString:@"RCT"]; + } + return name; } /** @@ -57,11 +78,22 @@ static NSArray *RCTJSMethods(void) dispatch_once(&onceToken, ^{ NSMutableSet *uniqueMethods = [NSMutableSet set]; - RCTEnumerateClasses(^(__unsafe_unretained Class cls) { - if (RCTClassOverridesClassMethod(cls, @selector(JSMethods))) { - [uniqueMethods addObjectsFromArray:[cls JSMethods]]; + Dl_info info; + dladdr(&RCTJSMethods, &info); + + const RCTHeaderValue mach_header = (RCTHeaderValue)info.dli_fbase; + const RCTHeaderSection *section = RCTGetSectByNameFromHeader((void *)mach_header, "__DATA", "RCTImport"); + + if (section) { + for (RCTHeaderValue addr = section->offset; + addr < section->offset + section->size; + addr += sizeof(const char **)) { + + // Get data entry + NSString *entry = @(*(const char **)(mach_header + addr)); + [uniqueMethods addObject:entry]; } - }); + } JSMethods = [uniqueMethods allObjects]; }); @@ -70,35 +102,85 @@ static NSArray *RCTJSMethods(void) } /** - * This function scans all classes available at runtime and returns an array - * of all classes that implement the RTCBridgeModule protocol. + * This function scans all exported modules available at runtime and returns an + * array. As a backup, it also scans all classes that implement the + * RTCBridgeModule protocol to ensure they've been exported. This scanning + * functionality is disabled in release mode to improve startup performance. */ static NSArray *RCTModuleNamesByID; +static NSArray *RCTModuleClassesByID; static NSArray *RCTBridgeModuleClassesByModuleID(void) { - static NSArray *modules; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - modules = [NSMutableArray array]; + RCTModuleNamesByID = [NSMutableArray array]; + RCTModuleClassesByID = [NSMutableArray array]; - RCTEnumerateClasses(^(__unsafe_unretained Class cls) { - if ([cls conformsToProtocol:@protocol(RCTBridgeModule)]) { + Dl_info info; + dladdr(&RCTBridgeModuleClassesByModuleID, &info); - // Add module - [(NSMutableArray *)modules addObject:cls]; + const RCTHeaderValue mach_header = (RCTHeaderValue)info.dli_fbase; + const RCTHeaderSection *section = RCTGetSectByNameFromHeader((void *)mach_header, "__DATA", "RCTExportModule"); - // Add module name - NSString *moduleName = RCTBridgeModuleNameForClass(cls); - [(NSMutableArray *)RCTModuleNamesByID addObject:moduleName]; + if (section) { + for (RCTHeaderValue addr = section->offset; + addr < section->offset + section->size; + addr += sizeof(const char **)) { + + // Get data entry + NSString *entry = @(*(const char **)(mach_header + addr)); + NSArray *parts = [[entry substringWithRange:(NSRange){2, entry.length - 3}] componentsSeparatedByString:@" "]; + + // Parse class name + NSString *moduleClassName = parts[0]; + NSRange categoryRange = [moduleClassName rangeOfString:@"("]; + if (categoryRange.length) { + moduleClassName = [moduleClassName substringToIndex:categoryRange.location]; + } + + // Get class + Class cls = NSClassFromString(moduleClassName); + RCTCAssert([cls conformsToProtocol:@protocol(RCTBridgeModule)], + @"%@ does not conform to the RCTBridgeModule protocol", + NSStringFromClass(cls)); + + // Register module + [(NSMutableArray *)RCTModuleNamesByID addObject:RCTBridgeModuleNameForClass(cls)]; + [(NSMutableArray *)RCTModuleClassesByID addObject:cls]; } - }); + } + +#if DEBUG + + // We may be able to get rid of this check in future, once people + // get used to the new registration system. That would potentially + // allow you to create modules that are not automatically registered + + static unsigned int classCount; + Class *classes = objc_copyClassList(&classCount); + for (unsigned int i = 0; i < classCount; i++) + { + Class cls = classes[i]; + Class superclass = cls; + while (superclass) + { + if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule))) + { + if (![RCTModuleClassesByID containsObject:cls]) { + RCTLogError(@"Class %@ was not exported. Did you forget to use RCT_EXPORT_MODULE()?", NSStringFromClass(cls)); + } + break; + } + superclass = class_getSuperclass(superclass); + } + } + +#endif - modules = [modules copy]; - RCTModuleNamesByID = [RCTModuleNamesByID copy]; }); - return modules; + return RCTModuleClassesByID; } @interface RCTBridge () @@ -137,13 +219,12 @@ static Class _globalExecutorClass; if ((self = [super init])) { _methodName = methodName; - NSArray *parts = [[methodName substringWithRange:NSMakeRange(2, methodName.length - 3)] componentsSeparatedByString:@" "]; + NSArray *parts = [[methodName substringWithRange:(NSRange){2, methodName.length - 3}] componentsSeparatedByString:@" "]; // Parse class and method _moduleClassName = parts[0]; NSRange categoryRange = [_moduleClassName rangeOfString:@"("]; - if (categoryRange.length) - { + if (categoryRange.length) { _moduleClassName = [_moduleClassName substringToIndex:categoryRange.location]; } @@ -308,18 +389,8 @@ static RCTSparseArray *RCTExportedMethodsByModuleID(void) Dl_info info; dladdr(&RCTExportedMethodsByModuleID, &info); -#ifdef __LP64__ - typedef uint64_t RCTExportValue; - typedef struct section_64 RCTExportSection; -#define RCTGetSectByNameFromHeader getsectbynamefromheader_64 -#else - typedef uint32_t RCTExportValue; - typedef struct section RCTExportSection; -#define RCTGetSectByNameFromHeader getsectbynamefromheader -#endif - - const RCTExportValue mach_header = (RCTExportValue)info.dli_fbase; - const RCTExportSection *section = RCTGetSectByNameFromHeader((void *)mach_header, "__DATA", "RCTExport"); + const RCTHeaderValue mach_header = (RCTHeaderValue)info.dli_fbase; + const RCTHeaderSection *section = RCTGetSectByNameFromHeader((void *)mach_header, "__DATA", "RCTExport"); if (section == NULL) { return; @@ -328,7 +399,7 @@ static RCTSparseArray *RCTExportedMethodsByModuleID(void) NSArray *classes = RCTBridgeModuleClassesByModuleID(); NSMutableDictionary *methodsByModuleClassName = [NSMutableDictionary dictionaryWithCapacity:[classes count]]; - for (RCTExportValue addr = section->offset; + for (RCTHeaderValue addr = section->offset; addr < section->offset + section->size; addr += sizeof(const char **) * 2) { @@ -593,31 +664,34 @@ static id _latestJSExecutor; _loaded = YES; } else if (_bundlePath != nil) { // Allow testing without a script RCTJavaScriptLoader *loader = [[RCTJavaScriptLoader alloc] initWithBridge:self]; - [loader loadBundleAtURL:[NSURL URLWithString:_bundlePath] - onComplete:^(NSError *error) { - _loaded = YES; - if (error != nil) { - NSArray *stack = [[error userInfo] objectForKey:@"stack"]; - if (stack) { - [[RCTRedBox sharedInstance] showErrorMessage:[error localizedDescription] withStack:stack]; - } else { - [[RCTRedBox sharedInstance] showErrorMessage:[error localizedDescription] withDetails:[error localizedFailureReason]]; - } - } else { - [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification - object:self]; - } - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(reload) - name:RCTReloadNotification - object:nil]; - }]; + [loader loadBundleAtURL:[NSURL URLWithString:_bundlePath] onComplete:^(NSError *error) { + _loaded = YES; + if (error != nil) { + NSArray *stack = [[error userInfo] objectForKey:@"stack"]; + if (stack) { + [[RCTRedBox sharedInstance] showErrorMessage:[error localizedDescription] + withStack:stack]; + } else { + [[RCTRedBox sharedInstance] showErrorMessage:[error localizedDescription] + withDetails:[error localizedFailureReason]]; + } + } else { + [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification + object:self]; + } + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(reload) + name:RCTReloadNotification + object:nil]; + }]; } } - (void)bindKeys { #if TARGET_IPHONE_SIMULATOR + __weak RCTBridge *weakSelf = self; + // Workaround around the first cmd+r not working: http://openradar.appspot.com/19613391 // You can register just the cmd key and do nothing. This will trigger the bug and cmd+r // will work like a charm! @@ -626,31 +700,38 @@ static id _latestJSExecutor; action:^(UIKeyCommand *command) { // Do nothing }]; - [[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"r" modifierFlags:UIKeyModifierCommand action:^(UIKeyCommand *command) { - [self reload]; + [weakSelf reload]; }]; [[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"n" modifierFlags:UIKeyModifierCommand action:^(UIKeyCommand *command) { - _executorClass = Nil; - [self reload]; + RCTBridge *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + strongSelf->_executorClass = Nil; + [strongSelf reload]; }]; - [[RCTKeyCommands sharedInstance] registerKeyCommandWithInput:@"d" modifierFlags:UIKeyModifierCommand action:^(UIKeyCommand *command) { - _executorClass = NSClassFromString(@"RCTWebSocketExecutor"); - if (!_executorClass) { + RCTBridge *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + strongSelf->_executorClass = NSClassFromString(@"RCTWebSocketExecutor"); + if (!strongSelf->_executorClass) { RCTLogError(@"WebSocket debugger is not available. Did you forget to include RCTWebSocketExecutor?"); } - [self reload]; + [strongSelf reload]; }]; #endif } + - (NSDictionary *)modules { RCTAssert(_modulesByName != nil, @"Bridge modules have not yet been initialized. \ @@ -882,15 +963,9 @@ static id _latestJSExecutor; } } -+ (BOOL)hasValidJSExecutor -{ - return (_latestJSExecutor != nil && [_latestJSExecutor isValid]); -} - + (void)logMessage:(NSString *)message level:(NSString *)level { if (!_latestJSExecutor || ![_latestJSExecutor isValid]) { - RCTLogError(@"ERROR: No valid JS executor to log '%@'.", message); return; } diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h index 2134dc2e5..ddc6785ed 100644 --- a/React/Base/RCTBridgeModule.h +++ b/React/Base/RCTBridgeModule.h @@ -9,8 +9,6 @@ #import -#import "RCTJSMethodRegistrar.h" - @class RCTBridge; /** @@ -22,7 +20,7 @@ typedef void (^RCTResponseSenderBlock)(NSArray *response); /** * Provides the interface needed to register a bridge module. */ -@protocol RCTBridgeModule +@protocol RCTBridgeModule @optional /** @@ -34,10 +32,14 @@ typedef void (^RCTResponseSenderBlock)(NSArray *response); @property (nonatomic, strong) RCTBridge *bridge; /** - * The module name exposed to JS. If omitted, this will be inferred - * automatically by using the native module's class name. + * 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. */ -+ (NSString *)moduleName; +#define RCT_EXPORT_MODULE(js_name) \ ++ (NSString *)moduleName { __attribute__((used, section("__DATA,RCTExportModule" \ +))) static const char *__rct_export_entry__ = { __func__ }; return @#js_name; } \ /** * Place this macro inside the method body of any method you want to expose diff --git a/React/Base/RCTDevMenu.m b/React/Base/RCTDevMenu.m index f6eee2cd4..fdb79b8fb 100644 --- a/React/Base/RCTDevMenu.m +++ b/React/Base/RCTDevMenu.m @@ -67,7 +67,7 @@ - (void)_pollAndReload { if (_liveReload) { - RCTSourceCode *sourceCodeModule = self.bridge.modules[NSStringFromClass([RCTSourceCode class])]; + RCTSourceCode *sourceCodeModule = self.bridge.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])]; NSURL *url = sourceCodeModule.scriptURL; NSURL *longPollURL = [[NSURL alloc] initWithString:@"/onchange" relativeToURL:url]; [self performSelectorInBackground:@selector(_checkForUpdates:) withObject:longPollURL]; diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m index a83ce58cc..c82eca01c 100644 --- a/React/Base/RCTEventDispatcher.m +++ b/React/Base/RCTEventDispatcher.m @@ -25,14 +25,9 @@ return self; } -+ (NSArray *)JSMethods -{ - return @[ - @"RCTNativeAppEventEmitter.emit", - @"RCTDeviceEventEmitter.emit", - @"RCTEventEmitter.receiveEvent", - ]; -} +RCT_IMPORT_METHOD(RCTNativeAppEventEmitter, emit); +RCT_IMPORT_METHOD(RCTDeviceEventEmitter, emit); +RCT_IMPORT_METHOD(RCTEventEmitter, receiveEvent); - (void)sendAppEventWithName:(NSString *)name body:(id)body { diff --git a/React/Base/RCTJSMethodRegistrar.h b/React/Base/RCTJSMethodRegistrar.h deleted file mode 100644 index 9d7212d07..000000000 --- a/React/Base/RCTJSMethodRegistrar.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import - -@class RCTBridge; - -/** - * Provides an interface to register JS methods to be called via the bridge. - */ -@protocol RCTJSMethodRegistrar -@optional - -/** - * An array of JavaScript methods that the class will call via the - * -[RCTBridge enqueueJSCall:args:] method. Each method should be specified - * as a string of the form "JSModuleName.jsMethodName". Attempting to call a - * method that has not been registered will result in an error. If a method - * has already been registered by another class, it is not necessary to - * register it again, but it is good practice. Registering the same method - * more than once is silently ignored and will not result in an error. - */ -+ (NSArray *)JSMethods; - -@end diff --git a/React/Base/RCTJavaScriptLoader.m b/React/Base/RCTJavaScriptLoader.m index 3d2974e98..518916c92 100755 --- a/React/Base/RCTJavaScriptLoader.m +++ b/React/Base/RCTJavaScriptLoader.m @@ -128,7 +128,7 @@ onComplete(error); return; } - RCTSourceCode *sourceCodeModule = _bridge.modules[NSStringFromClass([RCTSourceCode class])]; + RCTSourceCode *sourceCodeModule = _bridge.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])]; sourceCodeModule.scriptURL = scriptURL; sourceCodeModule.scriptText = rawText; diff --git a/React/Base/RCTLog.h b/React/Base/RCTLog.h index c30da141b..bc19448ac 100644 --- a/React/Base/RCTLog.h +++ b/React/Base/RCTLog.h @@ -42,8 +42,7 @@ typedef NS_ENUM(NSInteger, RCTLogLevel) { /** * 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, or use the RCTSimpleLogFunction() constructor to register - * a simple function that does not use all of the arguments. + * generate a string. */ typedef void (^RCTLogFunction)( RCTLogLevel level, @@ -65,13 +64,6 @@ NSString *RCTFormatLog( NSString *message ); -/** - * A method to generate a log function from a block with a much simpler - * template. The message passed to the simpler block is equivalent to the - * output of the RCTFormatLog() function. - */ -RCTLogFunction RCTSimpleLogFunction(void (^logFunction)(RCTLogLevel level, NSString *message)); - /** * The default logging function used by RCTLogXX. */ diff --git a/React/Base/RCTLog.m b/React/Base/RCTLog.m index d2de897f1..d5e495d8c 100644 --- a/React/Base/RCTLog.m +++ b/React/Base/RCTLog.m @@ -116,12 +116,11 @@ NSString *RCTFormatLog( }); [log appendString:[formatter stringFromDate:timestamp]]; } - [log appendString:@"[react]"]; if (level) { [log appendFormat:@"[%s]", RCTLogLevels[level - 1]]; } if (thread) { - NSString *threadName = thread.name; + NSString *threadName = [thread isMainThread] ? @"main" : thread.name; if (threadName.length == 0) { #if DEBUG #pragma clang diagnostic push @@ -149,19 +148,6 @@ NSString *RCTFormatLog( return log; } -RCTLogFunction RCTSimpleLogFunction(void (^logFunction)(RCTLogLevel level, NSString *message)) -{ - return ^(RCTLogLevel level, - NSString *fileName, - NSNumber *lineNumber, - NSString *message) { - - logFunction(level, RCTFormatLog( - [NSDate date], [NSThread currentThread], level, fileName, lineNumber, message - )); - }; -} - void _RCTLogFormat(RCTLogLevel level, const char *fileName, int lineNumber, NSString *format, ...) { if (RCTCurrentLogFunction && level >= RCTCurrentLogThreshold) { @@ -193,9 +179,7 @@ void _RCTLogFormat(RCTLogLevel level, const char *fileName, int lineNumber, NSSt } // Log to JS executor - if ([RCTBridge hasValidJSExecutor]) { - [RCTBridge logMessage:message level:level ? @(RCTLogLevels[level - 1]) : @"info"]; - } + [RCTBridge logMessage:message level:level ? @(RCTLogLevels[level - 1]) : @"info"]; #endif diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index 6c15e509c..02d7ef447 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -162,13 +162,8 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification"; } } -+ (NSArray *)JSMethods -{ - return @[ - @"AppRegistry.runApplication", - @"ReactIOS.unmountComponentAtNodeAndRemoveContainer" - ]; -} +RCT_IMPORT_METHOD(AppRegistry, runApplication) +RCT_IMPORT_METHOD(ReactIOS, unmountComponentAtNodeAndRemoveContainer) - (void)bundleFinishedLoading { @@ -176,9 +171,9 @@ NSString *const RCTReloadViewsNotification = @"RCTReloadViewsNotification"; _registered = YES; NSString *moduleName = _moduleName ?: @""; NSDictionary *appParameters = @{ - @"rootTag": _contentView.reactTag, - @"initialProps": self.initialProperties ?: @{}, - }; + @"rootTag": _contentView.reactTag, + @"initialProps": self.initialProperties ?: @{}, + }; [_bridge.uiManager registerRootView:_contentView]; [_bridge enqueueJSCall:@"AppRegistry.runApplication" args:@[moduleName, appParameters]]; diff --git a/React/Base/RCTTouchHandler.m b/React/Base/RCTTouchHandler.m index b5d3b1e72..d409ec3e5 100644 --- a/React/Base/RCTTouchHandler.m +++ b/React/Base/RCTTouchHandler.m @@ -200,10 +200,7 @@ typedef NS_ENUM(NSInteger, RCTTouchEventType) { reactTouch[@"timestamp"] = @(nativeTouch.timestamp * 1000); // in ms, for JS } -+ (NSArray *)JSMethods -{ - return @[@"RCTEventEmitter.receiveTouches"]; -} +RCT_IMPORT_METHOD(RCTEventEmitter, receiveTouches); /** * Constructs information about touch events to send across the serialized diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h index 4a6336e20..d20ba8a5f 100644 --- a/React/Base/RCTUtils.h +++ b/React/Base/RCTUtils.h @@ -45,9 +45,6 @@ void RCTSwapInstanceMethods(Class cls, SEL original, SEL replacement); BOOL RCTClassOverridesClassMethod(Class cls, SEL selector); BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector); -// Enumerate all classes that conform to NSObject protocol -void RCTEnumerateClasses(void (^block)(Class cls)); - // Creates a standardized error object // TODO(#6472857): create NSErrors and automatically convert them over the bridge. NSDictionary *RCTMakeError(NSString *message, id toStringify, NSDictionary *extraData); diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m index 300f6d721..cea45c324 100644 --- a/React/Base/RCTUtils.m +++ b/React/Base/RCTUtils.m @@ -183,31 +183,6 @@ BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector) return NO; } -void RCTEnumerateClasses(void (^block)(Class cls)) -{ - static Class *classes; - static unsigned int classCount; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - classes = objc_copyClassList(&classCount); - }); - - for (unsigned int i = 0; i < classCount; i++) - { - Class cls = classes[i]; - Class superclass = cls; - while (superclass) - { - if (class_conformsToProtocol(superclass, @protocol(NSObject))) - { - block(cls); - break; - } - superclass = class_getSuperclass(superclass); - } - } -} - NSDictionary *RCTMakeError(NSString *message, id toStringify, NSDictionary *extraData) { if (toStringify) { diff --git a/React/Modules/RCTAlertManager.m b/React/Modules/RCTAlertManager.m index bda7c357e..5ffb9c396 100644 --- a/React/Modules/RCTAlertManager.m +++ b/React/Modules/RCTAlertManager.m @@ -23,6 +23,8 @@ NSMutableArray *_alertButtonKeys; } +RCT_EXPORT_MODULE() + - (instancetype)init { if ((self = [super init])) { diff --git a/React/Modules/RCTAppState.m b/React/Modules/RCTAppState.m index ab44a70a3..148bbfc3c 100644 --- a/React/Modules/RCTAppState.m +++ b/React/Modules/RCTAppState.m @@ -33,6 +33,8 @@ static NSString *RCTCurrentAppBackgroundState() NSString *_lastKnownState; } +RCT_EXPORT_MODULE() + @synthesize bridge = _bridge; #pragma mark - Lifecycle diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m index 95fb383e4..feec17048 100644 --- a/React/Modules/RCTAsyncLocalStorage.m +++ b/React/Modules/RCTAsyncLocalStorage.m @@ -88,6 +88,8 @@ static dispatch_queue_t RCTFileQueue(void) NSString *_storageDirectory; } +RCT_EXPORT_MODULE() + - (NSString *)_filePathForKey:(NSString *)key { NSString *safeFileName = RCTMD5Hash(key); diff --git a/React/Modules/RCTExceptionsManager.m b/React/Modules/RCTExceptionsManager.m index 01b701f54..97806011f 100644 --- a/React/Modules/RCTExceptionsManager.m +++ b/React/Modules/RCTExceptionsManager.m @@ -16,6 +16,8 @@ __weak id _delegate; } +RCT_EXPORT_MODULE() + - (instancetype)initWithDelegate:(id)delegate { if ((self = [super init])) { diff --git a/React/Modules/RCTSourceCode.m b/React/Modules/RCTSourceCode.m index 9ccc0269d..1afffc3db 100644 --- a/React/Modules/RCTSourceCode.m +++ b/React/Modules/RCTSourceCode.m @@ -14,6 +14,8 @@ @implementation RCTSourceCode +RCT_EXPORT_MODULE() + - (void)getScriptText:(RCTResponseSenderBlock)successCallback failureCallback:(RCTResponseSenderBlock)failureCallback { RCT_EXPORT(); diff --git a/React/Modules/RCTStatusBarManager.m b/React/Modules/RCTStatusBarManager.m index 258ef4e8c..2cc2bc40a 100644 --- a/React/Modules/RCTStatusBarManager.m +++ b/React/Modules/RCTStatusBarManager.m @@ -24,6 +24,8 @@ static BOOL RCTViewControllerBasedStatusBarAppearance() return value; } +RCT_EXPORT_MODULE() + - (void)setStyle:(UIStatusBarStyle)statusBarStyle animated:(BOOL)animated { RCT_EXPORT(); diff --git a/React/Modules/RCTTiming.m b/React/Modules/RCTTiming.m index 5fd46e21c..734046047 100644 --- a/React/Modules/RCTTiming.m +++ b/React/Modules/RCTTiming.m @@ -61,12 +61,11 @@ id _updateTimer; } +RCT_EXPORT_MODULE() + @synthesize bridge = _bridge; -+ (NSArray *)JSMethods -{ - return @[@"RCTJSTimers.callTimers"]; -} +RCT_IMPORT_METHOD(RCTJSTimers, callTimers) - (instancetype)init { diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index c21adc1d0..1ecc868b5 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -195,6 +195,8 @@ static UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimatio NSUInteger _rootTag; } +RCT_EXPORT_MODULE() + @synthesize bridge = _bridge; /** @@ -209,6 +211,7 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls); static NSString *RCTViewNameForModuleName(NSString *moduleName) { NSString *name = moduleName; + RCTCAssert(name.length, @"Invalid moduleName '%@'", moduleName); if ([name hasSuffix:@"Manager"]) { name = [name substringToIndex:name.length - @"Manager".length]; } @@ -797,7 +800,7 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView RCT_EXPORT(); RCTViewManager *viewManager = _viewManagerRegistry[reactTag]; - NSString *viewName = RCTViewNameForModuleName([[viewManager class] moduleName]); + NSString *viewName = RCTViewNameForModuleName(RCTBridgeModuleNameForClass([viewManager class])); RCTShadowView *shadowView = _shadowViewRegistry[reactTag]; RCTSetShadowViewProps(props, shadowView, _defaultShadowViews[viewName], viewManager); @@ -1417,7 +1420,8 @@ static void RCTMeasureLayout(RCTShadowView *view, if (config[@"delete"] != nil) { RCTLogError(@"LayoutAnimation only supports create and update right now. Config: %@", config); } - _nextLayoutAnimation = [[RCTLayoutAnimation alloc] initWithDictionary:config callback:callback]; + _nextLayoutAnimation = [[RCTLayoutAnimation alloc] initWithDictionary:config + callback:callback]; } - (void)startOrResetInteractionTiming @@ -1449,7 +1453,7 @@ static void RCTMeasureLayout(RCTShadowView *view, timingData[reactTag.stringValue] = [rootView endAndResetInteractionTiming]; } } - onSuccess(@[ timingData ]); + onSuccess(@[timingData]); }]; } @@ -1466,7 +1470,7 @@ static UIView *_jsResponder; - (RCTUIManager *)uiManager { - return self.modules[NSStringFromClass([RCTUIManager class])]; + return self.modules[RCTBridgeModuleNameForClass([RCTUIManager class])]; } @end diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index f8dfd3862..5c9c13355 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -146,7 +146,6 @@ 13E067501A70F44B002CDEE1 /* RCTView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTView.m; sourceTree = ""; }; 13E067531A70F44B002CDEE1 /* UIView+React.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+React.h"; sourceTree = ""; }; 13E067541A70F44B002CDEE1 /* UIView+React.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+React.m"; sourceTree = ""; }; - 13EFFCCF1A98E6FE002607DC /* RCTJSMethodRegistrar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSMethodRegistrar.h; sourceTree = ""; }; 14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJavaScriptLoader.h; sourceTree = ""; }; 14200DA91AC179B3008EE6BA /* RCTJavaScriptLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJavaScriptLoader.m; sourceTree = ""; }; 14435CE11AAC4AE100FC20F4 /* RCTMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMap.h; sourceTree = ""; }; @@ -366,7 +365,6 @@ 83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */, 83CBBA4C1A601E3B00E9B192 /* RCTInvalidating.h */, 83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */, - 13EFFCCF1A98E6FE002607DC /* RCTJSMethodRegistrar.h */, 13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */, 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */, 83CBBA4D1A601E3B00E9B192 /* RCTLog.h */, diff --git a/React/Views/RCTDatePickerManager.m b/React/Views/RCTDatePickerManager.m index 4029998c2..36397d6e5 100644 --- a/React/Views/RCTDatePickerManager.m +++ b/React/Views/RCTDatePickerManager.m @@ -27,6 +27,8 @@ RCT_ENUM_CONVERTER(UIDatePickerMode, (@{ @implementation RCTDatePickerManager +RCT_EXPORT_MODULE() + - (UIView *)view { UIDatePicker *picker = [[UIDatePicker alloc] init]; diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m index 9bd0f7eab..24d8bee16 100644 --- a/React/Views/RCTMapManager.m +++ b/React/Views/RCTMapManager.m @@ -54,6 +54,8 @@ @implementation RCTMapManager +RCT_EXPORT_MODULE() + - (UIView *)view { RCTMap *map = [[RCTMap alloc] init]; diff --git a/React/Views/RCTNavItemManager.m b/React/Views/RCTNavItemManager.m index 549859ae0..b6d38ac00 100644 --- a/React/Views/RCTNavItemManager.m +++ b/React/Views/RCTNavItemManager.m @@ -14,6 +14,8 @@ @implementation RCTNavItemManager +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTNavItem alloc] init]; diff --git a/React/Views/RCTNavigatorManager.m b/React/Views/RCTNavigatorManager.m index 7df00c764..b508d6318 100644 --- a/React/Views/RCTNavigatorManager.m +++ b/React/Views/RCTNavigatorManager.m @@ -17,6 +17,8 @@ @implementation RCTNavigatorManager +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTNavigator alloc] initWithEventDispatcher:self.bridge.eventDispatcher]; diff --git a/React/Views/RCTPickerManager.m b/React/Views/RCTPickerManager.m index cffacca68..3bbc60b94 100644 --- a/React/Views/RCTPickerManager.m +++ b/React/Views/RCTPickerManager.m @@ -15,6 +15,8 @@ @implementation RCTPickerManager +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTPicker alloc] initWithEventDispatcher:self.bridge.eventDispatcher]; diff --git a/React/Views/RCTScrollViewManager.m b/React/Views/RCTScrollViewManager.m index 066d28adc..9274b46cb 100644 --- a/React/Views/RCTScrollViewManager.m +++ b/React/Views/RCTScrollViewManager.m @@ -17,6 +17,8 @@ @implementation RCTScrollViewManager +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTScrollView alloc] initWithEventDispatcher:self.bridge.eventDispatcher]; diff --git a/React/Views/RCTSliderManager.m b/React/Views/RCTSliderManager.m index 0228eab68..58b763b92 100644 --- a/React/Views/RCTSliderManager.m +++ b/React/Views/RCTSliderManager.m @@ -15,6 +15,8 @@ @implementation RCTSliderManager +RCT_EXPORT_MODULE() + - (UIView *)view { UISlider *slider = [[UISlider alloc] init]; diff --git a/React/Views/RCTSwitchManager.m b/React/Views/RCTSwitchManager.m index e2118023d..eb0d626e6 100644 --- a/React/Views/RCTSwitchManager.m +++ b/React/Views/RCTSwitchManager.m @@ -16,6 +16,8 @@ @implementation RCTSwitchManager +RCT_EXPORT_MODULE() + - (UIView *)view { RCTSwitch *switcher = [[RCTSwitch alloc] init]; diff --git a/React/Views/RCTTabBarItemManager.m b/React/Views/RCTTabBarItemManager.m index 7f4ce9642..8bbe782b7 100644 --- a/React/Views/RCTTabBarItemManager.m +++ b/React/Views/RCTTabBarItemManager.m @@ -14,6 +14,8 @@ @implementation RCTTabBarItemManager +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTTabBarItem alloc] init]; diff --git a/React/Views/RCTTabBarManager.m b/React/Views/RCTTabBarManager.m index 7ff9ef075..973a1c972 100644 --- a/React/Views/RCTTabBarManager.m +++ b/React/Views/RCTTabBarManager.m @@ -14,6 +14,8 @@ @implementation RCTTabBarManager +RCT_EXPORT_MODULE() + @synthesize bridge = _bridge; - (UIView *)view diff --git a/React/Views/RCTTextFieldManager.m b/React/Views/RCTTextFieldManager.m index 041474643..3cfdd53a1 100644 --- a/React/Views/RCTTextFieldManager.m +++ b/React/Views/RCTTextFieldManager.m @@ -17,6 +17,8 @@ @implementation RCTTextFieldManager +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTTextField alloc] initWithEventDispatcher:self.bridge.eventDispatcher]; diff --git a/React/Views/RCTUIActivityIndicatorViewManager.m b/React/Views/RCTUIActivityIndicatorViewManager.m index 09a5cb6f9..e2c9b3d35 100644 --- a/React/Views/RCTUIActivityIndicatorViewManager.m +++ b/React/Views/RCTUIActivityIndicatorViewManager.m @@ -24,6 +24,8 @@ RCT_ENUM_CONVERTER(UIActivityIndicatorViewStyle, (@{ @implementation RCTUIActivityIndicatorViewManager +RCT_EXPORT_MODULE(UIActivityIndicatorViewManager) + - (UIView *)view { return [[UIActivityIndicatorView alloc] init]; diff --git a/React/Views/RCTViewManager.h b/React/Views/RCTViewManager.h index 32babecc9..17d89dff6 100644 --- a/React/Views/RCTViewManager.h +++ b/React/Views/RCTViewManager.h @@ -30,14 +30,6 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, RCTSparseArray *v */ @property (nonatomic, strong) RCTBridge *bridge; -/** - * The module name exposed to React JS. If omitted, this will be inferred - * automatically by using the view module's class name. It is better to not - * override this, and just follow standard naming conventions for your view - * module subclasses. - */ -+ (NSString *)moduleName; - /** * This method instantiates a native view to be managed by the module. Override * this to return a custom view instance, which may be preconfigured with default diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 50d55a8a7..330a597f8 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -19,20 +19,9 @@ @implementation RCTViewManager -@synthesize bridge = _bridge; +RCT_EXPORT_MODULE() -+ (NSString *)moduleName -{ - // Default implementation, works in most cases - NSString *name = NSStringFromClass(self); - if ([name hasPrefix:@"RK"]) { - name = [name stringByReplacingCharactersInRange:(NSRange){0,@"RK".length} withString:@"RCT"]; - } - if ([name hasPrefix:@"RCTUI"]) { - name = [name substringFromIndex:@"RCT".length]; - } - return name; -} +@synthesize bridge = _bridge; - (UIView *)view { diff --git a/React/Views/RCTWebViewManager.m b/React/Views/RCTWebViewManager.m index 7525ee236..0843f25ba 100644 --- a/React/Views/RCTWebViewManager.m +++ b/React/Views/RCTWebViewManager.m @@ -16,6 +16,8 @@ @implementation RCTWebViewManager +RCT_EXPORT_MODULE() + - (UIView *)view { return [[RCTWebView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];