-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for Events on the Fabric Interop Layer (#37059)
Summary: Pull Request resolved: #37059 This diff introduces InteropEventEmitter, a re-implementation of RCTEventEmitter that works with Fabric and allows to support events on the Fabric Interop for Android. Thanks to this, users can keep on calling `getJSModule(RCTEventEmitter.class).receiveEvent(...)` in their legacy ViewManagers and they will be using the EventDispatcher under the hood to dispatch events. The logic is enabled only if the `unstable_useFabricInterop` flag is turned on. I've turned this on for the template setup and for RN Tester. On top of this, this diff takes care also of event name "normalization". On Fabric, all the events needs to be registered with a "top" prefix. With this diff, we'll be adding the "top" prefix at registration time, if the user hasn't added them. This allows to use legacy ViewManagers on Fabric without having to ask users to change their event name. Changelog: [Android] [Added] - Add support for Events on the Fabric Interop Layer Differential Revision: D45144246 fbshipit-source-id: 4d175d0318ab707ad7cbbab608b8603067ebbb94
- Loading branch information
1 parent
aab11c2
commit 2a9cda6
Showing
15 changed files
with
566 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
...e/ReactAndroid/src/main/java/com/facebook/react/bridge/interop/InteropModuleRegistry.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react.bridge.interop; | ||
|
||
import androidx.annotation.Nullable; | ||
import com.facebook.react.bridge.JavaScriptModule; | ||
import com.facebook.react.config.ReactFeatureFlags; | ||
import java.util.HashMap; | ||
|
||
/** | ||
* A utility class that takes care of returning {@link JavaScriptModule} which are used for the | ||
* Fabric Interop Layer. This allows us to override the returned classes once the user is invoking | ||
* `ReactContext.getJsModule()`. | ||
* | ||
* <p>Currently we only support a `RCTEventEmitter` re-implementation, being `InteropEventEmitter` | ||
* but this class can support other re-implementation in the future. | ||
*/ | ||
public class InteropModuleRegistry { | ||
|
||
@SuppressWarnings("rawtypes") | ||
private final HashMap<Class, Object> supportedModules; | ||
|
||
public InteropModuleRegistry() { | ||
this.supportedModules = new HashMap<>(); | ||
} | ||
|
||
public <T extends JavaScriptModule> boolean shouldReturnInteropModule(Class<T> requestedModule) { | ||
return checkReactFeatureFlagsConditions() && supportedModules.containsKey(requestedModule); | ||
} | ||
|
||
@Nullable | ||
public <T extends JavaScriptModule> T getInteropModule(Class<T> requestedModule) { | ||
if (checkReactFeatureFlagsConditions()) { | ||
//noinspection unchecked | ||
return (T) supportedModules.get(requestedModule); | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
public <T extends JavaScriptModule> void registerInteropModule( | ||
Class<T> interopModuleInterface, Object interopModule) { | ||
if (checkReactFeatureFlagsConditions()) { | ||
supportedModules.put(interopModuleInterface, interopModule); | ||
} | ||
} | ||
|
||
private boolean checkReactFeatureFlagsConditions() { | ||
return ReactFeatureFlags.enableFabricRenderer && ReactFeatureFlags.unstable_useFabricInterop; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
...act-native/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react.fabric.interop; | ||
|
||
import androidx.annotation.Nullable; | ||
import com.facebook.react.bridge.WritableMap; | ||
import com.facebook.react.common.annotations.VisibleForTesting; | ||
import com.facebook.react.uimanager.events.Event; | ||
|
||
/** | ||
* An {@link Event} class used by the {@link InteropEventEmitter}. This class is just holding the | ||
* event name and the data which is received by the `receiveEvent` method and will be passed over | ||
* the the {@link com.facebook.react.uimanager.events.EventDispatcher} | ||
*/ | ||
class InteropEvent extends Event<InteropEvent> { | ||
|
||
private final String mName; | ||
private final WritableMap mEventData; | ||
|
||
InteropEvent(String name, @Nullable WritableMap eventData, int surfaceId, int viewTag) { | ||
super(surfaceId, viewTag); | ||
mName = name; | ||
mEventData = eventData; | ||
} | ||
|
||
@Override | ||
public String getEventName() { | ||
return mName; | ||
} | ||
|
||
@Override | ||
@VisibleForTesting | ||
public WritableMap getEventData() { | ||
return mEventData; | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
...ive/ReactAndroid/src/main/java/com/facebook/react/fabric/interop/InteropEventEmitter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react.fabric.interop; | ||
|
||
import androidx.annotation.Nullable; | ||
import com.facebook.react.bridge.ReactContext; | ||
import com.facebook.react.bridge.WritableArray; | ||
import com.facebook.react.bridge.WritableMap; | ||
import com.facebook.react.common.annotations.VisibleForTesting; | ||
import com.facebook.react.uimanager.UIManagerHelper; | ||
import com.facebook.react.uimanager.events.EventDispatcher; | ||
import com.facebook.react.uimanager.events.RCTEventEmitter; | ||
|
||
/** | ||
* A reimplementation of {@link RCTEventEmitter} which is using a {@link EventDispatcher} under the | ||
* hood. | ||
* | ||
* <p>On Fabric, you're supposed to use {@link EventDispatcher} to dispatch events. However, we | ||
* provide an interop layer for non-Fabric migrated components. | ||
* | ||
* <p>This instance will be returned if the user is invoking `context.getJsModule(RCTEventEmitter) | ||
* and is providing support for the `receiveEvent` method, so that non-Fabric ViewManagers can | ||
* continue to deliver events also when Fabric is turned on. | ||
*/ | ||
public class InteropEventEmitter implements RCTEventEmitter { | ||
|
||
private final ReactContext mReactContext; | ||
|
||
private @Nullable EventDispatcher mEventDispatcherOverride; | ||
|
||
public InteropEventEmitter(ReactContext reactContext) { | ||
mReactContext = reactContext; | ||
} | ||
|
||
@Override | ||
public void receiveEvent(int targetReactTag, String eventName, @Nullable WritableMap eventData) { | ||
EventDispatcher dispatcher; | ||
if (mEventDispatcherOverride != null) { | ||
dispatcher = mEventDispatcherOverride; | ||
} else { | ||
dispatcher = UIManagerHelper.getEventDispatcherForReactTag(mReactContext, targetReactTag); | ||
} | ||
int surfaceId = UIManagerHelper.getSurfaceId(mReactContext); | ||
if (dispatcher != null) { | ||
dispatcher.dispatchEvent(new InteropEvent(eventName, eventData, surfaceId, targetReactTag)); | ||
} | ||
} | ||
|
||
@Override | ||
public void receiveTouches( | ||
String eventName, WritableArray touches, WritableArray changedIndices) { | ||
throw new UnsupportedOperationException( | ||
"EventEmitter#receiveTouches is not supported by the Fabric Interop Layer"); | ||
} | ||
|
||
@VisibleForTesting | ||
void overrideEventDispatcher(EventDispatcher eventDispatcherOverride) { | ||
mEventDispatcherOverride = eventDispatcherOverride; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
...ive/ReactAndroid/src/test/java/com/facebook/react/bridge/interop/FakeRCTEventEmitter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react.bridge.interop; | ||
|
||
import androidx.annotation.Nullable; | ||
import com.facebook.react.bridge.WritableArray; | ||
import com.facebook.react.bridge.WritableMap; | ||
import com.facebook.react.uimanager.events.RCTEventEmitter; | ||
|
||
public class FakeRCTEventEmitter implements RCTEventEmitter { | ||
|
||
@Override | ||
public void receiveEvent(int targetReactTag, String eventName, @Nullable WritableMap event) {} | ||
|
||
@Override | ||
public void receiveTouches( | ||
String eventName, WritableArray touches, WritableArray changedIndices) {} | ||
} |
Oops, something went wrong.