Skip to content

Commit 05ef779

Browse files
fabriziocuccifacebook-github-bot
authored andcommitted
Push ReactContext logic in derived classes (#44026)
Summary: Pull Request resolved: #44026 Changelog: [Android][Removed] Delete ReactContext.initializeWithInstance(). ReactContext now no longer contains legacy react instance methods. Please use BridgeReactInstance instead. Yet another attempt to land this (last one was D55505416). Copy-pasting below the amazing summary from RSNara. ## 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). NOTE: Intentionally not converting `BridgeReactContext` to Kotlin to minimize the risk of these changes. Reviewed By: RSNara Differential Revision: D55964787 fbshipit-source-id: b404efe0c7095894fa815165cc8682f78dccfa17
1 parent b4f9aa1 commit 05ef779

6 files changed

Lines changed: 349 additions & 200 deletions

File tree

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

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -543,8 +543,25 @@ public abstract class com/facebook/react/bridge/BaseJavaModule : com/facebook/re
543543
public fun invalidate ()V
544544
}
545545

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

550567
public abstract interface class com/facebook/react/bridge/Callback {
@@ -1090,36 +1107,35 @@ public abstract class com/facebook/react/bridge/ReactContext : android/content/C
10901107
public fun assertOnNativeModulesQueueThread ()V
10911108
public fun assertOnNativeModulesQueueThread (Ljava/lang/String;)V
10921109
public fun assertOnUiQueueThread ()V
1093-
public fun destroy ()V
1110+
public abstract fun destroy ()V
10941111
public fun emitDeviceEvent (Ljava/lang/String;)V
10951112
public fun emitDeviceEvent (Ljava/lang/String;Ljava/lang/Object;)V
1096-
public fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
1113+
public abstract fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
10971114
public fun getCurrentActivity ()Landroid/app/Activity;
10981115
public fun getExceptionHandler ()Lcom/facebook/react/bridge/JSExceptionHandler;
1099-
public fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
1116+
public abstract fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
11001117
public fun getJSExceptionHandler ()Lcom/facebook/react/bridge/JSExceptionHandler;
11011118
public fun getJSMessageQueueThread ()Lcom/facebook/react/bridge/queue/MessageQueueThread;
1102-
public fun getJSModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
1103-
public fun getJavaScriptContextHolder ()Lcom/facebook/react/bridge/JavaScriptContextHolder;
1119+
public abstract fun getJSModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
1120+
public abstract fun getJavaScriptContextHolder ()Lcom/facebook/react/bridge/JavaScriptContextHolder;
11041121
public fun getLifecycleState ()Lcom/facebook/react/common/LifecycleState;
1105-
public fun getNativeModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/NativeModule;
1106-
public fun getNativeModules ()Ljava/util/Collection;
1122+
public abstract fun getNativeModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/NativeModule;
1123+
public abstract fun getNativeModules ()Ljava/util/Collection;
11071124
public fun getNativeModulesMessageQueueThread ()Lcom/facebook/react/bridge/queue/MessageQueueThread;
1108-
public fun getSourceURL ()Ljava/lang/String;
1125+
public abstract fun getSourceURL ()Ljava/lang/String;
11091126
public fun getSystemService (Ljava/lang/String;)Ljava/lang/Object;
11101127
public fun getUiMessageQueueThread ()Lcom/facebook/react/bridge/queue/MessageQueueThread;
1111-
public fun handleException (Ljava/lang/Exception;)V
1112-
public fun hasActiveCatalystInstance ()Z
1113-
public fun hasActiveReactInstance ()Z
1114-
public fun hasCatalystInstance ()Z
1128+
public abstract fun handleException (Ljava/lang/Exception;)V
1129+
public abstract fun hasActiveCatalystInstance ()Z
1130+
public abstract fun hasActiveReactInstance ()Z
1131+
public abstract fun hasCatalystInstance ()Z
11151132
public fun hasCurrentActivity ()Z
1116-
public fun hasNativeModule (Ljava/lang/Class;)Z
1133+
public abstract fun hasNativeModule (Ljava/lang/Class;)Z
1134+
protected fun initializeFromOther (Lcom/facebook/react/bridge/ReactContext;)V
11171135
protected fun initializeInteropModules ()V
1118-
protected fun initializeInteropModules (Lcom/facebook/react/bridge/ReactContext;)V
11191136
public fun initializeMessageQueueThreads (Lcom/facebook/react/bridge/queue/ReactQueueConfiguration;)V
1120-
public fun initializeWithInstance (Lcom/facebook/react/bridge/CatalystInstance;)V
11211137
public fun internal_registerInteropModule (Ljava/lang/Class;Ljava/lang/Object;)V
1122-
public fun isBridgeless ()Z
1138+
public abstract fun isBridgeless ()Z
11231139
public fun isOnJSQueueThread ()Z
11241140
public fun isOnNativeModulesQueueThread ()Z
11251141
public fun isOnUiQueueThread ()Z
@@ -1129,7 +1145,7 @@ public abstract class com/facebook/react/bridge/ReactContext : android/content/C
11291145
public fun onHostResume (Landroid/app/Activity;)V
11301146
public fun onNewIntent (Landroid/app/Activity;Landroid/content/Intent;)V
11311147
public fun onWindowFocusChange (Z)V
1132-
public fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
1148+
public abstract fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
11331149
public fun removeActivityEventListener (Lcom/facebook/react/bridge/ActivityEventListener;)V
11341150
public fun removeLifecycleEventListener (Lcom/facebook/react/bridge/LifecycleEventListener;)V
11351151
public fun removeWindowFocusChangeListener (Lcom/facebook/react/bridge/WindowFocusChangeListener;)V
@@ -4894,16 +4910,25 @@ public class com/facebook/react/uimanager/ThemedReactContext : com/facebook/reac
48944910
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Landroid/content/Context;)V
48954911
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Landroid/content/Context;Ljava/lang/String;)V
48964912
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Landroid/content/Context;Ljava/lang/String;I)V
4897-
public fun addLifecycleEventListener (Lcom/facebook/react/bridge/LifecycleEventListener;)V
4898-
public fun getCurrentActivity ()Landroid/app/Activity;
4913+
public fun destroy ()V
4914+
public fun getCatalystInstance ()Lcom/facebook/react/bridge/CatalystInstance;
48994915
public fun getFabricUIManager ()Lcom/facebook/react/bridge/UIManager;
4916+
public fun getJSModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/JavaScriptModule;
4917+
public fun getJavaScriptContextHolder ()Lcom/facebook/react/bridge/JavaScriptContextHolder;
49004918
public fun getModuleName ()Ljava/lang/String;
4919+
public fun getNativeModule (Ljava/lang/Class;)Lcom/facebook/react/bridge/NativeModule;
4920+
public fun getNativeModules ()Ljava/util/Collection;
49014921
public fun getReactApplicationContext ()Lcom/facebook/react/bridge/ReactApplicationContext;
4922+
public fun getSourceURL ()Ljava/lang/String;
49024923
public fun getSurfaceID ()Ljava/lang/String;
49034924
public fun getSurfaceId ()I
4904-
public fun hasCurrentActivity ()Z
4925+
public fun handleException (Ljava/lang/Exception;)V
4926+
public fun hasActiveCatalystInstance ()Z
4927+
public fun hasActiveReactInstance ()Z
4928+
public fun hasCatalystInstance ()Z
4929+
public fun hasNativeModule (Ljava/lang/Class;)Z
49054930
public fun isBridgeless ()Z
4906-
public fun removeLifecycleEventListener (Lcom/facebook/react/bridge/LifecycleEventListener;)V
4931+
public fun registerSegment (ILjava/lang/String;Lcom/facebook/react/bridge/Callback;)V
49074932
}
49084933

