Skip to content

Commit f99dc48

Browse files
RSNarafacebook-github-bot
authored andcommitted
Pull react instance method impls out of ReactContext
Summary: ## Context Prior, ReactContext used to implement bridge logic. For bridgeless mode, we created BridgelessReactContext < ReactContext ## Problem This could lead to failures: we could call bridge methods in bridgeless mode. ## Changes Primary change: - Make all the react instance methods inside ReactContext abstract. Secondary changes: Implement react instance methods in concrete subclasses: - **New:** BridgeReactContext: By delegating to CatalystInstance - **New:** ThemedReactContext: By delegating to inner ReactContext - **Unchanged:** BridgelessReactContext: By delegating to ReactHost ## Auxiliary changes This fixes ThemedReactContext in bridgeless mode. **Problem:** Prior, ThemedReactContext's react instance methods did not work in bridgeless mode: ThemedReactContext wasn't initialized in bridgeless mode, so all those methods had undefined behaviour. **Solution:** ThemedReactContext now implements all react instance methods, by just forwarding to the initialized ReactContext it decorates (which has an instance). Changelog: [Android][Removed] Delete ReactContext.initializeWithInstance(). ReactContext now no longer contains legacy react instance methods. Please use BridgeReactInstance instead. Reviewed By: javache Differential Revision: D53145010 fbshipit-source-id: 2405bc24afb00864117d3c504fc9c4cbffd7203a
1 parent 5ceb928 commit f99dc48

5 files changed

Lines changed: 343 additions & 181 deletions

File tree

packages/react-native/ReactAndroid/api/ReactAndroid.api

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,27 @@ public abstract class com/facebook/react/bridge/BaseJavaModule : com/facebook/re
542542
}
543543

544544
public final class com/facebook/react/bridge/BridgeReactContext : com/facebook/react/bridge/ReactApplicationContext {
545+
public static final field Companion Lcom/facebook/react/bridge/BridgeReactContext$Companion;
545546
public fun <init> (Landroid/content/Context;)V
547+
public fun destroy ()V
548+
public fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
549+
public fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
550+
public fun getJSModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
551+
public fun getJavaScriptContextHolder ()Lcom/facebook/react/bridge/JavaScriptContextHolder;
552+
public fun getNativeModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/NativeModule;
553+
public fun getNativeModules ()Ljava/util/Collection;
554+
public fun getSourceURL ()Ljava/lang/String;
555+
public fun handleException (Ljava/lang/Exception;)V
556+
public fun hasActiveCatalystInstance ()Z
557+
public fun hasActiveReactInstance ()Z
558+
public fun hasCatalystInstance ()Z
559+
public fun hasNativeModule (Ljava/lang/Class;)Z
560+
public final fun initializeWithInstance (Lcom/facebook/react/bridge/CatalystInstance;)V
561+
public fun isBridgeless ()Z
562+
public fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
563+
}
564+
565+
public final class com/facebook/react/bridge/BridgeReactContext$Companion {
546566
}
547567

