diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m index e9559d558..9e70eeda6 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m @@ -19,7 +19,7 @@ #import "RCTEventDispatcher.h" #import "RCTBridge+Private.h" -@interface RCTTestEvent : NSObject +@interface RCTTestEvent : NSObject @property (atomic, assign, readwrite) BOOL canCoalesce; @end @@ -54,7 +54,7 @@ + (NSString *)moduleDotMethod { - return @"RCTDeviceEventEmitter.emit"; + return @"MyCustomEventemitter.emit"; } - (NSArray *)arguments @@ -100,8 +100,10 @@ - (void)testLegacyEventsAreImmediatelyDispatched { - [[_bridge expect] enqueueJSCall:_JSMethod - args:[_testEvent arguments]]; + [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter" + method:@"emit" + args:[_testEvent arguments] + completion:NULL]; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -154,9 +156,8 @@ [_eventDispatcher sendEvent:_testEvent]; [_bridge verify]; - // eventsEmittingBlock would be called when js is no longer busy, which will result in emitting events - [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit" + [[_bridge expect] enqueueJSCall:[[_testEvent class] moduleDotMethod] args:[_testEvent arguments]]; eventsEmittingBlock(); [_bridge verify]; @@ -174,7 +175,7 @@ eventsEmittingBlock = block; return YES; }] queue:RCTJSThread]; - [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit" + [[_bridge expect] enqueueJSCall:[[_testEvent class] moduleDotMethod] args:[_testEvent arguments]]; RCTTestEvent *ignoredEvent = [[RCTTestEvent alloc] initWithViewTag:nil @@ -201,9 +202,9 @@ eventsEmittingBlock = block; return YES; }] queue:RCTJSThread]; - [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit" + [[_bridge expect] enqueueJSCall:[[_testEvent class] moduleDotMethod] args:[firstEvent arguments]]; - [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit" + [[_bridge expect] enqueueJSCall:[[_testEvent class] moduleDotMethod] args:[_testEvent arguments]]; @@ -231,9 +232,9 @@ eventsEmittingBlock = block; return YES; }] queue:RCTJSThread]; - [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit" + [[_bridge expect] enqueueJSCall:[[_testEvent class] moduleDotMethod] args:[firstEvent arguments]]; - [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit" + [[_bridge expect] enqueueJSCall:[[_testEvent class] moduleDotMethod] args:[secondEvent arguments]]; diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js index 6555631a4..b9347604a 100644 --- a/Libraries/Utilities/MessageQueue.js +++ b/Libraries/Utilities/MessageQueue.js @@ -201,6 +201,11 @@ class MessageQueue { 'Module %s is not a registered callable module.', module ); + invariant( + !!moduleMethods[method], + 'Method %s does not exist on module %s', + method, module + ); const result = moduleMethods[method].apply(moduleMethods, args); Systrace.endEvent(); return result; @@ -219,7 +224,7 @@ class MessageQueue { let errorMessage = `Callback with id ${cbID}: ${module}.${method}() not found`; if (method) { errorMessage = `The callback ${method}() exists in module ${module}, ` - + `but only one callback may be registered to a function in a native module.`; + + 'but only one callback may be registered to a function in a native module.'; } invariant( callback, diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index f45089736..c822f0950 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -557,7 +557,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id)dele NSString *path = [self.bundleURL.path substringFromIndex:1]; // strip initial slash NSString *host = self.bundleURL.host; NSNumber *port = self.bundleURL.port; - [self enqueueJSCall:@"HMRClient.enable" args:@[@"ios", path, host, RCTNullIfNil(port)]]; + [self enqueueJSCall:@"HMRClient" + method:@"enable" + args:@[@"ios", path, host, RCTNullIfNil(port)] + completion:NULL]; } #endif } @@ -745,8 +748,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR - (void)logMessage:(NSString *)message level:(NSString *)level { if (RCT_DEBUG && [_javaScriptExecutor isValid]) { - [self enqueueJSCall:@"RCTLog.logIfNoNativeHook" - args:@[level, message]]; + [self enqueueJSCall:@"RCTLog" + method:@"logIfNoNativeHook" + args:@[level, message] + completion:NULL]; } } diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m index dbfd7a0df..6fe1d4e33 100644 --- a/React/Base/RCTEventDispatcher.m +++ b/React/Base/RCTEventDispatcher.m @@ -63,14 +63,18 @@ RCT_EXPORT_MODULE() - (void)sendAppEventWithName:(NSString *)name body:(id)body { - [_bridge enqueueJSCall:@"RCTNativeAppEventEmitter.emit" - args:body ? @[name, body] : @[name]]; + [_bridge enqueueJSCall:@"RCTNativeAppEventEmitter" + method:@"emit" + args:body ? @[name, body] : @[name] + completion:NULL]; } - (void)sendDeviceEventWithName:(NSString *)name body:(id)body { - [_bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit" - args:body ? @[name, body] : @[name]]; + [_bridge enqueueJSCall:@"RCTDeviceEventEmitter" + method:@"emit" + args:body ? @[name, body] : @[name] + completion:NULL]; } - (void)sendInputEventWithName:(NSString *)name body:(NSDictionary *)body @@ -81,8 +85,10 @@ RCT_EXPORT_MODULE() } name = RCTNormalizeInputEventName(name); - [_bridge enqueueJSCall:@"RCTEventEmitter.receiveEvent" - args:body ? @[body[@"target"], name, body] : @[body[@"target"], name]]; + [_bridge enqueueJSCall:@"RCTEventEmitter" + method:@"receiveEvent" + args:body ? @[body[@"target"], name, body] : @[body[@"target"], name] + completion:NULL]; } - (void)sendTextEventWithType:(RCTTextEventType)type diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index fe0b3ed2d..01c03e105 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -228,8 +228,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) @"initialProps": _appProperties ?: @{}, }; - [bridge enqueueJSCall:@"AppRegistry.runApplication" - args:@[moduleName, appParameters]]; + [bridge enqueueJSCall:@"AppRegistry" + method:@"runApplication" + args:@[moduleName, appParameters] + completion:NULL]; } - (void)setSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility @@ -376,8 +378,10 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder:(nonnull NSCoder *)aDecoder) if (self.userInteractionEnabled) { self.userInteractionEnabled = NO; [(RCTRootView *)self.superview contentViewInvalidated]; - [_bridge enqueueJSCall:@"AppRegistry.unmountApplicationComponentAtRootTag" - args:@[self.reactTag]]; + [_bridge enqueueJSCall:@"AppRegistry" + method:@"unmountApplicationComponentAtRootTag" + args:@[self.reactTag] + completion:NULL]; } } diff --git a/React/Executors/RCTJSCExecutor.mm b/React/Executors/RCTJSCExecutor.mm index 4d8f15acd..97794f62d 100644 --- a/React/Executors/RCTJSCExecutor.mm +++ b/React/Executors/RCTJSCExecutor.mm @@ -559,7 +559,10 @@ static void installBasicSynchronousHooksOnContext(JSContext *context) { [self executeBlockOnJavaScriptQueue:^{ BOOL enabled = [notification.name isEqualToString:RCTProfileDidStartProfiling]; - [self->_bridge enqueueJSCall:@"Systrace.setEnabled" args:@[enabled ? @YES : @NO]]; + [self->_bridge enqueueJSCall:@"Systrace" + method:@"setEnabled" + args:@[enabled ? @YES : @NO] + completion:NULL]; }]; } diff --git a/React/Modules/RCTEventEmitter.m b/React/Modules/RCTEventEmitter.m index 3d4f70a5f..4cfec6575 100644 --- a/React/Modules/RCTEventEmitter.m +++ b/React/Modules/RCTEventEmitter.m @@ -46,8 +46,10 @@ eventName, [self class], [[self supportedEvents] componentsJoinedByString:@"`, `"]); } if (_listenerCount > 0) { - [_bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit" - args:body ? @[eventName, body] : @[eventName]]; + [_bridge enqueueJSCall:@"RCTDeviceEventEmitter" + method:@"emit" + args:body ? @[eventName, body] : @[eventName] + completion:NULL]; } else { RCTLogWarn(@"Sending `%@` with no listeners registered.", eventName); } diff --git a/React/Modules/RCTTiming.m b/React/Modules/RCTTiming.m index 2ae7df17d..d2ab050d7 100644 --- a/React/Modules/RCTTiming.m +++ b/React/Modules/RCTTiming.m @@ -192,7 +192,10 @@ RCT_EXPORT_MODULE() // Call timers that need to be called if (timersToCall.count > 0) { - [_bridge enqueueJSCall:@"JSTimersExecution.callTimers" args:@[timersToCall]]; + [_bridge enqueueJSCall:@"JSTimersExecution" + method:@"callTimers" + args:@[timersToCall] + completion:NULL]; } if (_sendIdleEvents) { @@ -200,7 +203,10 @@ RCT_EXPORT_MODULE() if (kFrameDuration - frameElapsed >= kIdleCallbackFrameDeadline) { NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; NSNumber *absoluteFrameStartMS = @((currentTimestamp - frameElapsed) * 1000); - [_bridge enqueueJSCall:@"JSTimersExecution.callIdleCallbacks" args:@[absoluteFrameStartMS]]; + [_bridge enqueueJSCall:@"JSTimersExecution" + method:@"callIdleCallbacks" + args:@[absoluteFrameStartMS] + completion:NULL]; } }