49094934
public class com/facebook/react/uimanager/TouchTargetHelper {
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.bridge;
9+
10+
import android.content.Context;
11+
import androidx.annotation.Nullable;
12+
import com.facebook.common.logging.FLog;
13+
import com.facebook.infer.annotation.Assertions;
14+
import com.facebook.infer.annotation.Nullsafe;
15+
import com.facebook.react.bridge.queue.ReactQueueConfiguration;
16+
import com.facebook.react.common.ReactConstants;
17+
import com.facebook.react.common.annotations.DeprecatedInNewArchitecture;
18+
import java.util.Collection;
19+
20+
/**
21+
* This is the bridge-specific concrete subclass of ReactContext. ReactContext has many methods that
22+
* delegate to the react instance. This subclass implements those methods, by delegating to the
23+
* CatalystInstance. If you need to create a ReactContext within an "bridge context", please create
24+
* BridgeReactContext.
25+
*/
26+
@DeprecatedInNewArchitecture
27+
@Nullsafe(Nullsafe.Mode.LOCAL)
28+
public class BridgeReactContext extends ReactApplicationContext {
29+
30+
private static final String TAG = "BridgeReactContext";
31+
32+
private static final String EARLY_CALL_EXCEPTION_MESSAGE =
33+
"Called %s before setting the Catalyst instance!";
34+
35+
private static final String LATE_CALL_EXCEPTION_MESSAGE =
36+
"Called %s after destroying the Catalyst instance!";
37+
38+
private volatile boolean mDestroyed = false;
39+
private @Nullable CatalystInstance mCatalystInstance;
40+
41+
public BridgeReactContext(Context context) {
42+
super(context);
43+
}
44+
45+
public void initializeWithInstance(CatalystInstance catalystInstance) {
46+
if (catalystInstance == null) {
47+
throw new IllegalArgumentException("CatalystInstance cannot be null.");
48+
}
49+
if (mCatalystInstance != null) {
50+
throw new IllegalStateException("ReactContext has been already initialized");
51+
}
52+
if (mDestroyed) {
53+
ReactSoftExceptionLogger.logSoftException(
54+
TAG,
55+
new IllegalStateException("Cannot initialize ReactContext after it has been destroyed."));
56+
}
57+
58+
mCatalystInstance = catalystInstance;
59+
60+
ReactQueueConfiguration queueConfig = catalystInstance.getReactQueueConfiguration();
61+
initializeMessageQueueThreads(queueConfig);
62+
initializeInteropModules();
63+
}
64+
65+
@Override
66+
public void destroy() {
67+
UiThreadUtil.assertOnUiThread();
68+
69+
mDestroyed = true;
70+
if (mCatalystInstance != null) {
71+
mCatalystInstance.destroy();
72+
}
73+
}
74+
75+
@Override
76+
public CatalystInstance getCatalystInstance() {
77+
return Assertions.assertNotNull(mCatalystInstance);
78+
}
79+
80+
@Override
81+
public @Nullable UIManager getFabricUIManager() {
82+
CatalystInstance catalystInstance = getNonNullableCatalystInstanceOrThrow("getFabricUIManager");
83+
UIManager uiManager = catalystInstance.getFabricUIManager();
84+
return uiManager != null
85+
? uiManager
86+
: (UIManager) catalystInstance.getJSIModule(JSIModuleType.UIManager);
87+
}
88+
89+
@Override
90+
public @Nullable JavaScriptContextHolder getJavaScriptContextHolder() {
91+
return mCatalystInstance != null ? mCatalystInstance.getJavaScriptContextHolder() : null;
92+
}
93+
94+
@Override
95+
public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
96+
CatalystInstance catalystInstance = getNonNullableCatalystInstanceOrThrow("getJSModule");
97+
98+
if (mInteropModuleRegistry != null
99+
&& mInteropModuleRegistry.shouldReturnInteropModule(jsInterface)) {
100+
return mInteropModuleRegistry.getInteropModule(jsInterface);
101+
}
102+
103+
return catalystInstance.getJSModule(jsInterface);
104+
}
105+
106+
@Override
107+
public @Nullable <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
108+
CatalystInstance catalystInstance = getNonNullableCatalystInstanceOrThrow("getNativeModule");
109+
return catalystInstance.getNativeModule(nativeModuleInterface);
110+
}
111+
112+
@Override
113+
public Collection<NativeModule> getNativeModules() {
114+
CatalystInstance catalystInstance = getNonNullableCatalystInstanceOrThrow("getNativeModules");
115+
return catalystInstance.getNativeModules();
116+
}
117+
118+
@Override
119+
public @Nullable RuntimeExecutor getRuntimeExecutor() {
120+
CatalystInstance catalystInstance = getNonNullableCatalystInstanceOrThrow("getRuntimeExecutor");
121+
return catalystInstance.getRuntimeExecutor();
122+
}
123+
124+
@Override
125+
public @Nullable String getSourceURL() {
126+
return mCatalystInstance != null ? mCatalystInstance.getSourceURL() : null;
127+
}
128+
129+
@Override
130+
public void handleException(Exception e) {
131+
JSExceptionHandler jsExceptionHandler = getJSExceptionHandler();
132+
if (hasActiveReactInstance() && jsExceptionHandler != null) {
133+
jsExceptionHandler.handleException(e);
134+
} else {
135+
FLog.e(
136+
ReactConstants.TAG,
137+
"Unable to handle Exception - catalystInstanceVariableExists: "
138+
+ (mCatalystInstance != null)
139+
+ " - isCatalystInstanceAlive: "
140+
+ hasActiveReactInstance()
141+
+ " - hasExceptionHandler: "
142+
+ (jsExceptionHandler != null),
143+
e);
144+
throw new IllegalStateException(e);
145+
}
146+
}
147+
148+
@Deprecated
149+
@Override
150+
public boolean hasActiveCatalystInstance() {
151+
return hasActiveReactInstance();
152+
}
153+
154+
@Override
155+
public boolean hasActiveReactInstance() {
156+
return mCatalystInstance != null && !mCatalystInstance.isDestroyed();
157+
}
158+
159+
@Override
160+
public boolean hasCatalystInstance() {
161+
return mCatalystInstance != null;
162+
}
163+
164+
@Override
165+
public <T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface) {
166+
CatalystInstance catalystInstance = getNonNullableCatalystInstanceOrThrow("hasNativeModule");
167+
return catalystInstance.hasNativeModule(nativeModuleInterface);
168+
}
169+
170+
@Override
171+
public boolean isBridgeless() {
172+
return false;
173+
}
174+
175+
@Override
176+
public void registerSegment(int segmentId, String path, Callback callback) {
177+
Assertions.assertNotNull(mCatalystInstance).registerSegment(segmentId, path);
178+
Assertions.assertNotNull(callback).invoke();
179+
}
180+
181+
private CatalystInstance getNonNullableCatalystInstanceOrThrow(String accessTarget) {
182+
if (mCatalystInstance != null) {
183+
return mCatalystInstance;
184+
}
185+
throw new IllegalStateException(
186+
String.format(
187+
mDestroyed ? LATE_CALL_EXCEPTION_MESSAGE : EARLY_CALL_EXCEPTION_MESSAGE, accessTarget));
188+
}
189+
}

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

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)