mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Support custom DevSupportManager (#31841)
Summary: to open possibilities for some DX enhancement, the pr introduces `DevSupportManagerFactory` customization. applications could implement a different DevSupportManager in ReactNativeHost. ## Changelog [Internal] [Added] - Support custom DevSupportManager Pull Request resolved: https://github.com/facebook/react-native/pull/31841 Test Plan: this pr just introduces some new interfaces and should not break existing functionalities. Reviewed By: RSNara Differential Revision: D30878134 Pulled By: yungsters fbshipit-source-id: ccdf798caa322b07a876da8312b97002da057388
This commit is contained in:
committed by
Facebook GitHub Bot
parent
88021894f2
commit
369b28ce01
@@ -219,6 +219,7 @@ public class ReactInstanceManager {
|
||||
@Nullable String jsMainModulePath,
|
||||
List<ReactPackage> packages,
|
||||
boolean useDeveloperSupport,
|
||||
DevSupportManagerFactory devSupportManagerFactory,
|
||||
boolean requireActivity,
|
||||
@Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
|
||||
LifecycleState initialLifecycleState,
|
||||
@@ -250,7 +251,7 @@ public class ReactInstanceManager {
|
||||
Systrace.beginSection(
|
||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.initDevSupportManager");
|
||||
mDevSupportManager =
|
||||
DevSupportManagerFactory.create(
|
||||
devSupportManagerFactory.create(
|
||||
applicationContext,
|
||||
createDevHelperInterface(),
|
||||
mJSMainModulePath,
|
||||
@@ -1225,7 +1226,8 @@ public class ReactInstanceManager {
|
||||
// If we can't get a UIManager something has probably gone horribly wrong
|
||||
if (uiManager == null) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to attach a rootView to ReactInstance when UIManager is not properly initialized.");
|
||||
"Unable to attach a rootView to ReactInstance when UIManager is not properly"
|
||||
+ " initialized.");
|
||||
}
|
||||
|
||||
@Nullable Bundle initialProperties = reactRoot.getAppProperties();
|
||||
|
||||
@@ -22,6 +22,8 @@ import com.facebook.react.bridge.JavaScriptExecutorFactory;
|
||||
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
|
||||
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.devsupport.DefaultDevSupportManagerFactory;
|
||||
import com.facebook.react.devsupport.DevSupportManagerFactory;
|
||||
import com.facebook.react.devsupport.RedBoxHandler;
|
||||
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
@@ -45,6 +47,7 @@ public class ReactInstanceManagerBuilder {
|
||||
private @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
|
||||
private @Nullable Application mApplication;
|
||||
private boolean mUseDeveloperSupport;
|
||||
private @Nullable DevSupportManagerFactory mDevSupportManagerFactory;
|
||||
private boolean mRequireActivity;
|
||||
private @Nullable LifecycleState mInitialLifecycleState;
|
||||
private @Nullable UIImplementationProvider mUIImplementationProvider;
|
||||
@@ -172,6 +175,16 @@ public class ReactInstanceManagerBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the custom {@link DevSupportManagerFactory}. If not set, will use {@link
|
||||
* DefaultDevSupportManagerFactory}.
|
||||
*/
|
||||
public ReactInstanceManagerBuilder setDevSupportManagerFactory(
|
||||
final DevSupportManagerFactory devSupportManagerFactory) {
|
||||
mDevSupportManagerFactory = devSupportManagerFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* When {@code false}, indicates that correct usage of React Native will NOT involve an Activity.
|
||||
* For the vast majority of Android apps in the ecosystem, this will not need to change. Unless
|
||||
@@ -294,6 +307,9 @@ public class ReactInstanceManagerBuilder {
|
||||
mJSMainModulePath,
|
||||
mPackages,
|
||||
mUseDeveloperSupport,
|
||||
mDevSupportManagerFactory == null
|
||||
? new DefaultDevSupportManagerFactory()
|
||||
: mDevSupportManagerFactory,
|
||||
mRequireActivity,
|
||||
mBridgeIdleDebugListener,
|
||||
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.facebook.react.bridge.JavaScriptExecutorFactory;
|
||||
import com.facebook.react.bridge.ReactMarker;
|
||||
import com.facebook.react.bridge.ReactMarkerConstants;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.devsupport.DevSupportManagerFactory;
|
||||
import com.facebook.react.devsupport.RedBoxHandler;
|
||||
import com.facebook.react.uimanager.UIImplementationProvider;
|
||||
import java.util.List;
|
||||
@@ -68,6 +69,7 @@ public abstract class ReactNativeHost {
|
||||
.setApplication(mApplication)
|
||||
.setJSMainModulePath(getJSMainModuleName())
|
||||
.setUseDeveloperSupport(getUseDeveloperSupport())
|
||||
.setDevSupportManagerFactory(getDevSupportManagerFactory())
|
||||
.setRequireActivity(getShouldRequireActivity())
|
||||
.setRedBoxHandler(getRedBoxHandler())
|
||||
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
|
||||
@@ -160,6 +162,11 @@ public abstract class ReactNativeHost {
|
||||
/** Returns whether dev mode should be enabled. This enables e.g. the dev menu. */
|
||||
public abstract boolean getUseDeveloperSupport();
|
||||
|
||||
/** Get the {@link DevSupportManagerFactory}. Override this to use a custom dev support manager */
|
||||
protected @Nullable DevSupportManagerFactory getDevSupportManagerFactory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of {@link ReactPackage} used by the app. You'll most likely want to return at
|
||||
* least the {@code MainReactPackage}. If your app uses additional views or modules besides the
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.packagerconnection.RequestHandler;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A simple factory that creates instances of {@link 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, {@link
|
||||
* DisabledDevSupportManager} is returned instead.
|
||||
*/
|
||||
public class DefaultDevSupportManagerFactory implements DevSupportManagerFactory {
|
||||
|
||||
private static final String DEVSUPPORT_IMPL_PACKAGE = "com.facebook.react.devsupport";
|
||||
private static final String DEVSUPPORT_IMPL_CLASS = "BridgeDevSupportManager";
|
||||
|
||||
public DevSupportManager create(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevHelper reactInstanceDevHelper,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
int minNumShakes) {
|
||||
|
||||
return create(
|
||||
applicationContext,
|
||||
reactInstanceDevHelper,
|
||||
packagerPathForJSBundleName,
|
||||
enableOnCreate,
|
||||
null,
|
||||
null,
|
||||
minNumShakes,
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevSupportManager create(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevHelper reactInstanceManagerHelper,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
@Nullable RedBoxHandler redBoxHandler,
|
||||
@Nullable DevBundleDownloadListener devBundleDownloadListener,
|
||||
int minNumShakes,
|
||||
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers) {
|
||||
if (!enableOnCreate) {
|
||||
return new DisabledDevSupportManager();
|
||||
}
|
||||
try {
|
||||
// ProGuard is surprisingly smart in this case and will keep a class if it detects a call to
|
||||
// Class.forName() with a static string. So instead we generate a quasi-dynamic string to
|
||||
// confuse it.
|
||||
String className =
|
||||
new StringBuilder(DEVSUPPORT_IMPL_PACKAGE)
|
||||
.append(".")
|
||||
.append(DEVSUPPORT_IMPL_CLASS)
|
||||
.toString();
|
||||
Class<?> devSupportManagerClass = Class.forName(className);
|
||||
Constructor constructor =
|
||||
devSupportManagerClass.getConstructor(
|
||||
Context.class,
|
||||
ReactInstanceDevHelper.class,
|
||||
String.class,
|
||||
boolean.class,
|
||||
RedBoxHandler.class,
|
||||
DevBundleDownloadListener.class,
|
||||
int.class,
|
||||
Map.class);
|
||||
return (DevSupportManager)
|
||||
constructor.newInstance(
|
||||
applicationContext,
|
||||
reactInstanceManagerHelper,
|
||||
packagerPathForJSBundleName,
|
||||
true,
|
||||
redBoxHandler,
|
||||
devBundleDownloadListener,
|
||||
minNumShakes,
|
||||
customPackagerCommandHandlers);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"Requested enabled DevSupportManager, but BridgeDevSupportManager class was not found"
|
||||
+ " or could not be created",
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-72
@@ -12,39 +12,10 @@ import androidx.annotation.Nullable;
|
||||
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.packagerconnection.RequestHandler;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A simple factory that creates instances of {@link 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, {@link
|
||||
* DisabledDevSupportManager} is returned instead.
|
||||
*/
|
||||
public class DevSupportManagerFactory {
|
||||
|
||||
private static final String DEVSUPPORT_IMPL_PACKAGE = "com.facebook.react.devsupport";
|
||||
private static final String DEVSUPPORT_IMPL_CLASS = "BridgeDevSupportManager";
|
||||
|
||||
public static DevSupportManager create(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevHelper reactInstanceDevHelper,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
int minNumShakes) {
|
||||
|
||||
return create(
|
||||
applicationContext,
|
||||
reactInstanceDevHelper,
|
||||
packagerPathForJSBundleName,
|
||||
enableOnCreate,
|
||||
null,
|
||||
null,
|
||||
minNumShakes,
|
||||
null);
|
||||
}
|
||||
|
||||
public static DevSupportManager create(
|
||||
public interface DevSupportManagerFactory {
|
||||
DevSupportManager create(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevHelper reactInstanceManagerHelper,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
@@ -52,45 +23,5 @@ public class DevSupportManagerFactory {
|
||||
@Nullable RedBoxHandler redBoxHandler,
|
||||
@Nullable DevBundleDownloadListener devBundleDownloadListener,
|
||||
int minNumShakes,
|
||||
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers) {
|
||||
if (!enableOnCreate) {
|
||||
return new DisabledDevSupportManager();
|
||||
}
|
||||
try {
|
||||
// ProGuard is surprisingly smart in this case and will keep a class if it detects a call to
|
||||
// Class.forName() with a static string. So instead we generate a quasi-dynamic string to
|
||||
// confuse it.
|
||||
String className =
|
||||
new StringBuilder(DEVSUPPORT_IMPL_PACKAGE)
|
||||
.append(".")
|
||||
.append(DEVSUPPORT_IMPL_CLASS)
|
||||
.toString();
|
||||
Class<?> devSupportManagerClass = Class.forName(className);
|
||||
Constructor constructor =
|
||||
devSupportManagerClass.getConstructor(
|
||||
Context.class,
|
||||
ReactInstanceDevHelper.class,
|
||||
String.class,
|
||||
boolean.class,
|
||||
RedBoxHandler.class,
|
||||
DevBundleDownloadListener.class,
|
||||
int.class,
|
||||
Map.class);
|
||||
return (DevSupportManager)
|
||||
constructor.newInstance(
|
||||
applicationContext,
|
||||
reactInstanceManagerHelper,
|
||||
packagerPathForJSBundleName,
|
||||
true,
|
||||
redBoxHandler,
|
||||
devBundleDownloadListener,
|
||||
minNumShakes,
|
||||
customPackagerCommandHandlers);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"Requested enabled DevSupportManager, but BridgeDevSupportManager class was not found"
|
||||
+ " or could not be created",
|
||||
e);
|
||||
}
|
||||
}
|
||||
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user