Skip to content

Commit 14fb1cc

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: fkgozali Differential Revision: D55505416 fbshipit-source-id: ce1e3ab379eb788d26130dd44a66544aada3db02
1 parent e05319c commit 14fb1cc

5 files changed

Lines changed: 341 additions & 181 deletions

File tree

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

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,22 @@ public abstract class com/facebook/react/bridge/BaseJavaModule : com/facebook/re
543543

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

548564
public abstract interface class com/facebook/react/bridge/Callback {
@@ -1088,36 +1104,35 @@ public abstract class com/facebook/react/bridge/ReactContext : android/content/C
10881104
public fun assertOnNativeModulesQueueThread ()V
10891105
public fun assertOnNativeModulesQueueThread (Ljava/lang/String;)V
10901106
public fun assertOnUiQueueThread ()V
1091-
public fun destroy ()V
1107+
public abstract fun destroy ()V
10921108
public fun emitDeviceEvent (Ljava/lang/String;)V
10931109
public fun emitDeviceEvent (Ljava/lang/String;Ljava/lang/Object;)V
1094-
public fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
1110+
public abstract fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
10951111
public fun getCurrentActivity ()Landroid/app/Activity;
10961112
public fun getExceptionHandler ()Lcom/facebook/react/bridge/JSExceptionHandler;
1097-
public fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
1113+
public abstract fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
10981114
public fun getJSExceptionHandler ()Lcom/facebook/react/bridge/JSExceptionHandler;
10991115
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;
1116+
public abstract fun getJSModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
1117+
public abstract fun getJavaScriptContextHolder ()Lcom/facebook/react/bridge/JavaScriptContextHolder;
11021118
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;
1119+
public abstract fun getNativeModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/NativeModule;
1120+
public abstract fun getNativeModules ()Ljava/util/Collection;
11051121
public fun getNativeModulesMessageQueueThread ()Lcom/facebook/react/bridge/queue/MessageQueueThread;
1106-
public fun getSourceURL ()Ljava/lang/String;
1122+
public abstract fun getSourceURL ()Ljava/lang/String;
11071123
public fun getSystemService (Ljava/lang/String;)Ljava/lang/Object;
11081124
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
1125+
public abstract fun handleException (Ljava/lang/Exception;)V
1126+
public abstract fun hasActiveCatalystInstance ()Z
1127+
public abstract fun hasActiveReactInstance ()Z
1128+
public abstract fun hasCatalystInstance ()Z
11131129
public fun hasCurrentActivity ()Z
1114-
public fun hasNativeModule (Ljava/lang/Class;)Z
1130+
public abstract fun hasNativeModule (Ljava/lang/Class;)Z
1131+
protected fun initializeFromOther (Lcom/facebook/react/bridge/ReactContext;)V
11151132
protected fun initializeInteropModules ()V
1116-
protected fun initializeInteropModules (Lcom/facebook/react/bridge/ReactContext;)V
11171133
public fun initializeMessageQueueThreads (Lcom/facebook/react/bridge/queue/ReactQueueConfiguration;)V
1118-
public fun initializeWithInstance (Lcom/facebook/react/bridge/CatalystInstance;)V
11191134
public fun internal_registerInteropModule (Ljava/lang/Class;Ljava/lang/Object;)V
1120-
public fun isBridgeless ()Z
1135+
public abstract fun isBridgeless ()Z
11211136
public fun isOnJSQueueThread ()Z
11221137
public fun isOnNativeModulesQueueThread ()Z
11231138
public fun isOnUiQueueThread ()Z
@@ -1127,7 +1142,7 @@ public abstract class com/facebook/react/bridge/ReactContext : android/content/C
11271142
public fun onHostResume (Landroid/app/Activity;)V
11281143
public fun onNewIntent (Landroid/app/Activity;Landroid/content/Intent;)V
11291144
public fun onWindowFocusChange (Z)V
1130-
public fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
1145+
public abstract fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
11311146
public fun removeActivityEventListener (Lcom/facebook/react/bridge/ActivityEventListener;)V
11321147
public fun removeLifecycleEventListener (Lcom/facebook/react/bridge/LifecycleEventListener;)V
11331148
public fun removeWindowFocusChangeListener (Lcom/facebook/react/bridge/WindowFocusChangeListener;)V
@@ -4822,16 +4837,25 @@ public class com/facebook/react/uimanager/ThemedReactContext : com/facebook/reac
48224837
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Landroid/content/Context;)V
48234838
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Landroid/content/Context;Ljava/lang/String;)V
48244839
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;
4840+
public fun destroy ()V
4841+
public fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
48274842
public fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
4843+
public fun getJSModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
4844+
public fun getJavaScriptContextHolder ()Lcom/facebook/react/bridge/JavaScriptContextHolder;
48284845
public fun getModuleName ()Ljava/lang/String;
4846+
public fun getNativeModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/NativeModule;
4847+
public fun getNativeModules ()Ljava/util/Collection;
48294848
public fun getReactApplicationContext ()Lcom/facebook/react/bridge/ReactApplicationContext;
4849+
public fun getSourceURL ()Ljava/lang/String;
48304850
public fun getSurfaceID ()Ljava/lang/String;
48314851
public fun getSurfaceId ()I
4832-
public fun hasCurrentActivity ()Z
4852+
public fun handleException (Ljava/lang/Exception;)V
4853+
public fun hasActiveCatalystInstance ()Z
4854+
public fun hasActiveReactInstance ()Z
4855+
public fun hasCatalystInstance ()Z
4856+
public fun hasNativeModule (Ljava/lang/Class;)Z
48334857
public fun isBridgeless ()Z
4834-
public fun removeLifecycleEventListener (Lcom/facebook/react/bridge/LifecycleEventListener;)V
4858+
public fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
48354859
}
48364860

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

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

