mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Move BridgelessDevSupportManager to .devsupport package (#46914)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46914 The `BridgelessDevSupportManager` should have lived inside the `.devsupport` package alongside all the other devsupport related tooling. It was instead created inside `.runtime` causing a tight coupling with `ReactHostImpl`. This made it impossible for Frameworks to customize it (i.e. in Expo GO) also because there was a circular dependency between ReactHostImpl and BridgelessDevSupportManager In this diff I'm: 1. Breaking the circular dependency by using `ReactHostDevHelper` 2. Updating all the parameters to reference `ReactHost` rather than `ReactHostImpl` 3. Moving BridgelessDevSupportManager to the `.devsupport` package. This is breaking for users that are manually composing a `BridgelessDevSupportManager` or that are extending the `ReactInstanceDevHelper`. - `ReactInstanceDevHelper` has 3 new method which will have to be implemented. - `BridgelessDevSupportManager` is now living in a different package. Changelog: [Android] [Breaking] - Add 3 methods to ReactInstanceDevHelper Reviewed By: rshest Differential Revision: D64105790 fbshipit-source-id: 13478fe1a035adb5b0dc83ebb1daad6cfb243881
This commit is contained in:
committed by
Facebook GitHub Bot
parent
ad6a2fa612
commit
c867aba2f3
@@ -2134,6 +2134,7 @@ public final class com/facebook/react/devsupport/DefaultDevLoadingViewImplementa
|
||||
public final class com/facebook/react/devsupport/DefaultDevSupportManagerFactory : com/facebook/react/devsupport/DevSupportManagerFactory {
|
||||
public fun <init> ()V
|
||||
public fun create (Landroid/content/Context;Lcom/facebook/react/devsupport/ReactInstanceDevHelper;Ljava/lang/String;ZLcom/facebook/react/devsupport/interfaces/RedBoxHandler;Lcom/facebook/react/devsupport/interfaces/DevBundleDownloadListener;ILjava/util/Map;Lcom/facebook/react/common/SurfaceDelegateFactory;Lcom/facebook/react/devsupport/interfaces/DevLoadingViewManager;Lcom/facebook/react/devsupport/interfaces/PausedInDebuggerOverlayManager;)Lcom/facebook/react/devsupport/interfaces/DevSupportManager;
|
||||
public fun create (Landroid/content/Context;Lcom/facebook/react/devsupport/ReactInstanceDevHelper;Ljava/lang/String;ZLcom/facebook/react/devsupport/interfaces/RedBoxHandler;Lcom/facebook/react/devsupport/interfaces/DevBundleDownloadListener;ILjava/util/Map;Lcom/facebook/react/common/SurfaceDelegateFactory;Lcom/facebook/react/devsupport/interfaces/DevLoadingViewManager;Lcom/facebook/react/devsupport/interfaces/PausedInDebuggerOverlayManager;Z)Lcom/facebook/react/devsupport/interfaces/DevSupportManager;
|
||||
}
|
||||
|
||||
public class com/facebook/react/devsupport/DevServerHelper {
|
||||
@@ -2173,6 +2174,7 @@ public final class com/facebook/react/devsupport/DevSettingsActivity : android/p
|
||||
}
|
||||
|
||||
public abstract class com/facebook/react/devsupport/DevSupportManagerBase : com/facebook/react/devsupport/interfaces/DevSupportManager {
|
||||
protected final field mReactInstanceDevHelper Lcom/facebook/react/devsupport/ReactInstanceDevHelper;
|
||||
public fun <init> (Landroid/content/Context;Lcom/facebook/react/devsupport/ReactInstanceDevHelper;Ljava/lang/String;ZLcom/facebook/react/devsupport/interfaces/RedBoxHandler;Lcom/facebook/react/devsupport/interfaces/DevBundleDownloadListener;ILjava/util/Map;Lcom/facebook/react/common/SurfaceDelegateFactory;Lcom/facebook/react/devsupport/interfaces/DevLoadingViewManager;Lcom/facebook/react/devsupport/interfaces/PausedInDebuggerOverlayManager;)V
|
||||
public fun addCustomDevOption (Ljava/lang/String;Lcom/facebook/react/devsupport/interfaces/DevOptionHandler;)V
|
||||
public fun createRootView (Ljava/lang/String;)Landroid/view/View;
|
||||
@@ -2236,6 +2238,7 @@ public abstract interface class com/facebook/react/devsupport/DevSupportManagerB
|
||||
|
||||
public abstract interface class com/facebook/react/devsupport/DevSupportManagerFactory {
|
||||
public abstract fun create (Landroid/content/Context;Lcom/facebook/react/devsupport/ReactInstanceDevHelper;Ljava/lang/String;ZLcom/facebook/react/devsupport/interfaces/RedBoxHandler;Lcom/facebook/react/devsupport/interfaces/DevBundleDownloadListener;ILjava/util/Map;Lcom/facebook/react/common/SurfaceDelegateFactory;Lcom/facebook/react/devsupport/interfaces/DevLoadingViewManager;Lcom/facebook/react/devsupport/interfaces/PausedInDebuggerOverlayManager;)Lcom/facebook/react/devsupport/interfaces/DevSupportManager;
|
||||
public abstract fun create (Landroid/content/Context;Lcom/facebook/react/devsupport/ReactInstanceDevHelper;Ljava/lang/String;ZLcom/facebook/react/devsupport/interfaces/RedBoxHandler;Lcom/facebook/react/devsupport/interfaces/DevBundleDownloadListener;ILjava/util/Map;Lcom/facebook/react/common/SurfaceDelegateFactory;Lcom/facebook/react/devsupport/interfaces/DevLoadingViewManager;Lcom/facebook/react/devsupport/interfaces/PausedInDebuggerOverlayManager;Z)Lcom/facebook/react/devsupport/interfaces/DevSupportManager;
|
||||
}
|
||||
|
||||
public final class com/facebook/react/devsupport/DoubleTapReloadRecognizer {
|
||||
@@ -2327,9 +2330,12 @@ public abstract interface class com/facebook/react/devsupport/ReactInstanceDevHe
|
||||
public abstract fun createRootView (Ljava/lang/String;)Landroid/view/View;
|
||||
public abstract fun destroyRootView (Landroid/view/View;)V
|
||||
public abstract fun getCurrentActivity ()Landroid/app/Activity;
|
||||
public abstract fun getCurrentReactContext ()Lcom/facebook/react/bridge/ReactContext;
|
||||
public abstract fun getJavaScriptExecutorFactory ()Lcom/facebook/react/bridge/JavaScriptExecutorFactory;
|
||||
public abstract fun loadBundle (Lcom/facebook/react/bridge/JSBundleLoader;)Lcom/facebook/react/interfaces/TaskInterface;
|
||||
public abstract fun onJSBundleLoadedFromServer ()V
|
||||
public abstract fun onReloadWithJSDebugger (Lcom/facebook/react/bridge/JavaJSExecutor$Factory;)V
|
||||
public abstract fun reload (Ljava/lang/String;)V
|
||||
public abstract fun toggleElementInspector ()V
|
||||
}
|
||||
|
||||
@@ -3887,6 +3893,7 @@ public abstract class com/facebook/react/runtime/JSRuntimeFactory {
|
||||
|
||||
public class com/facebook/react/runtime/ReactHostImpl : com/facebook/react/ReactHost {
|
||||
public fun <init> (Landroid/content/Context;Lcom/facebook/react/runtime/ReactHostDelegate;Lcom/facebook/react/fabric/ComponentFactory;Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;ZZ)V
|
||||
public fun <init> (Landroid/content/Context;Lcom/facebook/react/runtime/ReactHostDelegate;Lcom/facebook/react/fabric/ComponentFactory;Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;ZZLcom/facebook/react/devsupport/DevSupportManagerFactory;)V
|
||||
public fun <init> (Landroid/content/Context;Lcom/facebook/react/runtime/ReactHostDelegate;Lcom/facebook/react/fabric/ComponentFactory;ZZ)V
|
||||
public fun addBeforeDestroyListener (Lkotlin/jvm/functions/Function0;)V
|
||||
public fun addReactInstanceEventListener (Lcom/facebook/react/ReactInstanceEventListener;)V
|
||||
@@ -3918,7 +3925,7 @@ public class com/facebook/react/runtime/ReactHostImpl : com/facebook/react/React
|
||||
|
||||
public class com/facebook/react/runtime/ReactSurfaceImpl : com/facebook/react/interfaces/fabric/ReactSurface {
|
||||
public fun <init> (Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)V
|
||||
public fun attach (Lcom/facebook/react/runtime/ReactHostImpl;)V
|
||||
public fun attach (Lcom/facebook/react/ReactHost;)V
|
||||
public fun attachView (Lcom/facebook/react/runtime/ReactSurfaceView;)V
|
||||
public fun clear ()V
|
||||
public static fun createWithView (Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Lcom/facebook/react/runtime/ReactSurfaceImpl;
|
||||
|
||||
+18
@@ -92,6 +92,7 @@ import com.facebook.react.devsupport.interfaces.DevSupportManager.PausedInDebugg
|
||||
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
|
||||
import com.facebook.react.devsupport.interfaces.PausedInDebuggerOverlayManager;
|
||||
import com.facebook.react.devsupport.interfaces.RedBoxHandler;
|
||||
import com.facebook.react.interfaces.TaskInterface;
|
||||
import com.facebook.react.internal.AndroidChoreographerProvider;
|
||||
import com.facebook.react.internal.ChoreographerProvider;
|
||||
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
|
||||
@@ -369,6 +370,23 @@ public class ReactInstanceManager {
|
||||
((ReactRootView) rootView).unmountReactApplication();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(String s) {
|
||||
// no-op not implemented for Bridge Mode
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskInterface<Boolean> loadBundle(JSBundleLoader bundleLoader) {
|
||||
// no-op not implemented for Bridge Mode
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactContext getCurrentReactContext() {
|
||||
// no-op not implemented for Bridge Mode
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.devsupport;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.bridge.JSBundleLoader;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.SurfaceDelegateFactory;
|
||||
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.devsupport.interfaces.DevLoadingViewManager;
|
||||
import com.facebook.react.devsupport.interfaces.DevSplitBundleCallback;
|
||||
import com.facebook.react.devsupport.interfaces.PausedInDebuggerOverlayManager;
|
||||
import com.facebook.react.devsupport.interfaces.RedBoxHandler;
|
||||
import com.facebook.react.packagerconnection.RequestHandler;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An implementation of {@link com.facebook.react.devsupport.interfaces.DevSupportManager} that
|
||||
* extends the functionality in {@link DevSupportManagerBase} with some additional, more flexible
|
||||
* APIs for asynchronously loading the JS bundle.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
class BridgelessDevSupportManager extends DevSupportManagerBase {
|
||||
|
||||
public BridgelessDevSupportManager(
|
||||
Context context,
|
||||
ReactInstanceDevHelper reactInstanceManagerHelper,
|
||||
@Nullable String packagerPathForJSBundleName) {
|
||||
this(
|
||||
context.getApplicationContext(),
|
||||
reactInstanceManagerHelper,
|
||||
packagerPathForJSBundleName,
|
||||
true /* enableOnCreate */,
|
||||
null /* redBoxHandler */,
|
||||
null /* devBundleDownloadListener */,
|
||||
2 /* minNumShakes */,
|
||||
null /* customPackagerCommandHandlers */,
|
||||
null /* surfaceDelegateFactory */,
|
||||
null /* devLoadingViewManager */,
|
||||
null /* pausedInDebuggerOverlayManager */);
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor mirrors the same constructor we have for {@link BridgeDevSupportManager} and
|
||||
* is kept for backward compatibility.
|
||||
*/
|
||||
public BridgelessDevSupportManager(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevHelper reactInstanceManagerHelper,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
@Nullable RedBoxHandler redBoxHandler,
|
||||
@Nullable DevBundleDownloadListener devBundleDownloadListener,
|
||||
int minNumShakes,
|
||||
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers,
|
||||
@Nullable SurfaceDelegateFactory surfaceDelegateFactory,
|
||||
@Nullable DevLoadingViewManager devLoadingViewManager,
|
||||
@Nullable PausedInDebuggerOverlayManager pausedInDebuggerOverlayManager) {
|
||||
super(
|
||||
applicationContext,
|
||||
reactInstanceManagerHelper,
|
||||
packagerPathForJSBundleName,
|
||||
enableOnCreate,
|
||||
redBoxHandler,
|
||||
devBundleDownloadListener,
|
||||
minNumShakes,
|
||||
customPackagerCommandHandlers,
|
||||
surfaceDelegateFactory,
|
||||
devLoadingViewManager,
|
||||
pausedInDebuggerOverlayManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUniqueTag() {
|
||||
return "Bridgeless";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSplitBundleFromServer(
|
||||
final String bundlePath, final DevSplitBundleCallback callback) {
|
||||
fetchSplitBundleAndCreateBundleLoader(
|
||||
bundlePath,
|
||||
new CallbackWithBundleLoader() {
|
||||
@Override
|
||||
public void onSuccess(final JSBundleLoader bundleLoader) {
|
||||
try {
|
||||
mReactInstanceDevHelper.loadBundle(bundleLoader).waitForCompletion();
|
||||
String bundleURL = getDevServerHelper().getDevServerSplitBundleURL(bundlePath);
|
||||
ReactContext reactContext = mReactInstanceDevHelper.getCurrentReactContext();
|
||||
if (reactContext != null) {
|
||||
reactContext.getJSModule(HMRClient.class).registerBundle(bundleURL);
|
||||
}
|
||||
callback.onSuccess();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(
|
||||
"[BridgelessDevSupportManager]: Got interrupted while loading bundle", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String url, Throwable cause) {
|
||||
callback.onError(url, cause);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReloadJS() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
// dismiss redbox if exists
|
||||
hideRedboxDialog();
|
||||
mReactInstanceDevHelper.reload("BridgelessDevSupportManager.handleReloadJS()");
|
||||
}
|
||||
}
|
||||
+33
-1
@@ -19,7 +19,8 @@ import com.facebook.react.packagerconnection.RequestHandler
|
||||
/**
|
||||
* A simple factory that creates instances of [DevSupportManager] implementations. Uses reflection
|
||||
* to create BridgeDevSupportManager if it exists. This allows ProGuard to strip that class and its
|
||||
* dependencies in release builds. If the class isn't found, [ ] is returned instead.
|
||||
* dependencies in release builds. If the class isn't found, [PerftestDevSupportManager] is returned
|
||||
* instead.
|
||||
*/
|
||||
public class DefaultDevSupportManagerFactory : DevSupportManagerFactory {
|
||||
|
||||
@@ -85,6 +86,37 @@ public class DefaultDevSupportManagerFactory : DevSupportManagerFactory {
|
||||
}
|
||||
}
|
||||
|
||||
override fun create(
|
||||
applicationContext: Context,
|
||||
reactInstanceManagerHelper: ReactInstanceDevHelper,
|
||||
packagerPathForJSBundleName: String?,
|
||||
enableOnCreate: Boolean,
|
||||
redBoxHandler: RedBoxHandler?,
|
||||
devBundleDownloadListener: DevBundleDownloadListener?,
|
||||
minNumShakes: Int,
|
||||
customPackagerCommandHandlers: MutableMap<String, RequestHandler>?,
|
||||
surfaceDelegateFactory: SurfaceDelegateFactory?,
|
||||
devLoadingViewManager: DevLoadingViewManager?,
|
||||
pausedInDebuggerOverlayManager: PausedInDebuggerOverlayManager?,
|
||||
useDevSupport: Boolean
|
||||
): DevSupportManager =
|
||||
if (!useDevSupport) {
|
||||
ReleaseDevSupportManager()
|
||||
} else {
|
||||
BridgelessDevSupportManager(
|
||||
applicationContext,
|
||||
reactInstanceManagerHelper,
|
||||
packagerPathForJSBundleName,
|
||||
enableOnCreate,
|
||||
redBoxHandler,
|
||||
devBundleDownloadListener,
|
||||
minNumShakes,
|
||||
customPackagerCommandHandlers,
|
||||
surfaceDelegateFactory,
|
||||
devLoadingViewManager,
|
||||
pausedInDebuggerOverlayManager)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val DEVSUPPORT_IMPL_PACKAGE = "com.facebook.react.devsupport"
|
||||
private const val DEVSUPPORT_IMPL_CLASS = "BridgeDevSupportManager"
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
|
||||
private final BroadcastReceiver mReloadAppBroadcastReceiver;
|
||||
private final DevServerHelper mDevServerHelper;
|
||||
private final LinkedHashMap<String, DevOptionHandler> mCustomDevOptions = new LinkedHashMap<>();
|
||||
private final ReactInstanceDevHelper mReactInstanceDevHelper;
|
||||
protected final ReactInstanceDevHelper mReactInstanceDevHelper;
|
||||
private final @Nullable String mJSAppBundleName;
|
||||
private final File mJSBundleDownloadedFile;
|
||||
private final File mJSSplitBundlesDir;
|
||||
|
||||
+22
@@ -19,6 +19,10 @@ import com.facebook.react.packagerconnection.RequestHandler;
|
||||
import java.util.Map;
|
||||
|
||||
public interface DevSupportManagerFactory {
|
||||
/**
|
||||
* Factory used by the Old Architecture flow to create a {@link DevSupportManager} and a {@link
|
||||
* com.facebook.react.runtime.BridgeDevSupportManager}
|
||||
*/
|
||||
DevSupportManager create(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevHelper reactInstanceManagerHelper,
|
||||
@@ -31,4 +35,22 @@ public interface DevSupportManagerFactory {
|
||||
@Nullable SurfaceDelegateFactory surfaceDelegateFactory,
|
||||
@Nullable DevLoadingViewManager devLoadingViewManager,
|
||||
@Nullable PausedInDebuggerOverlayManager pausedInDebuggerOverlayManager);
|
||||
|
||||
/**
|
||||
* Factory used by the New Architecture/Bridgeless flow to create a {@link DevSupportManager} and
|
||||
* a {@link BridgelessDevSupportManager}
|
||||
*/
|
||||
DevSupportManager create(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevHelper reactInstanceManagerHelper,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
@Nullable RedBoxHandler redBoxHandler,
|
||||
@Nullable DevBundleDownloadListener devBundleDownloadListener,
|
||||
int minNumShakes,
|
||||
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers,
|
||||
@Nullable SurfaceDelegateFactory surfaceDelegateFactory,
|
||||
@Nullable DevLoadingViewManager devLoadingViewManager,
|
||||
@Nullable PausedInDebuggerOverlayManager pausedInDebuggerOverlayManager,
|
||||
boolean useDevSupport);
|
||||
}
|
||||
|
||||
+12
-2
@@ -10,13 +10,16 @@ package com.facebook.react.devsupport;
|
||||
import android.app.Activity;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.JSBundleLoader;
|
||||
import com.facebook.react.bridge.JavaJSExecutor;
|
||||
import com.facebook.react.bridge.JavaScriptExecutorFactory;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.interfaces.TaskInterface;
|
||||
|
||||
/**
|
||||
* Interface used by {@link DevSupportManager} for accessing some fields and methods of {@link
|
||||
* ReactInstanceManager} or {@link ReactHostImpl} for the purpose of displaying and handling
|
||||
* developer menu options.
|
||||
* ReactInstanceManager} or {@link ReactHost} for the purpose of displaying and handling developer
|
||||
* menu options.
|
||||
*/
|
||||
public interface ReactInstanceDevHelper {
|
||||
|
||||
@@ -39,4 +42,11 @@ public interface ReactInstanceDevHelper {
|
||||
View createRootView(String appKey);
|
||||
|
||||
void destroyRootView(View rootView);
|
||||
|
||||
void reload(String s);
|
||||
|
||||
TaskInterface<Boolean> loadBundle(JSBundleLoader bundleLoader);
|
||||
|
||||
@Nullable
|
||||
ReactContext getCurrentReactContext();
|
||||
}
|
||||
|
||||
-159
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* 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.runtime;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.bridge.JSBundleLoader;
|
||||
import com.facebook.react.bridge.JavaJSExecutor;
|
||||
import com.facebook.react.bridge.JavaScriptExecutorFactory;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.devsupport.DevSupportManagerBase;
|
||||
import com.facebook.react.devsupport.HMRClient;
|
||||
import com.facebook.react.devsupport.ReactInstanceDevHelper;
|
||||
import com.facebook.react.devsupport.interfaces.DevSplitBundleCallback;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.runtime.internal.bolts.Continuation;
|
||||
import com.facebook.react.runtime.internal.bolts.Task;
|
||||
|
||||
/**
|
||||
* An implementation of {@link com.facebook.react.devsupport.interfaces.DevSupportManager} that
|
||||
* extends the functionality in {@link DevSupportManagerBase} with some additional, more flexible
|
||||
* APIs for asynchronously loading the JS bundle.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
class BridgelessDevSupportManager extends DevSupportManagerBase {
|
||||
|
||||
private final ReactHostImpl mReactHost;
|
||||
|
||||
public BridgelessDevSupportManager(
|
||||
ReactHostImpl host, Context context, @Nullable String packagerPathForJSBundleName) {
|
||||
super(
|
||||
context.getApplicationContext(),
|
||||
createInstanceDevHelper(host),
|
||||
packagerPathForJSBundleName,
|
||||
true /* enableOnCreate */,
|
||||
null /* redBoxHandler */,
|
||||
null /* devBundleDownloadListener */,
|
||||
2 /* minNumShakes */,
|
||||
null /* customPackagerCommandHandlers */,
|
||||
null /* surfaceDelegateFactory */,
|
||||
null /* devLoadingViewManager */,
|
||||
null /* pausedInDebuggerOverlayManager */);
|
||||
mReactHost = host;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUniqueTag() {
|
||||
return "Bridgeless";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSplitBundleFromServer(
|
||||
final String bundlePath, final DevSplitBundleCallback callback) {
|
||||
fetchSplitBundleAndCreateBundleLoader(
|
||||
bundlePath,
|
||||
new CallbackWithBundleLoader() {
|
||||
@Override
|
||||
public void onSuccess(final JSBundleLoader bundleLoader) {
|
||||
mReactHost
|
||||
.loadBundle(bundleLoader)
|
||||
.onSuccess(
|
||||
new Continuation<Boolean, Void>() {
|
||||
@Override
|
||||
public Void then(Task<Boolean> task) {
|
||||
if (task.getResult().equals(Boolean.TRUE)) {
|
||||
String bundleURL =
|
||||
getDevServerHelper().getDevServerSplitBundleURL(bundlePath);
|
||||
ReactContext reactContext = mReactHost.getCurrentReactContext();
|
||||
if (reactContext != null) {
|
||||
reactContext.getJSModule(HMRClient.class).registerBundle(bundleURL);
|
||||
}
|
||||
callback.onSuccess();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String url, Throwable cause) {
|
||||
callback.onError(url, cause);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReloadJS() {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
// dismiss redbox if exists
|
||||
hideRedboxDialog();
|
||||
mReactHost.reload("BridgelessDevSupportManager.handleReloadJS()");
|
||||
}
|
||||
|
||||
private static ReactInstanceDevHelper createInstanceDevHelper(final ReactHostImpl reactHost) {
|
||||
return new ReactInstanceDevHelper() {
|
||||
@Override
|
||||
public void onReloadWithJSDebugger(JavaJSExecutor.Factory proxyExecutorFactory) {
|
||||
// Not implemented, only used by BridgeDevSupportManager to reload with proxy executor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJSBundleLoadedFromServer() {
|
||||
// Not implemented, only referenced by BridgeDevSupportManager
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggleElementInspector() {
|
||||
ReactContext reactContext = reactHost.getCurrentReactContext();
|
||||
if (reactContext != null) {
|
||||
reactContext
|
||||
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
||||
.emit("toggleElementInspector", null);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Activity getCurrentActivity() {
|
||||
return reactHost.getLastUsedActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptExecutorFactory getJavaScriptExecutorFactory() {
|
||||
throw new IllegalStateException("Not implemented for bridgeless mode");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View createRootView(String appKey) {
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
if (currentActivity != null && !reactHost.isSurfaceWithModuleNameAttached(appKey)) {
|
||||
ReactSurfaceImpl reactSurface =
|
||||
ReactSurfaceImpl.createWithView(currentActivity, appKey, new Bundle());
|
||||
reactSurface.attach(reactHost);
|
||||
reactSurface.start();
|
||||
|
||||
return reactSurface.getView();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyRootView(View rootView) {
|
||||
// Not implemented
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+40
-9
@@ -46,9 +46,10 @@ import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.bridge.queue.ReactQueueConfiguration;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.common.build.ReactBuildConfig;
|
||||
import com.facebook.react.devsupport.DefaultDevSupportManagerFactory;
|
||||
import com.facebook.react.devsupport.DevSupportManagerBase;
|
||||
import com.facebook.react.devsupport.DevSupportManagerFactory;
|
||||
import com.facebook.react.devsupport.InspectorFlags;
|
||||
import com.facebook.react.devsupport.ReleaseDevSupportManager;
|
||||
import com.facebook.react.devsupport.inspector.InspectorNetworkHelper;
|
||||
import com.facebook.react.devsupport.inspector.InspectorNetworkRequestListener;
|
||||
import com.facebook.react.devsupport.interfaces.BundleLoadCallback;
|
||||
@@ -106,7 +107,7 @@ public class ReactHostImpl implements ReactHost {
|
||||
private final Context mContext;
|
||||
private final ReactHostDelegate mReactHostDelegate;
|
||||
private final ComponentFactory mComponentFactory;
|
||||
private final DevSupportManager mDevSupportManager;
|
||||
private DevSupportManager mDevSupportManager;
|
||||
private final Executor mBGExecutor;
|
||||
private final Executor mUIExecutor;
|
||||
private final Set<ReactSurfaceImpl> mAttachedSurfaces = new HashSet<>();
|
||||
@@ -165,6 +166,26 @@ public class ReactHostImpl implements ReactHost {
|
||||
Executor uiExecutor,
|
||||
boolean allowPackagerServerAccess,
|
||||
boolean useDevSupport) {
|
||||
this(
|
||||
context,
|
||||
delegate,
|
||||
componentFactory,
|
||||
bgExecutor,
|
||||
uiExecutor,
|
||||
allowPackagerServerAccess,
|
||||
useDevSupport,
|
||||
null);
|
||||
}
|
||||
|
||||
public ReactHostImpl(
|
||||
Context context,
|
||||
ReactHostDelegate delegate,
|
||||
ComponentFactory componentFactory,
|
||||
Executor bgExecutor,
|
||||
Executor uiExecutor,
|
||||
boolean allowPackagerServerAccess,
|
||||
boolean useDevSupport,
|
||||
@Nullable DevSupportManagerFactory devSupportManagerFactory) {
|
||||
mContext = context;
|
||||
mReactHostDelegate = delegate;
|
||||
mComponentFactory = componentFactory;
|
||||
@@ -173,14 +194,24 @@ public class ReactHostImpl implements ReactHost {
|
||||
mMemoryPressureRouter = new MemoryPressureRouter(context);
|
||||
mAllowPackagerServerAccess = allowPackagerServerAccess;
|
||||
mUseDevSupport = useDevSupport;
|
||||
|
||||
if (mUseDevSupport) {
|
||||
mDevSupportManager =
|
||||
new BridgelessDevSupportManager(
|
||||
ReactHostImpl.this, mContext, mReactHostDelegate.getJsMainModulePath());
|
||||
} else {
|
||||
mDevSupportManager = new ReleaseDevSupportManager();
|
||||
if (devSupportManagerFactory == null) {
|
||||
devSupportManagerFactory = new DefaultDevSupportManagerFactory();
|
||||
}
|
||||
|
||||
mDevSupportManager =
|
||||
devSupportManagerFactory.create(
|
||||
/* applicationContext */ context.getApplicationContext(),
|
||||
/* reactInstanceManagerHelper */ new ReactHostImplDevHelper(ReactHostImpl.this),
|
||||
/* packagerPathForJSBundleName */ mReactHostDelegate.getJsMainModulePath(),
|
||||
/* enableOnCreate */ true,
|
||||
/* redBoxHandler */ null,
|
||||
/* devBundleDownloadListener */ null,
|
||||
/* minNumShakes */ 2,
|
||||
/* customPackagerCommandHandlers */ null,
|
||||
/* surfaceDelegateFactory */ null,
|
||||
/* devLoadingViewManager */ null,
|
||||
/* pausedInDebuggerOverlayManager */ null,
|
||||
mUseDevSupport);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.runtime
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.facebook.react.bridge.JSBundleLoader
|
||||
import com.facebook.react.bridge.JavaJSExecutor
|
||||
import com.facebook.react.bridge.JavaScriptExecutorFactory
|
||||
import com.facebook.react.bridge.ReactContext
|
||||
import com.facebook.react.devsupport.ReactInstanceDevHelper
|
||||
import com.facebook.react.interfaces.TaskInterface
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule
|
||||
|
||||
/**
|
||||
* Implementation of [ReactInstanceDevHelper] for [ReactHostImpl].
|
||||
*
|
||||
* This allows [BridgelessDevSupportHelper] and other classes inside the .devsupport package to
|
||||
* communicate with the Bridgeless infrastructure without exposing public APIs.
|
||||
*/
|
||||
internal class ReactHostImplDevHelper(private val delegate: ReactHostImpl) :
|
||||
ReactInstanceDevHelper {
|
||||
|
||||
override fun onReloadWithJSDebugger(proxyExecutorFactory: JavaJSExecutor.Factory) {
|
||||
// Not implemented, only used by BridgeDevSupportManager to reload with proxy executor
|
||||
}
|
||||
|
||||
override fun onJSBundleLoadedFromServer() {
|
||||
// Not implemented, only referenced by BridgeDevSupportManager
|
||||
}
|
||||
|
||||
override fun toggleElementInspector() {
|
||||
val reactContext = delegate.currentReactContext
|
||||
reactContext
|
||||
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
||||
?.emit("toggleElementInspector", null)
|
||||
}
|
||||
|
||||
override fun getCurrentActivity(): Activity? = delegate.lastUsedActivity
|
||||
|
||||
override fun getJavaScriptExecutorFactory(): JavaScriptExecutorFactory {
|
||||
throw IllegalStateException("Not implemented for bridgeless mode")
|
||||
}
|
||||
|
||||
override fun createRootView(appKey: String): View? {
|
||||
val currentActivity = currentActivity
|
||||
if (currentActivity != null && !delegate.isSurfaceWithModuleNameAttached(appKey)) {
|
||||
val reactSurface = ReactSurfaceImpl.createWithView(currentActivity, appKey, Bundle())
|
||||
reactSurface.attach(delegate)
|
||||
reactSurface.start()
|
||||
|
||||
return reactSurface.view
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun destroyRootView(rootView: View) {
|
||||
// Not implemented, only referenced by BridgeDevSupportManager
|
||||
}
|
||||
|
||||
override fun reload(s: String) {
|
||||
delegate.reload(s)
|
||||
}
|
||||
|
||||
override fun loadBundle(bundleLoader: JSBundleLoader): TaskInterface<Boolean> =
|
||||
delegate.loadBundle(bundleLoader)
|
||||
|
||||
override fun getCurrentReactContext(): ReactContext? = delegate.currentReactContext
|
||||
}
|
||||
+6
-2
@@ -16,6 +16,7 @@ import android.view.ViewGroup;
|
||||
import androidx.annotation.UiThread;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.infer.annotation.ThreadSafe;
|
||||
import com.facebook.react.ReactHost;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.NativeMap;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
@@ -93,9 +94,12 @@ public class ReactSurfaceImpl implements ReactSurface {
|
||||
*
|
||||
* @param host The ReactHost to attach.
|
||||
*/
|
||||
public void attach(ReactHostImpl host) {
|
||||
if (!mReactHost.compareAndSet(null, host)) {
|
||||
public void attach(ReactHost host) {
|
||||
if (host instanceof ReactHostImpl && !mReactHost.compareAndSet(null, (ReactHostImpl) host)) {
|
||||
throw new IllegalStateException("This surface is already attached to a host!");
|
||||
} else if (!(host instanceof ReactHostImpl)) {
|
||||
throw new IllegalArgumentException(
|
||||
"ReactSurfaceImpl.attach can only attach to ReactHostImpl.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-17
@@ -16,7 +16,6 @@ import com.facebook.react.bridge.UIManager
|
||||
import com.facebook.react.common.LifecycleState
|
||||
import com.facebook.react.common.annotations.UnstableReactNativeAPI
|
||||
import com.facebook.react.devsupport.ReleaseDevSupportManager
|
||||
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback
|
||||
import com.facebook.react.fabric.ComponentFactory
|
||||
import com.facebook.react.interfaces.TaskInterface
|
||||
import com.facebook.react.runtime.internal.bolts.TaskCompletionSource
|
||||
@@ -58,7 +57,6 @@ class ReactHostTest {
|
||||
private lateinit var mockedReactInstanceCtor: MockedConstruction<ReactInstance>
|
||||
private lateinit var mockedReactHostInspectorTargetCtor:
|
||||
MockedConstruction<ReactHostInspectorTarget>
|
||||
private lateinit var mockedDevSupportManagerCtor: MockedConstruction<BridgelessDevSupportManager>
|
||||
private lateinit var mockedBridgelessReactContextCtor: MockedConstruction<BridgelessReactContext>
|
||||
private lateinit var mockedMemoryPressureRouterCtor: MockedConstruction<MemoryPressureRouter>
|
||||
private lateinit var mockedTaskCompletionSourceCtor: MockedConstruction<TaskCompletionSource<*>>
|
||||
@@ -77,7 +75,6 @@ class ReactHostTest {
|
||||
mockedReactInstanceCtor = Mockito.mockConstruction(ReactInstance::class.java)
|
||||
mockedReactHostInspectorTargetCtor =
|
||||
Mockito.mockConstruction(ReactHostInspectorTarget::class.java)
|
||||
mockedDevSupportManagerCtor = Mockito.mockConstruction(BridgelessDevSupportManager::class.java)
|
||||
mockedBridgelessReactContextCtor = Mockito.mockConstruction(BridgelessReactContext::class.java)
|
||||
mockedMemoryPressureRouterCtor = Mockito.mockConstruction(MemoryPressureRouter::class.java)
|
||||
|
||||
@@ -95,7 +92,6 @@ class ReactHostTest {
|
||||
fun tearDown() {
|
||||
mockedReactInstanceCtor.close()
|
||||
mockedReactHostInspectorTargetCtor.close()
|
||||
mockedDevSupportManagerCtor.close()
|
||||
mockedBridgelessReactContextCtor.close()
|
||||
mockedMemoryPressureRouterCtor.close()
|
||||
mockedTaskCompletionSourceCtor.close()
|
||||
@@ -114,26 +110,29 @@ class ReactHostTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetDevSupportManager() {
|
||||
fun testGetDevSupportManager_withRelease() {
|
||||
// BridgelessDevSupportManager is created only for debug
|
||||
// we check if it was instantiated or if ReleaseDevSupportManager was created (for release).
|
||||
if (mockedDevSupportManagerCtor.constructed().isNotEmpty()) {
|
||||
val devSupportManager = mockedDevSupportManagerCtor.constructed().first()
|
||||
Assertions.assertThat(reactHost.devSupportManager).isEqualTo(devSupportManager)
|
||||
} else {
|
||||
Assertions.assertThat(reactHost.devSupportManager)
|
||||
.isInstanceOf(ReleaseDevSupportManager::class.java)
|
||||
}
|
||||
Assertions.assertThat(reactHost.devSupportManager)
|
||||
.isInstanceOf(ReleaseDevSupportManager::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetDevSupportManager_withDebug() {
|
||||
reactHost =
|
||||
ReactHostImpl(
|
||||
activityController.get().application,
|
||||
reactHostDelegate,
|
||||
componentFactory,
|
||||
false,
|
||||
true /* useDevSupport */)
|
||||
Assertions.assertThat(reactHost.devSupportManager)
|
||||
.isNotInstanceOf(ReleaseDevSupportManager::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Test is currently failing in OSS and needs to be looked into")
|
||||
fun testStart() {
|
||||
val devSupportManager = mockedDevSupportManagerCtor.constructed().first()
|
||||
|
||||
Mockito.doNothing()
|
||||
.`when`(devSupportManager)
|
||||
.isPackagerRunning(ArgumentMatchers.any(PackagerStatusCallback::class.java))
|
||||
Assertions.assertThat(reactHost.isInstanceInitialized).isFalse()
|
||||
waitForTaskUIThread(reactHost.start())
|
||||
Assertions.assertThat(reactHost.isInstanceInitialized).isTrue()
|
||||
|
||||
Reference in New Issue
Block a user