diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index f5cc5ac0552fe9..0f29f624968f0d 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -2384,15 +2384,6 @@ public final class com/facebook/react/fabric/FabricUIManagerProviderImpl : com/f public fun createUIManager (Lcom/facebook/react/bridge/ReactApplicationContext;)Lcom/facebook/react/bridge/UIManager; } -public final class com/facebook/react/fabric/StateWrapperImpl : com/facebook/jni/HybridClassBase, com/facebook/react/uimanager/StateWrapper { - public fun destroyState ()V - public fun getStateData ()Lcom/facebook/react/bridge/ReadableNativeMap; - public fun getStateDataMapBuffer ()Lcom/facebook/react/common/mapbuffer/ReadableMapBuffer; - public fun toString ()Ljava/lang/String; - public fun updateState (Lcom/facebook/react/bridge/WritableMap;)V - public final fun updateStateImpl (Lcom/facebook/react/bridge/NativeMap;)V -} - public final class com/facebook/react/fabric/events/EventBeatManager : com/facebook/jni/HybridClassBase, com/facebook/react/uimanager/events/BatchEventDispatchedListener { public fun ()V public fun onBatchEventDispatched ()V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/StateWrapperImpl.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/StateWrapperImpl.kt index 4c51ff3a762d5d..dbff42f1c4d5fa 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/StateWrapperImpl.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/StateWrapperImpl.kt @@ -15,7 +15,7 @@ import com.facebook.react.bridge.NativeMap import com.facebook.react.bridge.ReadableNativeMap import com.facebook.react.bridge.WritableMap import com.facebook.react.common.mapbuffer.ReadableMapBuffer -import com.facebook.react.uimanager.StateWrapper +import com.facebook.react.uimanager.ReferenceStateWrapper /** * This class holds reference to the C++ EventEmitter object. Instances of this class are created on @@ -23,7 +23,7 @@ import com.facebook.react.uimanager.StateWrapper */ @SuppressLint("MissingNativeLoadLibrary") @DoNotStripAny -public class StateWrapperImpl private constructor() : HybridClassBase(), StateWrapper { +internal class StateWrapperImpl private constructor() : HybridClassBase(), ReferenceStateWrapper { private external fun initHybrid() @@ -31,6 +31,8 @@ public class StateWrapperImpl private constructor() : HybridClassBase(), StateWr private external fun getStateMapBufferDataImpl(): ReadableMapBuffer? + private external fun getStateDataReferenceImpl(): Any? + public external fun updateStateImpl(map: NativeMap) public override val stateDataMapBuffer: ReadableMapBuffer? @@ -51,6 +53,15 @@ public class StateWrapperImpl private constructor() : HybridClassBase(), StateWr return getStateDataImpl() } + public override val stateDataReference: Any? + get() { + if (!isValid) { + FLog.e(TAG, "Race between StateWrapperImpl destruction and getState") + return null + } + return getStateDataReferenceImpl() + } + init { initHybrid() } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReferenceStateWrapper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReferenceStateWrapper.kt new file mode 100644 index 00000000000000..71289e078925e9 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReferenceStateWrapper.kt @@ -0,0 +1,13 @@ +/* + * 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.uimanager + +internal interface ReferenceStateWrapper : StateWrapper { + /** Returns state data backed by JNI reference. The underlying object should not be modified. */ + public val stateDataReference: Any? +} diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.cpp index 01db7fb563d686..2459ad556d945a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.cpp @@ -43,6 +43,13 @@ StateWrapperImpl::getStateMapBufferDataImpl() { } } +jni::local_ref StateWrapperImpl::getStateDataReferenceImpl() { + if (state_) { + return state_->getJNIReference(); + } + return nullptr; +} + void StateWrapperImpl::updateStateImpl(NativeMap* map) { if (state_) { // Get folly::dynamic from map @@ -68,6 +75,9 @@ void StateWrapperImpl::registerNatives() { makeNativeMethod( "getStateMapBufferDataImpl", StateWrapperImpl::getStateMapBufferDataImpl), + makeNativeMethod( + "getStateDataReferenceImpl", + StateWrapperImpl::getStateDataReferenceImpl), }); } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.h index 340b7761458a10..b15f65b0314826 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/StateWrapperImpl.h @@ -27,6 +27,7 @@ class StateWrapperImpl : public jni::HybridClass { jni::local_ref getStateMapBufferDataImpl(); jni::local_ref getStateDataImpl(); + jni::local_ref getStateDataReferenceImpl(); void updateStateImpl(NativeMap* map); void setState(std::shared_ptr state); std::shared_ptr getState() const; diff --git a/packages/react-native/ReactCommon/react/renderer/core/ConcreteState.h b/packages/react-native/ReactCommon/react/renderer/core/ConcreteState.h index 1fab5de494041d..fa0d7b46e05792 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ConcreteState.h +++ b/packages/react-native/ReactCommon/react/renderer/core/ConcreteState.h @@ -14,6 +14,7 @@ #include #ifdef ANDROID +#include #include #include #endif @@ -25,6 +26,11 @@ template concept StateDataWithMapBuffer = requires(StateDataT stateData) { { stateData.getMapBuffer() } -> std::same_as; }; + +template +concept StateDataWithJNIReference = requires(StateDataT stateData) { + { stateData.getJNIReference() } -> std::same_as>; +}; #endif /* @@ -119,6 +125,14 @@ class ConcreteState : public State { return MapBufferBuilder::EMPTY(); } } + + jni::local_ref getJNIReference() const override { + if constexpr (StateDataWithJNIReference) { + return getData().getJNIReference(); + } else { + return nullptr; + } + } #endif }; diff --git a/packages/react-native/ReactCommon/react/renderer/core/State.h b/packages/react-native/ReactCommon/react/renderer/core/State.h index 82c19c20f77960..e65a39b2094e8b 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/State.h +++ b/packages/react-native/ReactCommon/react/renderer/core/State.h @@ -8,6 +8,7 @@ #pragma once #ifdef ANDROID +#include #include #include #endif @@ -66,6 +67,7 @@ class State { #ifdef ANDROID virtual folly::dynamic getDynamic() const = 0; virtual MapBuffer getMapBuffer() const = 0; + virtual jni::local_ref getJNIReference() const = 0; virtual void updateState(folly::dynamic&& data) const = 0; #endif