#import #ifdef RCT_NEW_ARCH_ENABLED #import #import #import #import #import #import #if REACT_NATIVE_MINOR_VERSION < 73 #import #endif // REACT_NATIVE_MINOR_VERSION < 73 #endif // RCT_NEW_ARCH_ENABLED #ifdef RCT_NEW_ARCH_ENABLED #import #endif // RCT_NEW_ARCH_ENABLED #import #import #import #import #import #import #import #import #import #if __has_include() #import #endif // __has_include() using namespace facebook::react; using namespace reanimated; @interface RCTBridge (JSIRuntime) - (void *)runtime; @end @interface RCTBridge (RCTTurboModule) - (std::shared_ptr)jsCallInvoker; - (void)_tryAndHandleError:(dispatch_block_t)block; @end #ifdef RCT_NEW_ARCH_ENABLED static __strong REAInitializerRCTFabricSurface *reaSurface; #else typedef void (^AnimatedOperation)(REANodesManager *nodesManager); #endif // RCT_NEW_ARCH_ENABLED @implementation REAModule { #ifdef RCT_NEW_ARCH_ENABLED __weak RCTSurfacePresenter *_surfacePresenter; std::weak_ptr weakNativeReanimatedModule_; #else NSMutableArray *_operations; #endif // RCT_NEW_ARCH_ENABLED #ifndef NDEBUG SingleInstanceChecker singleInstanceChecker_; #endif // NDEBUG bool hasListeners; bool _isBridgeless; } @synthesize moduleRegistry = _moduleRegistry; #if REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED) @synthesize runtimeExecutor = _runtimeExecutor; #endif // REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED) RCT_EXPORT_MODULE(ReanimatedModule); #ifdef RCT_NEW_ARCH_ENABLED + (BOOL)requiresMainQueueSetup { return YES; } #endif // RCT_NEW_ARCH_ENABLED - (void)invalidate { #ifdef RCT_NEW_ARCH_ENABLED [[NSNotificationCenter defaultCenter] removeObserver:self]; #endif // RCT_NEW_ARCH_ENABLED [_nodesManager invalidate]; [super invalidate]; } - (dispatch_queue_t)methodQueue { // This module needs to be on the same queue as the UIManager to avoid // having to lock `_operations` and `_preOperations` since `uiManagerWillPerformMounting` // will be called from that queue. return RCTGetUIManagerQueue(); } #ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getUIManager { RCTScheduler *scheduler = [_surfacePresenter scheduler]; return scheduler.uiManager; } - (void)injectDependencies:(jsi::Runtime &)runtime { const auto &uiManager = [self getUIManager]; react_native_assert(uiManager.get() != nil); if (auto nativeReanimatedModule = weakNativeReanimatedModule_.lock()) { nativeReanimatedModule->initializeFabric(uiManager); } } #pragma mark-- Initialize - (void)installReanimatedAfterReload { // called from REAInitializerRCTFabricSurface::start __weak __typeof__(self) weakSelf = self; _surfacePresenter = self.bridge.surfacePresenter; [_nodesManager setSurfacePresenter:_surfacePresenter]; // to avoid deadlock we can't use Executor from React Native // but we can create own and use it because initialization is already synchronized react_native_assert(self.bridge != nil); RCTRuntimeExecutorFromBridge(self.bridge)(^(jsi::Runtime &runtime) { if (__typeof__(self) strongSelf = weakSelf) { [strongSelf injectDependencies:runtime]; } }); } - (void)handleJavaScriptDidLoadNotification:(NSNotification *)notification { [self attachReactEventListener]; } - (void)attachReactEventListener { RCTScheduler *scheduler = [_surfacePresenter scheduler]; __weak __typeof__(self) weakSelf = self; _surfacePresenter.runtimeExecutor(^(jsi::Runtime &runtime) { __typeof__(self) strongSelf = weakSelf; if (strongSelf == nil) { return; } if (auto nativeReanimatedModule = strongSelf->weakNativeReanimatedModule_.lock()) { auto eventListener = std::make_shared([nativeReanimatedModule](const RawEvent &rawEvent) { if (!RCTIsMainQueue()) { // event listener called on the JS thread, let's ignore this event // as we cannot safely access worklet runtime here // and also we don't care about topLayout events return false; } return nativeReanimatedModule->handleRawEvent(rawEvent, CACurrentMediaTime() * 1000); }); [scheduler addEventListener:eventListener]; } }); } #pragma mark-- Bridgeless methods /* * Taken from RCTNativeAnimatedTurboModule: * This selector is invoked via BridgelessTurboModuleSetup. */ - (void)setSurfacePresenter:(id)surfacePresenter { _surfacePresenter = surfacePresenter; _isBridgeless = true; } - (void)setBridge:(RCTBridge *)bridge { [super setBridge:bridge]; // only within the first loading `self.bridge.surfacePresenter` exists // during the reload `self.bridge.surfacePresenter` is null if (self.bridge.surfacePresenter) { _surfacePresenter = self.bridge.surfacePresenter; } [self setReaSurfacePresenter]; _nodesManager = [[REANodesManager alloc] initWithModule:self bridge:bridge surfacePresenter:_surfacePresenter]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleJavaScriptDidLoadNotification:) name:RCTJavaScriptDidLoadNotification object:nil]; [[self.moduleRegistry moduleForName:"EventDispatcher"] addDispatchObserver:self]; } - (void)setReaSurfacePresenter { if (reaSurface == nil) { // we need only one instance because SurfacePresenter is the same during the application lifetime reaSurface = [[REAInitializerRCTFabricSurface alloc] init]; [_surfacePresenter registerSurface:reaSurface]; } reaSurface.reaModule = self; } #else // RCT_NEW_ARCH_ENABLED - (void)setBridge:(RCTBridge *)bridge { [super setBridge:bridge]; _nodesManager = [[REANodesManager alloc] initWithModule:self uiManager:self.bridge.uiManager]; _operations = [NSMutableArray new]; [bridge.uiManager.observerCoordinator addObserver:self]; _animationsManager = [[REAAnimationsManager alloc] initWithUIManager:bridge.uiManager]; } #pragma mark-- Batch handling - (void)addOperationBlock:(AnimatedOperation)operation { [_operations addObject:operation]; } #pragma mark - RCTUIManagerObserver - (void)uiManagerWillPerformMounting:(RCTUIManager *)uiManager { [_nodesManager maybeFlushUpdateBuffer]; if (_operations.count == 0) { return; } NSArray *operations = _operations; _operations = [NSMutableArray new]; REANodesManager *nodesManager = _nodesManager; [uiManager addUIBlock:^(__unused RCTUIManager *manager, __unused NSDictionary *viewRegistry) { for (AnimatedOperation operation in operations) { operation(nodesManager); } [nodesManager operationsBatchDidComplete]; }]; } #endif // RCT_NEW_ARCH_ENABLED #pragma mark-- Events - (NSArray *)supportedEvents { return @[ @"onReanimatedCall", @"onReanimatedPropsChange" ]; } - (void)eventDispatcherWillDispatchEvent:(id)event { // Events can be dispatched from any queue [_nodesManager dispatchEvent:event]; } - (void)startObserving { hasListeners = YES; } - (void)stopObserving { hasListeners = NO; } - (void)sendEventWithName:(NSString *)eventName body:(id)body { if (hasListeners) { [super sendEventWithName:eventName body:body]; } } RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(installTurboModule : (nonnull NSString *)valueUnpackerCode) { if (_isBridgeless) { #if REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED) RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge; auto &rnRuntime = *(jsi::Runtime *)cxxBridge.runtime; auto executorFunction = ([executor = _runtimeExecutor](std::function &&callback) { // Convert to Objective-C block so it can be captured properly. __block auto callbackBlock = callback; [executor execute:^(jsi::Runtime &runtime) { callbackBlock(runtime); }]; }); auto nativeReanimatedModule = reanimated::createReanimatedModuleBridgeless( _moduleRegistry, rnRuntime, std::string([valueUnpackerCode UTF8String]), executorFunction); [self attachReactEventListener]; [self commonInit:nativeReanimatedModule withRnRuntime:rnRuntime]; #else // REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED) [NSException raise:@"Missing bridge" format:@"[Reanimated] Failed to obtain the bridge."]; #endif // REACT_NATIVE_MINOR_VERSION >= 74 && defined(RCT_NEW_ARCH_ENABLED) } else { facebook::jsi::Runtime *jsiRuntime = [self.bridge respondsToSelector:@selector(runtime)] ? reinterpret_cast(self.bridge.runtime) : nullptr; if (jsiRuntime) { auto nativeReanimatedModule = reanimated::createReanimatedModule( self.bridge, self.bridge.jsCallInvoker, std::string([valueUnpackerCode UTF8String])); jsi::Runtime &rnRuntime = *jsiRuntime; [self commonInit:nativeReanimatedModule withRnRuntime:rnRuntime]; } } return @YES; } #ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { return std::make_shared(params); } #endif // RCT_NEW_ARCH_ENABLED - (void)commonInit:(std::shared_ptr)nativeReanimatedModule withRnRuntime:(jsi::Runtime &)rnRuntime { #if __has_include() auto isReducedMotion = UIAccessibilityIsReduceMotionEnabled(); #else auto isReducedMotion = NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion; #endif WorkletRuntimeCollector::install(rnRuntime); RNRuntimeDecorator::decorate(rnRuntime, nativeReanimatedModule, isReducedMotion); #ifdef RCT_NEW_ARCH_ENABLED weakNativeReanimatedModule_ = nativeReanimatedModule; if (self->_surfacePresenter != nil) { // reload, uiManager is null right now, we need to wait for `installReanimatedAfterReload` [self injectDependencies:rnRuntime]; } #endif // RCT_NEW_ARCH_ENABLED } @end