548568
public abstract interface class com/facebook/react/bridge/Callback {
@@ -1088,36 +1108,35 @@ public abstract class com/facebook/react/bridge/ReactContext : android/content/C
10881108
public fun assertOnNativeModulesQueueThread ()V
10891109
public fun assertOnNativeModulesQueueThread (Ljava/lang/String;)V
10901110
public fun assertOnUiQueueThread ()V
1091-
public fun destroy ()V
1111+
public abstract fun destroy ()V
10921112
public fun emitDeviceEvent (Ljava/lang/String;)V
10931113
public fun emitDeviceEvent (Ljava/lang/String;Ljava/lang/Object;)V
1094-
public fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
1114+
public abstract fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
10951115
public fun getCurrentActivity ()Landroid/app/Activity;
10961116
public fun getExceptionHandler ()Lcom/facebook/react/bridge/JSExceptionHandler;
1097-
public fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
1117+
public abstract fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
10981118
public fun getJSExceptionHandler ()Lcom/facebook/react/bridge/JSExceptionHandler;
10991119
public fun getJSMessageQueueThread ()Lcom/facebook/react/bridge/queue/MessageQueueThread;
1100-
public fun getJSModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
1101-
public fun getJavaScriptContextHolder ()Lcom/facebook/react/bridge/JavaScriptContextHolder;
1120+
public abstract fun getJSModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
1121+
public abstract fun getJavaScriptContextHolder ()Lcom/facebook/react/bridge/JavaScriptContextHolder;
11021122
public fun getLifecycleState ()Lcom/facebook/react/common/LifecycleState;
1103-
public fun getNativeModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/NativeModule;
1104-
public fun getNativeModules ()Ljava/util/Collection;
1123+
public abstract fun getNativeModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/NativeModule;
1124+
public abstract fun getNativeModules ()Ljava/util/Collection;
11051125
public fun getNativeModulesMessageQueueThread ()Lcom/facebook/react/bridge/queue/MessageQueueThread;
1106-
public fun getSourceURL ()Ljava/lang/String;
1126+
public abstract fun getSourceURL ()Ljava/lang/String;
11071127
public fun getSystemService (Ljava/lang/String;)Ljava/lang/Object;
11081128
public fun getUiMessageQueueThread ()Lcom/facebook/react/bridge/queue/MessageQueueThread;
1109-
public fun handleException (Ljava/lang/Exception;)V
1110-
public fun hasActiveCatalystInstance ()Z
1111-
public fun hasActiveReactInstance ()Z
1112-
public fun hasCatalystInstance ()Z
1129+
public abstract fun handleException (Ljava/lang/Exception;)V
1130+
public abstract fun hasActiveCatalystInstance ()Z
1131+
public abstract fun hasActiveReactInstance ()Z
1132+
public abstract fun hasCatalystInstance ()Z
11131133
public fun hasCurrentActivity ()Z
1114-
public fun hasNativeModule (Ljava/lang/Class;)Z
1134+
public abstract fun hasNativeModule (Ljava/lang/Class;)Z
1135+
protected fun initializeFromOther (Lcom/facebook/react/bridge/ReactContext;)V
11151136
protected fun initializeInteropModules ()V
1116-
protected fun initializeInteropModules (Lcom/facebook/react/bridge/ReactContext;)V
11171137
public fun initializeMessageQueueThreads (Lcom/facebook/react/bridge/queue/ReactQueueConfiguration;)V
1118-
public fun initializeWithInstance (Lcom/facebook/react/bridge/CatalystInstance;)V
11191138
public fun internal_registerInteropModule (Ljava/lang/Class;Ljava/lang/Object;)V
1120-
public fun isBridgeless ()Z
1139+
public abstract fun isBridgeless ()Z
11211140
public fun isOnJSQueueThread ()Z
11221141
public fun isOnNativeModulesQueueThread ()Z
11231142
public fun isOnUiQueueThread ()Z
@@ -1127,7 +1146,7 @@ public abstract class com/facebook/react/bridge/ReactContext : android/content/C
11271146
public fun onHostResume (Landroid/app/Activity;)V
11281147
public fun onNewIntent (Landroid/app/Activity;Landroid/content/Intent;)V
11291148
public fun onWindowFocusChange (Z)V
1130-
public fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
1149+
public abstract fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
11311150
public fun removeActivityEventListener (Lcom/facebook/react/bridge/ActivityEventListener;)V
11321151
public fun removeLifecycleEventListener (Lcom/facebook/react/bridge/LifecycleEventListener;)V
11331152
public fun removeWindowFocusChangeListener (Lcom/facebook/react/bridge/WindowFocusChangeListener;)V
@@ -4822,16 +4841,25 @@ public class com/facebook/react/uimanager/ThemedReactContext : com/facebook/reac
48224841
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Landroid/content/Context;)V
48234842
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Landroid/content/Context;Ljava/lang/String;)V
48244843
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Landroid/content/Context;Ljava/lang/String;I)V
4825-
public fun addLifecycleEventListener (Lcom/facebook/react/bridge/LifecycleEventListener;)V
4826-
public fun getCurrentActivity ()Landroid/app/Activity;
4844+
public fun destroy ()V
4845+
public fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
48274846
public fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
4847+
public fun getJSModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
4848+
public fun getJavaScriptContextHolder ()Lcom/facebook/react/bridge/JavaScriptContextHolder;
48284849
public fun getModuleName ()Ljava/lang/String;
4850+
public fun getNativeModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/NativeModule;
4851+
public fun getNativeModules ()Ljava/util/Collection;
48294852
public fun getReactApplicationContext ()Lcom/facebook/react/bridge/ReactApplicationContext;
4853+
public fun getSourceURL ()Ljava/lang/String;
48304854
public fun getSurfaceID ()Ljava/lang/String;
48314855
public fun getSurfaceId ()I
4832-
public fun hasCurrentActivity ()Z
4856+
public fun handleException (Ljava/lang/Exception;)V
4857+
public fun hasActiveCatalystInstance ()Z
4858+
public fun hasActiveReactInstance ()Z
4859+
public fun hasCatalystInstance ()Z
4860+
public fun hasNativeModule (Ljava/lang/Class;)Z
48334861
public fun isBridgeless ()Z
4834-
public fun removeLifecycleEventListener (Lcom/facebook/react/bridge/LifecycleEventListener;)V
4862+
public fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
48354863
}
48364864

