Skip to content

Commit 9bea72b

Browse files
authored
Migrate Gesture Handler to TurboModule (#2354)
## Description Make Gesture Handler a TurboModule instead of a Native Module 🚀 ## Test plan Tested on the Example and FabricExample app
1 parent f22ada3 commit 9bea72b

File tree

14 files changed

+271
-121
lines changed

14 files changed

+271
-121
lines changed

FabricExample/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,7 @@ SPEC CHECKSUMS:
14391439
React-runtimescheduler: a80659eb4504ad696295b3e51b90805a97c34129
14401440
React-utils: 2e199c0f64d49f8ca4175d878e365d2701ad41f7
14411441
ReactCommon: 82a6500a0906815f2e6079d6a3f226bd2f58e61d
1442-
RNGestureHandler: 38016feaff9bd5d8282c78ddce37a89b3a1d595b
1442+
RNGestureHandler: b028dd5cade762010a72ee9be3afac17a0f72787
14431443
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
14441444
Yoga: 580401abccf998bc081186108e981602f90e67b2
14451445

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.swmansion.gesturehandler;
2+
3+
import com.facebook.proguard.annotations.DoNotStrip;
4+
import com.facebook.react.bridge.ReactApplicationContext;
5+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
6+
import com.facebook.react.bridge.ReactMethod;
7+
import com.facebook.react.bridge.ReadableMap;
8+
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
9+
import javax.annotation.Nonnull;
10+
11+
public abstract class NativeRNGestureHandlerModuleSpec extends ReactContextBaseJavaModule implements TurboModule {
12+
public static final String NAME = "RNGestureHandlerModule";
13+
14+
public NativeRNGestureHandlerModuleSpec(ReactApplicationContext reactContext) {
15+
super(reactContext);
16+
}
17+
18+
@Override
19+
public @Nonnull String getName() {
20+
return NAME;
21+
}
22+
23+
@DoNotStrip
24+
public abstract void handleSetJSResponder(double tag, boolean blockNativeResponder);
25+
26+
@DoNotStrip
27+
public abstract void handleClearJSResponder();
28+
29+
@DoNotStrip
30+
public abstract void createGestureHandler(String handlerName, double handlerTag, ReadableMap config);
31+
32+
@DoNotStrip
33+
public abstract void attachGestureHandler(double handlerTag, double newView, double actionType);
34+
35+
@DoNotStrip
36+
public abstract void updateGestureHandler(double handlerTag, ReadableMap newConfig);
37+
38+
@DoNotStrip
39+
public abstract void dropGestureHandler(double handlerTag);
40+
41+
@DoNotStrip
42+
public abstract boolean install();
43+
44+
@DoNotStrip
45+
public abstract void flushOperations();
46+
}
Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,81 @@
11
package com.swmansion.gesturehandler
22

3-
import com.facebook.react.ReactPackage
3+
import com.facebook.react.TurboReactPackage
4+
import com.facebook.react.ViewManagerOnDemandReactPackage
5+
import com.facebook.react.bridge.ModuleSpec
46
import com.facebook.react.bridge.NativeModule
57
import com.facebook.react.bridge.ReactApplicationContext
8+
import com.facebook.react.module.annotations.ReactModule
9+
import com.facebook.react.module.model.ReactModuleInfo
10+
import com.facebook.react.module.model.ReactModuleInfoProvider
11+
import com.facebook.react.turbomodule.core.interfaces.TurboModule
612
import com.facebook.react.uimanager.ViewManager
713
import com.swmansion.gesturehandler.react.RNGestureHandlerButtonViewManager
814
import com.swmansion.gesturehandler.react.RNGestureHandlerModule
915
import com.swmansion.gesturehandler.react.RNGestureHandlerRootViewManager
1016

11-
class RNGestureHandlerPackage : ReactPackage {
12-
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
13-
return listOf<NativeModule>(RNGestureHandlerModule(reactContext))
17+
class RNGestureHandlerPackage : TurboReactPackage(), ViewManagerOnDemandReactPackage {
18+
private val viewManagers: Map<String, ModuleSpec> by lazy {
19+
mapOf(
20+
RNGestureHandlerRootViewManager.REACT_CLASS to ModuleSpec.viewManagerSpec {
21+
RNGestureHandlerRootViewManager()
22+
},
23+
RNGestureHandlerButtonViewManager.REACT_CLASS to ModuleSpec.viewManagerSpec {
24+
RNGestureHandlerButtonViewManager()
25+
}
26+
)
1427
}
1528

1629
override fun createViewManagers(reactContext: ReactApplicationContext) =
1730
listOf<ViewManager<*, *>>(
1831
RNGestureHandlerRootViewManager(),
1932
RNGestureHandlerButtonViewManager()
2033
)
34+
35+
override fun getViewManagerNames(reactContext: ReactApplicationContext?) =
36+
viewManagers.keys.toList()
37+
38+
override fun getViewManagers(reactContext: ReactApplicationContext?): MutableList<ModuleSpec> =
39+
viewManagers.values.toMutableList()
40+
41+
override fun createViewManager(
42+
reactContext: ReactApplicationContext?,
43+
viewManagerName: String?
44+
) = viewManagers[viewManagerName]?.provider?.get() as? ViewManager<*, *>
45+
46+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
47+
return if (name == RNGestureHandlerModule.MODULE_NAME) {
48+
RNGestureHandlerModule(reactContext)
49+
} else {
50+
null
51+
}
52+
}
53+
54+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
55+
try {
56+
val reactModuleInfoProviderClass =
57+
Class.forName("com.swmansion.gesturehandler.RNGestureHandlerPackage$\$ReactModuleInfoProvider")
58+
return reactModuleInfoProviderClass.newInstance() as ReactModuleInfoProvider
59+
} catch (e: ClassNotFoundException) {
60+
return ReactModuleInfoProvider {
61+
val reactModule: ReactModule = RNGestureHandlerModule::class.java.getAnnotation(ReactModule::class.java)!!
62+
63+
mutableMapOf(
64+
RNGestureHandlerModule.MODULE_NAME to ReactModuleInfo(
65+
reactModule.name,
66+
RNGestureHandlerModule::class.java.name,
67+
reactModule.canOverrideExistingModule,
68+
reactModule.needsEagerInit,
69+
reactModule.hasConstants,
70+
reactModule.isCxxModule,
71+
TurboModule::class.java.isAssignableFrom(RNGestureHandlerModule::class.java)
72+
)
73+
)
74+
}
75+
} catch (e: InstantiationException) {
76+
throw RuntimeException("No ReactModuleInfoProvider for RNGestureHandlerPackage$\$ReactModuleInfoProvider", e)
77+
} catch (e: IllegalAccessException) {
78+
throw RuntimeException("No ReactModuleInfoProvider for RNGestureHandlerPackage$\$ReactModuleInfoProvider", e)
79+
}
80+
}
2181
}