Lines changed: 183 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,194 @@
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+
public fun initializeWithInstance(otherCatalystInstance: CatalystInstance?): Unit {
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+
public 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+
public override fun <T : NativeModule?> hasNativeModule(
65+
nativeModuleInterface: Class<T>?
66+
): Boolean {
67+
val instance =
68+
catalystInstance
69+
?: throw IllegalStateException(
70+
if (destroyed) LATE_NATIVE_MODULE_EXCEPTION_MESSAGE
71+
else EARLY_NATIVE_MODULE_EXCEPTION_MESSAGE)
72+
return instance.hasNativeModule(nativeModuleInterface)
73+
}
74+
75+
public override fun getNativeModules(): MutableCollection<NativeModule> {
76+
val instance =
77+
catalystInstance
78+
?: throw IllegalStateException(
79+
if (destroyed) LATE_NATIVE_MODULE_EXCEPTION_MESSAGE
80+
else EARLY_NATIVE_MODULE_EXCEPTION_MESSAGE)
81+
return instance.nativeModules
82+
}
83+
84+
public override fun <T : NativeModule?> getNativeModule(nativeModuleInterface: Class<T>?): T? {
85+
val instance =
86+
catalystInstance
87+
?: throw IllegalStateException(
88+
if (destroyed) LATE_NATIVE_MODULE_EXCEPTION_MESSAGE
89+
else EARLY_NATIVE_MODULE_EXCEPTION_MESSAGE)
90+
return instance.getNativeModule(nativeModuleInterface)
91+
}
92+
93+
@FrameworkAPI
94+
@UnstableReactNativeAPI
95+
public override fun getRuntimeExecutor(): RuntimeExecutor? {
96+
val instance =
97+
catalystInstance
98+
?: throw IllegalStateException(
99+
if (destroyed) LATE_RUNTIME_EXECUTOR_ACCESS_EXCEPTION_MESSAGE
100+
else EARLY_RUNTIME_EXECUTOR_ACCESS_EXCEPTION_MESSAGE)
101+
102+
return instance.getRuntimeExecutor()
103+
}
104+
105+
public override fun getCatalystInstance(): CatalystInstance {
106+
return catalystInstance!!
107+
}
108+
109+
@Deprecated(
110+
"This API is unsupported in the New Architecture.", ReplaceWith("hasActiveReactInstance()"))
111+
public override fun hasActiveCatalystInstance(): Boolean {
112+
return hasActiveReactInstance()
113+
}
114+
115+
public override fun hasActiveReactInstance(): Boolean {
116+
val instance = catalystInstance
117+
return instance != null && !instance.isDestroyed
118+
}
119+
120+
public override fun hasCatalystInstance(): Boolean {
121+
return catalystInstance != null
122+
}
123+
124+
public override fun destroy(): Unit {
125+
UiThreadUtil.assertOnUiThread()
126+
127+
destroyed = true
128+
catalystInstance?.destroy()
129+
}
130+
131+
public override fun handleException(e: Exception?): Unit {
132+
val jsExceptionHandler: JSExceptionHandler? = jsExceptionHandler
133+
134+
if (hasActiveReactInstance() && jsExceptionHandler != null) {
135+
jsExceptionHandler.handleException(e)
136+
} else {
137+
FLog.e(
138+
ReactConstants.TAG,
139+
"Unable to handle Exception - catalystInstanceVariableExists: " +
140+
(catalystInstance != null) +
141+
" - isCatalystInstanceAlive: " +
142+
hasActiveReactInstance() +
143+
" - hasExceptionHandler: " +
144+
(jsExceptionHandler != null),
145+
e)
146+
throw IllegalStateException(e)
147+
}
148+
}
149+
150+
public override fun isBridgeless(): Boolean {
151+
return false
152+
}
153+
154+
public override fun getJavaScriptContextHolder(): JavaScriptContextHolder? {
155+
return catalystInstance?.javaScriptContextHolder
156+
}
157+
158+
public override fun getFabricUIManager(): UIManager? {
159+
val instance =
160+
catalystInstance
161+
?: throw IllegalStateException(
162+
if (destroyed) LATE_FABRIC_UI_MANAGER_ACCESS_EXCEPTION_MESSAGE
163+
else EARLY_FABRIC_UI_MANAGER_ACCESS_EXCEPTION_MESSAGE)
164+
165+
return instance.fabricUIManager ?: instance.getJSIModule(JSIModuleType.UIManager) as? UIManager
166+
}
167+
168+
public override fun getSourceURL(): String? {
169+
return catalystInstance?.sourceURL
170+
}
171+
172+
public override fun registerSegment(segmentId: Int, path: String?, callback: Callback?): Unit {
173+
catalystInstance!!.registerSegment(segmentId, path)
174+
callback!!.invoke()
175+
}
176+
177+
private companion object {
178+
private const val TAG = "BridgeReactContext"
179+
180+
private const val EARLY_JS_ACCESS_EXCEPTION_MESSAGE =
181+
("Tried to access a JS module before the React instance was fully set up. Calls to " +
182+
"ReactContext#getJSModule should only happen once initialize() has been called on your " +
183+
"native module.")
184+
private const val LATE_JS_ACCESS_EXCEPTION_MESSAGE =
185+
"Tried to access a JS module after the React instance was destroyed."
186+
private const val EARLY_NATIVE_MODULE_EXCEPTION_MESSAGE =
187+
"Trying to call native module before CatalystInstance has been set!"
188+
private const val LATE_NATIVE_MODULE_EXCEPTION_MESSAGE =
189+
"Trying to call native module after CatalystInstance has been destroyed!"
190+
191+
private const val EARLY_RUNTIME_EXECUTOR_ACCESS_EXCEPTION_MESSAGE =
192+
"Tried to access a RuntimeExecutor before CatalystInstance has been set!"
193+
private const val LATE_RUNTIME_EXECUTOR_ACCESS_EXCEPTION_MESSAGE =
194+
"Tried to access a RuntimeExecutor after CatalystInstance has been destroyed!"
195+
196+
private const val LATE_FABRIC_UI_MANAGER_ACCESS_EXCEPTION_MESSAGE =
197+
"Tried to access a FabricUIManager after CatalystInstance has been destroyed!"
198+
private const val EARLY_FABRIC_UI_MANAGER_ACCESS_EXCEPTION_MESSAGE =
199+
"Tried to access a FabricUIManager after CatalystInstance before it has been set!"
200+
}
201+
}

0 commit comments

Comments
 (0)