48374865
public class com/facebook/react/uimanager/TouchTargetHelper {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/BridgeReactContext.kt

Lines changed: 181 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,192 @@
88
package com.facebook.react.bridge
99

1010
import android.content.Context
11+
import com.facebook.common.logging.FLog
12+
import com.facebook.react.bridge.queue.ReactQueueConfiguration
13+
import com.facebook.react.common.ReactConstants
1114
import com.facebook.react.common.annotations.DeprecatedInNewArchitecture
15+
import com.facebook.react.common.annotations.FrameworkAPI
16+
import com.facebook.react.common.annotations.UnstableReactNativeAPI
1217

1318
/**
1419
* This is the bridge-specific concrete subclass of ReactContext. ReactContext has many methods that
15-
* delegate to the react instance. This subclass will implement those methods, by delegating to the
20+
* delegate to the react instance. This subclass implements those methods, by delegating to the
1621
* CatalystInstance. If you need to create a ReactContext within an "bridge context", please create
1722
* BridgeReactContext.
1823
*/
1924
@DeprecatedInNewArchitecture
20-
public class BridgeReactContext(base: Context) : ReactApplicationContext(base) {}
25+
public class BridgeReactContext(base: Context) : ReactApplicationContext(base) {
26+
@Volatile private var destroyed = false
27+
private var catalystInstance: CatalystInstance? = null
28+
29+
fun initializeWithInstance(otherCatalystInstance: CatalystInstance?) {
30+
if (otherCatalystInstance == null) {
31+
throw IllegalArgumentException("CatalystInstance cannot be null.")
32+
}
33+
if (catalystInstance != null) {
34+
throw IllegalStateException("ReactContext has been already initialized")
35+
}
36+
if (destroyed) {
37+
ReactSoftExceptionLogger.logSoftException(
38+
TAG, IllegalStateException("Cannot initialize ReactContext after it has been destroyed."))
39+
}
40+
41+
catalystInstance = otherCatalystInstance
42+
43+
val queueConfig: ReactQueueConfiguration = otherCatalystInstance.reactQueueConfiguration
44+
initializeMessageQueueThreads(queueConfig)
45+
initializeInteropModules()
46+
}
47+
48+
override fun <T : JavaScriptModule?> getJSModule(jsInterface: Class<T>?): T? {
49+
val instance =
50+
catalystInstance
51+
?: throw IllegalStateException(
52+
if (destroyed) LATE_JS_ACCESS_EXCEPTION_MESSAGE
53+
else EARLY_JS_ACCESS_EXCEPTION_MESSAGE)
54+
55+
val interopModuleRegistry = mInteropModuleRegistry
56+
if (interopModuleRegistry != null &&
57+
interopModuleRegistry.shouldReturnInteropModule(jsInterface)) {
58+
return interopModuleRegistry.getInteropModule(jsInterface)
59+
}
60+
61+
return instance.getJSModule(jsInterface)
62+
}
63+
64+
override fun <T : NativeModule?> hasNativeModule(nativeModuleInterface: Class<T>?): Boolean {
65+
val instance =
66+
catalystInstance
67+
?: throw IllegalStateException(
68+
if (destroyed) LATE_NATIVE_MODULE_EXCEPTION_MESSAGE
69+
else EARLY_NATIVE_MODULE_EXCEPTION_MESSAGE)
70+
return instance.hasNativeModule(nativeModuleInterface)
71+
}
72+
73+
override fun getNativeModules(): MutableCollection<NativeModule> {
74+
val instance =
75+
catalystInstance
76+
?: throw IllegalStateException(
77+
if (destroyed) LATE_NATIVE_MODULE_EXCEPTION_MESSAGE
78+
else EARLY_NATIVE_MODULE_EXCEPTION_MESSAGE)
79+
return instance.nativeModules
80+
}
81+
82+
override fun <T : NativeModule?> getNativeModule(nativeModuleInterface: Class<T>?): T? {
83+
val instance =
84+
catalystInstance
85+
?: throw IllegalStateException(
86+
if (destroyed) LATE_NATIVE_MODULE_EXCEPTION_MESSAGE
87+
else EARLY_NATIVE_MODULE_EXCEPTION_MESSAGE)
88+
return instance.getNativeModule(nativeModuleInterface)
89+
}
90+
91+
@FrameworkAPI
92+
@UnstableReactNativeAPI
93+
override fun getRuntimeExecutor(): RuntimeExecutor? {
94+
val instance =
95+
catalystInstance
96+
?: throw IllegalStateException(
97+
if (destroyed) LATE_RUNTIME_EXECUTOR_ACCESS_EXCEPTION_MESSAGE
98+
else EARLY_RUNTIME_EXECUTOR_ACCESS_EXCEPTION_MESSAGE)
99+
100+
return instance.getRuntimeExecutor()
101+
}
102+
103+
override fun getCatalystInstance(): CatalystInstance {
104+
return catalystInstance!!
105+
}
106+
107+
@Deprecated(
108+
"This API is unsupported in the New Architecture.", ReplaceWith("hasActiveReactInstance()"))
109+
override fun hasActiveCatalystInstance(): Boolean {
110+
return hasActiveReactInstance()
111+
}
112+
113+
override fun hasActiveReactInstance(): Boolean {
114+
val instance = catalystInstance
115+
return instance != null && !instance.isDestroyed
116+
}
117+
118+
override fun hasCatalystInstance(): Boolean {
119+
return catalystInstance != null
120+
}
121+
122+
override fun destroy() {
123+
UiThreadUtil.assertOnUiThread()
124+
125+
destroyed = true
126+
catalystInstance?.destroy()
127+
}
128+
129+
override fun handleException(e: Exception?) {
130+
val jsExceptionHandler: JSExceptionHandler? = jsExceptionHandler
131+
132+
if (hasActiveReactInstance() && jsExceptionHandler != null) {
133+
jsExceptionHandler.handleException(e)
134+
} else {
135+
FLog.e(
136+
ReactConstants.TAG,
137+
"Unable to handle Exception - catalystInstanceVariableExists: " +
138+
(catalystInstance != null) +
139+
" - isCatalystInstanceAlive: " +
140+
hasActiveReactInstance() +
141+
" - hasExceptionHandler: " +
142+
(jsExceptionHandler != null),
143+
e)
144+
throw IllegalStateException(e)
145+
}
146+
}
147+
148+
override fun isBridgeless(): Boolean {
149+
return false
150+
}
151+
152+
override fun getJavaScriptContextHolder(): JavaScriptContextHolder? {
153+
return catalystInstance?.javaScriptContextHolder
154+
}
155+
156+
override fun getFabricUIManager(): UIManager? {
157+
val instance =
158+
catalystInstance
159+
?: throw IllegalStateException(
160+
if (destroyed) LATE_FABRIC_UI_MANAGER_ACCESS_EXCEPTION_MESSAGE
161+
else EARLY_FABRIC_UI_MANAGER_ACCESS_EXCEPTION_MESSAGE)
162+
163+
return instance.fabricUIManager ?: instance.getJSIModule(JSIModuleType.UIManager) as? UIManager
164+
}
165+
166+
override fun getSourceURL(): String? {
167+
return catalystInstance?.sourceURL
168+
}
169+
170+
override fun registerSegment(segmentId: Int, path: String?, callback: Callback?) {
171+
catalystInstance!!.registerSegment(segmentId, path)
172+
callback!!.invoke()
173+
}
174+
175+
companion object {
176+
private const val TAG = "BridgeReactContext"
177+
178+
private const val EARLY_JS_ACCESS_EXCEPTION_MESSAGE =
179+
("Tried to access a JS module before the React instance was fully set up. Calls to " +
180+
"ReactContext#getJSModule should only happen once initialize() has been called on your " +
181+
"native module.")
182+
private const val LATE_JS_ACCESS_EXCEPTION_MESSAGE =
183+
"Tried to access a JS module after the React instance was destroyed."
184+
private const val EARLY_NATIVE_MODULE_EXCEPTION_MESSAGE =
185+
"Trying to call native module before CatalystInstance has been set!"
186+
private const val LATE_NATIVE_MODULE_EXCEPTION_MESSAGE =
187+
"Trying to call native module after CatalystInstance has been destroyed!"
188+
189+
private const val EARLY_RUNTIME_EXECUTOR_ACCESS_EXCEPTION_MESSAGE =
190+
"Tried to access a RuntimeExecutor before CatalystInstance has been set!"
191+
private const val LATE_RUNTIME_EXECUTOR_ACCESS_EXCEPTION_MESSAGE =
192+
"Tried to access a RuntimeExecutor after CatalystInstance has been destroyed!"
193+
194+
private const val LATE_FABRIC_UI_MANAGER_ACCESS_EXCEPTION_MESSAGE =
195+
"Tried to access a FabricUIManager after CatalystInstance has been destroyed!"
196+
private const val EARLY_FABRIC_UI_MANAGER_ACCESS_EXCEPTION_MESSAGE =
197+
"Tried to access a FabricUIManager after CatalystInstance before it has been set!"
198+
}
199+
}

0 commit comments

Comments
 (0)