android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import android.view.MotionEvent
66
import com.facebook.react.ReactRootView
77
import com.facebook.react.bridge.JSApplicationIllegalArgumentException
88
import com.facebook.react.bridge.ReactApplicationContext
9-
import com.facebook.react.bridge.ReactContextBaseJavaModule
109
import com.facebook.react.bridge.ReactMethod
1110
import com.facebook.react.bridge.ReadableMap
1211
import com.facebook.react.bridge.ReadableType
@@ -17,6 +16,7 @@ import com.facebook.react.uimanager.events.Event
1716
import com.facebook.soloader.SoLoader
1817
import com.swmansion.common.GestureHandlerStateManager
1918
import com.swmansion.gesturehandler.BuildConfig
19+
import com.swmansion.gesturehandler.NativeRNGestureHandlerModuleSpec
2020
import com.swmansion.gesturehandler.ReanimatedEventDispatcher
2121
import com.swmansion.gesturehandler.core.FlingGestureHandler
2222
import com.swmansion.gesturehandler.core.GestureHandler
@@ -49,7 +49,7 @@ import com.swmansion.gesturehandler.react.eventbuilders.TapGestureHandlerEventDa
4949
@Suppress("DEPRECATION")
5050
@ReactModule(name = RNGestureHandlerModule.MODULE_NAME)
5151
class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
52-
ReactContextBaseJavaModule(reactContext), GestureHandlerStateManager {
52+
NativeRNGestureHandlerModuleSpec(reactContext), GestureHandlerStateManager {
5353
private abstract class HandlerFactory<T : GestureHandler<T>> {
5454
abstract val type: Class<T>
5555
abstract val name: String
@@ -333,9 +333,8 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
333333
private val reanimatedEventDispatcher = ReanimatedEventDispatcher()
334334
override fun getName() = MODULE_NAME
335335

336-
@ReactMethod
337336
@Suppress("UNCHECKED_CAST")
338-
fun <T : GestureHandler<T>> createGestureHandler(
337+
private fun <T : GestureHandler<T>> createGestureHandlerHelper(
339338
handlerName: String,
340339
handlerTag: Int,
341340
config: ReadableMap,
@@ -363,7 +362,21 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
363362
}
364363

365364
@ReactMethod
366-
fun attachGestureHandler(handlerTag: Int, viewTag: Int, actionType: Int) {
365+
override fun createGestureHandler(
366+
handlerName: String,
367+
handlerTagDouble: Double,
368+
config: ReadableMap,
369+
) {
370+
val handlerTag = handlerTagDouble.toInt()
371+
372+
createGestureHandlerHelper(handlerName, handlerTag, config)
373+
}
374+
375+
@ReactMethod
376+
override fun attachGestureHandler(handlerTagDouble: Double, viewTagDouble: Double, actionTypeDouble: Double) {
377+
val handlerTag = handlerTagDouble.toInt()
378+
val viewTag = viewTagDouble.toInt()
379+
val actionType = actionTypeDouble.toInt()
367380
// We don't have to handle view flattening in any special way since handlers are stored as
368381
// a map: viewTag -> [handler]. If the view with attached handlers was to be flattened
369382
// then that viewTag simply wouldn't be visited when traversing the view hierarchy in the
@@ -373,9 +386,8 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
373386
}
374387
}
375388

376-
@ReactMethod
377389
@Suppress("UNCHECKED_CAST")
378-
fun <T : GestureHandler<T>> updateGestureHandler(handlerTag: Int, config: ReadableMap) {
390+
private fun <T : GestureHandler<T>> updateGestureHandlerHelper(handlerTag: Int, config: ReadableMap) {
379391
val handler = registry.getHandler(handlerTag) as T?
380392
if (handler != null) {
381393
val factory = findFactoryForHandler(handler)
@@ -388,19 +400,32 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
388400
}
389401

390402
@ReactMethod
391-
fun dropGestureHandler(handlerTag: Int) {
403+
override fun updateGestureHandler(handlerTagDouble: Double, config: ReadableMap) {
404+
val handlerTag = handlerTagDouble.toInt()
405+
406+
updateGestureHandlerHelper(handlerTag, config)
407+
}
408+
409+
@ReactMethod
410+
override fun dropGestureHandler(handlerTagDouble: Double) {
411+
val handlerTag = handlerTagDouble.toInt()
392412
interactionManager.dropRelationsForHandlerWithTag(handlerTag)
393413
registry.dropHandler(handlerTag)
394414
}
395415

396416
@ReactMethod
397-
fun handleSetJSResponder(viewTag: Int, blockNativeResponder: Boolean) {
417+
override fun handleSetJSResponder(viewTagDouble: Double, blockNativeResponder: Boolean) {
418+
val viewTag = viewTagDouble.toInt()
398419
val rootView = findRootHelperForViewAncestor(viewTag)
399420
rootView?.handleSetJSResponder(viewTag, blockNativeResponder)
400421
}
401422

402423
@ReactMethod
403-
fun handleClearJSResponder() {
424+
override fun handleClearJSResponder() {
425+
}
426+
427+
@ReactMethod
428+
override fun flushOperations() {
404429
}
405430

406431
override fun setGestureHandlerState(handlerTag: Int, newState: Int) {
@@ -416,16 +441,18 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
416441
}
417442

418443
@ReactMethod(isBlockingSynchronousMethod = true)
419-
fun install(): Boolean {
420-
return try {
421-
SoLoader.loadLibrary("gesturehandler")
422-
val jsContext = reactApplicationContext.javaScriptContextHolder!!
423-
decorateRuntime(jsContext.get())
424-
true
425-
} catch (exception: Exception) {
426-
Log.w("[RNGestureHandler]", "Could not install JSI bindings.")
427-
false
444+
override fun install(): Boolean {
445+
reactApplicationContext.runOnJSQueueThread {
446+
try {
447+
SoLoader.loadLibrary("gesturehandler")
448+
val jsContext = reactApplicationContext.javaScriptContextHolder!!
449+
decorateRuntime(jsContext.get())
450+
} catch (exception: Exception) {
451+
Log.w("[RNGestureHandler]", "Could not install JSI bindings.")
452+
}
428453
}
454+
455+
return true
429456
}
430457

431458
private external fun decorateRuntime(jsiPtr: Long)

apple/RNGestureHandlerManager.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
@interface RNGestureHandlerManager : NSObject
1111

1212
- (nonnull instancetype)initWithUIManager:(nonnull RCTUIManager *)uiManager
13-
eventDispatcher:(nonnull RCTEventDispatcher *)eventDispatcher;
13+
eventDispatcher:(nonnull id<RCTEventDispatcherProtocol>)eventDispatcher;
1414

1515
- (void)createGestureHandler:(nonnull NSString *)handlerName
1616
tag:(nonnull NSNumber *)handlerTag
@@ -26,7 +26,7 @@
2626

2727
- (void)dropAllGestureHandlers;
2828

29-
- (void)handleSetJSResponder:(nonnull NSNumber *)viewTag blockNativeResponder:(nonnull NSNumber *)blockNativeResponder;
29+
- (void)handleSetJSResponder:(nonnull NSNumber *)viewTag blockNativeResponder:(BOOL)blockNativeResponder;
3030

3131
- (void)handleClearJSResponder;
3232

apple/RNGestureHandlerManager.mm

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#import "RNGestureHandlerManager.h"
22

33
#import <React/RCTComponent.h>
4-
#import <React/RCTEventDispatcher.h>
4+
#import <React/RCTEventDispatcherProtocol.h>
55
#import <React/RCTLog.h>
66
#import <React/RCTModalHostViewController.h>
77
#import <React/RCTRootContentView.h>
@@ -52,11 +52,12 @@ @implementation RNGestureHandlerManager {
5252
RCTUIManager *_uiManager;
5353
NSHashTable<RNRootViewGestureRecognizer *> *_rootViewGestureRecognizers;
5454
NSMutableDictionary<NSNumber *, NSNumber *> *_attachRetryCounter;
55-
RCTEventDispatcher *_eventDispatcher;
55+
id<RCTEventDispatcherProtocol> _eventDispatcher;
5656
id _reanimatedModule;
5757
}
5858

59-
- (instancetype)initWithUIManager:(RCTUIManager *)uiManager eventDispatcher:(RCTEventDispatcher *)eventDispatcher
59+
- (instancetype)initWithUIManager:(RCTUIManager *)uiManager
60+
eventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher
6061
{
6162
if ((self = [super init])) {
6263
_uiManager = uiManager;
@@ -185,9 +186,9 @@ - (void)dropAllGestureHandlers
185186
[_registry dropAllHandlers];
186187
}
187188

188-
- (void)handleSetJSResponder:(NSNumber *)viewTag blockNativeResponder:(NSNumber *)blockNativeResponder
189+
- (void)handleSetJSResponder:(NSNumber *)viewTag blockNativeResponder:(BOOL)blockNativeResponder
189190
{
190-
if ([blockNativeResponder boolValue]) {
191+
if (blockNativeResponder) {
191192
for (RNRootViewGestureRecognizer *recognizer in _rootViewGestureRecognizers) {
192193
[recognizer blockOtherRecognizers];
193194
}

apple/RNGestureHandlerModule.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1-
#import <React/RCTBridgeModule.h>
21
#import <React/RCTEventEmitter.h>
32
#import <React/RCTUIManager.h>
43

5-
@interface RNGestureHandlerModule : RCTEventEmitter <RCTBridgeModule>
4+
#ifdef RN_FABRIC_ENABLED
5+
#import <rngesturehandler_codegen/rngesturehandler_codegen.h>
6+
#else
7+
#import <React/RCTBridgeModule.h>
8+
#endif
9+
10+
@interface RNGestureHandlerModule : RCTEventEmitter
11+
#ifdef RN_FABRIC_ENABLED
12+
<NativeRNGestureHandlerModuleSpec>
13+
#else
14+
<RCTBridgeModule>
15+
#endif
616

717
@end

0 commit comments

Comments
 (0)