mirror of
https://github.com/status-im/react-native.git
synced 2025-01-15 20:15:11 +00:00
Intercepting all redboxes in Android Ads Manager
Summary: Implement a handler to allow intercepting all RN redboxes in Android, including exceptions in both JS and Java. The handler is not open sourced, so there is only an open-source interface called **RedBoxHandler** in //fbandroid/java/com/facebook/catalyst/js/react-native-github/ReactAndroid/src/main/java/com/facebook/react/devsupport//, meantime there is an internal class called **FBRedBoxHandler**, which implements **RedBoxHandler** and is located in //fbandroid/java/com/facebook/fbreact/redboxhandler//, actually handles the exception information. The code structure is as follows: - **AdsManagerActivity** has a member variable of **FBRedBoxHandler**. - **AdsManagerActivity** passes this handler all the way down to the **DevSupportManagerImpl**, through** ReactInstanceManager**, **ReactInstanceManagerImpl**, **DevSupportManagerFactory**. - **DevSupportManagerImpl** intercepts the exceptions just before showing the redboxes, like this: mRedBoxDialog.setExceptionDetails(message, stack); mRedBoxDialog.setErrorCookie(errorCookie); if (mRedBoxHandler != null) { mRedBoxHandler.handleRedbox(message, stack); } mRedBoxDialog.show(); By now, the internal class just prints information for each redbox to logcat, including exception message and stack trace. Reviewed By: mkonicek Differential Revision: D3369064 fbshipit-source-id: 199012c4b6ecf4b3d3aff51a26c9c9901847b6fc
This commit is contained in:
parent
5961764668
commit
5aa0e098b4
@ -25,6 +25,7 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
import com.facebook.react.devsupport.DevSupportManager;
|
||||
import com.facebook.react.devsupport.RedBoxHandler;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
import com.facebook.react.uimanager.UIImplementationProvider;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
@ -188,6 +189,7 @@ public abstract class ReactInstanceManager {
|
||||
protected @Nullable JSCConfig mJSCConfig;
|
||||
protected @Nullable Activity mCurrentActivity;
|
||||
protected @Nullable DefaultHardwareBackBtnHandler mDefaultHardwareBackBtnHandler;
|
||||
protected @Nullable RedBoxHandler mRedBoxHandler;
|
||||
|
||||
protected Builder() {
|
||||
}
|
||||
@ -297,6 +299,11 @@ public abstract class ReactInstanceManager {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRedBoxHandler(RedBoxHandler redBoxHandler) {
|
||||
mRedBoxHandler = redBoxHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new {@link ReactInstanceManagerImpl}.
|
||||
* Before calling {@code build}, the following must be called:
|
||||
@ -335,7 +342,8 @@ public abstract class ReactInstanceManager {
|
||||
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
|
||||
mUIImplementationProvider,
|
||||
mNativeModuleCallExceptionHandler,
|
||||
mJSCConfig);
|
||||
mJSCConfig,
|
||||
mRedBoxHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ import com.facebook.react.devsupport.DevServerHelper;
|
||||
import com.facebook.react.devsupport.DevSupportManager;
|
||||
import com.facebook.react.devsupport.DevSupportManagerFactory;
|
||||
import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
|
||||
import com.facebook.react.devsupport.RedBoxHandler;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.uimanager.AppRegistry;
|
||||
@ -122,6 +123,7 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START
|
||||
private final MemoryPressureRouter mMemoryPressureRouter;
|
||||
private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||
private final @Nullable JSCConfig mJSCConfig;
|
||||
private @Nullable RedBoxHandler mRedBoxHandler;
|
||||
|
||||
private final ReactInstanceDevCommandsHandler mDevInterface =
|
||||
new ReactInstanceDevCommandsHandler() {
|
||||
@ -262,6 +264,35 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ ReactInstanceManagerImpl(
|
||||
Context applicationContext,
|
||||
@Nullable Activity currentActivity,
|
||||
@Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler,
|
||||
@Nullable String jsBundleFile,
|
||||
@Nullable String jsMainModuleName,
|
||||
List<ReactPackage> packages,
|
||||
boolean useDeveloperSupport,
|
||||
@Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
|
||||
LifecycleState initialLifecycleState,
|
||||
UIImplementationProvider uiImplementationProvider,
|
||||
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler,
|
||||
@Nullable JSCConfig jscConfig) {
|
||||
|
||||
this(applicationContext,
|
||||
currentActivity,
|
||||
defaultHardwareBackBtnHandler,
|
||||
jsBundleFile,
|
||||
jsMainModuleName,
|
||||
packages,
|
||||
useDeveloperSupport,
|
||||
bridgeIdleDebugListener,
|
||||
initialLifecycleState,
|
||||
uiImplementationProvider,
|
||||
nativeModuleCallExceptionHandler,
|
||||
jscConfig,
|
||||
null);
|
||||
}
|
||||
|
||||
/* package */ ReactInstanceManagerImpl(
|
||||
Context applicationContext,
|
||||
@Nullable Activity currentActivity,
|
||||
@ -274,7 +305,8 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START
|
||||
LifecycleState initialLifecycleState,
|
||||
UIImplementationProvider uiImplementationProvider,
|
||||
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler,
|
||||
@Nullable JSCConfig jscConfig) {
|
||||
@Nullable JSCConfig jscConfig,
|
||||
@Nullable RedBoxHandler redBoxHandler) {
|
||||
initializeSoLoaderIfNecessary(applicationContext);
|
||||
|
||||
// TODO(9577825): remove this
|
||||
@ -288,11 +320,13 @@ import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START
|
||||
mJSMainModuleName = jsMainModuleName;
|
||||
mPackages = packages;
|
||||
mUseDeveloperSupport = useDeveloperSupport;
|
||||
mRedBoxHandler = redBoxHandler;
|
||||
mDevSupportManager = DevSupportManagerFactory.create(
|
||||
applicationContext,
|
||||
mDevInterface,
|
||||
mJSMainModuleName,
|
||||
useDeveloperSupport);
|
||||
useDeveloperSupport,
|
||||
mRedBoxHandler);
|
||||
mBridgeIdleDebugListener = bridgeIdleDebugListener;
|
||||
mLifecycleState = initialLifecycleState;
|
||||
mUIImplementationProvider = uiImplementationProvider;
|
||||
|
@ -62,7 +62,8 @@ public abstract class XReactInstanceManager {
|
||||
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
|
||||
mUIImplementationProvider,
|
||||
mNativeModuleCallExceptionHandler,
|
||||
mJSCConfig);
|
||||
mJSCConfig,
|
||||
mRedBoxHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
import com.facebook.systrace.Systrace;
|
||||
import com.facebook.react.devsupport.RedBoxHandler;
|
||||
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_JS_MODULE_CONFIG_END;
|
||||
import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_JS_MODULE_CONFIG_START;
|
||||
@ -125,6 +126,7 @@ import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
|
||||
private final MemoryPressureRouter mMemoryPressureRouter;
|
||||
private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
|
||||
private final @Nullable JSCConfig mJSCConfig;
|
||||
private @Nullable RedBoxHandler mRedBoxHandler;
|
||||
|
||||
private final ReactInstanceDevCommandsHandler mDevInterface =
|
||||
new ReactInstanceDevCommandsHandler() {
|
||||
@ -276,6 +278,37 @@ import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
|
||||
UIImplementationProvider uiImplementationProvider,
|
||||
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler,
|
||||
@Nullable JSCConfig jscConfig) {
|
||||
|
||||
this(applicationContext,
|
||||
currentActivity,
|
||||
defaultHardwareBackBtnHandler,
|
||||
jsBundleFile,
|
||||
jsMainModuleName,
|
||||
packages,
|
||||
useDeveloperSupport,
|
||||
bridgeIdleDebugListener,
|
||||
initialLifecycleState,
|
||||
uiImplementationProvider,
|
||||
nativeModuleCallExceptionHandler,
|
||||
jscConfig,
|
||||
null);
|
||||
}
|
||||
|
||||
/* package */ XReactInstanceManagerImpl(
|
||||
Context applicationContext,
|
||||
@Nullable Activity currentActivity,
|
||||
@Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler,
|
||||
@Nullable String jsBundleFile,
|
||||
@Nullable String jsMainModuleName,
|
||||
List<ReactPackage> packages,
|
||||
boolean useDeveloperSupport,
|
||||
@Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
|
||||
LifecycleState initialLifecycleState,
|
||||
UIImplementationProvider uiImplementationProvider,
|
||||
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler,
|
||||
@Nullable JSCConfig jscConfig,
|
||||
@Nullable RedBoxHandler redBoxHandler) {
|
||||
|
||||
initializeSoLoaderIfNecessary(applicationContext);
|
||||
|
||||
// TODO(9577825): remove this
|
||||
@ -289,11 +322,13 @@ import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
|
||||
mJSMainModuleName = jsMainModuleName;
|
||||
mPackages = packages;
|
||||
mUseDeveloperSupport = useDeveloperSupport;
|
||||
mRedBoxHandler = redBoxHandler;
|
||||
mDevSupportManager = DevSupportManagerFactory.create(
|
||||
applicationContext,
|
||||
mDevInterface,
|
||||
mJSMainModuleName,
|
||||
useDeveloperSupport);
|
||||
useDeveloperSupport,
|
||||
mRedBoxHandler);
|
||||
mBridgeIdleDebugListener = bridgeIdleDebugListener;
|
||||
mLifecycleState = initialLifecycleState;
|
||||
mUIImplementationProvider = uiImplementationProvider;
|
||||
|
@ -1,3 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -5,10 +14,6 @@ import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.build.ReactBuildConfig;
|
||||
|
||||
/**
|
||||
* A simple factory that creates instances of {@link DevSupportManager} implementations. Uses
|
||||
@ -26,6 +31,21 @@ public class DevSupportManagerFactory {
|
||||
ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate) {
|
||||
|
||||
return create(
|
||||
applicationContext,
|
||||
reactInstanceCommandsHandler,
|
||||
packagerPathForJSBundleName,
|
||||
enableOnCreate,
|
||||
null);
|
||||
}
|
||||
|
||||
public static DevSupportManager create(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
@Nullable RedBoxHandler redBoxHandler) {
|
||||
if (!enableOnCreate) {
|
||||
return new DisabledDevSupportManager();
|
||||
}
|
||||
@ -34,28 +54,30 @@ public class DevSupportManagerFactory {
|
||||
// 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();
|
||||
new StringBuilder(DEVSUPPORT_IMPL_PACKAGE)
|
||||
.append(".")
|
||||
.append(DEVSUPPORT_IMPL_CLASS)
|
||||
.toString();
|
||||
Class<?> devSupportManagerClass =
|
||||
Class.forName(className);
|
||||
Class.forName(className);
|
||||
Constructor constructor =
|
||||
devSupportManagerClass.getConstructor(
|
||||
Context.class,
|
||||
ReactInstanceDevCommandsHandler.class,
|
||||
String.class,
|
||||
boolean.class);
|
||||
devSupportManagerClass.getConstructor(
|
||||
Context.class,
|
||||
ReactInstanceDevCommandsHandler.class,
|
||||
String.class,
|
||||
boolean.class,
|
||||
RedBoxHandler.class);
|
||||
return (DevSupportManager) constructor.newInstance(
|
||||
applicationContext,
|
||||
reactInstanceCommandsHandler,
|
||||
packagerPathForJSBundleName,
|
||||
true);
|
||||
applicationContext,
|
||||
reactInstanceCommandsHandler,
|
||||
packagerPathForJSBundleName,
|
||||
true,
|
||||
redBoxHandler);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"Requested enabled DevSupportManager, but DevSupportManagerImpl class was not found" +
|
||||
" or could not be created",
|
||||
e);
|
||||
"Requested enabled DevSupportManager, but DevSupportManagerImpl class was not found" +
|
||||
" or could not be created",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,12 +111,13 @@ public class DevSupportManagerImpl implements DevSupportManager {
|
||||
private boolean mIsDevSupportEnabled = false;
|
||||
private boolean mIsCurrentlyProfiling = false;
|
||||
private int mProfileIndex = 0;
|
||||
private @Nullable RedBoxHandler mRedBoxHandler;
|
||||
|
||||
public DevSupportManagerImpl(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate) {
|
||||
Context applicationContext,
|
||||
ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate) {
|
||||
mReactInstanceCommandsHandler = reactInstanceCommandsHandler;
|
||||
mApplicationContext = applicationContext;
|
||||
mJSAppBundleName = packagerPathForJSBundleName;
|
||||
@ -160,6 +161,21 @@ public class DevSupportManagerImpl implements DevSupportManager {
|
||||
setDevSupportEnabled(enableOnCreate);
|
||||
}
|
||||
|
||||
public DevSupportManagerImpl(
|
||||
Context applicationContext,
|
||||
ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
|
||||
@Nullable String packagerPathForJSBundleName,
|
||||
boolean enableOnCreate,
|
||||
@Nullable RedBoxHandler redBoxHandler) {
|
||||
|
||||
this(applicationContext,
|
||||
reactInstanceCommandsHandler,
|
||||
packagerPathForJSBundleName,
|
||||
enableOnCreate);
|
||||
|
||||
mRedBoxHandler = redBoxHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(Exception e) {
|
||||
if (mIsDevSupportEnabled) {
|
||||
@ -209,9 +225,12 @@ public class DevSupportManagerImpl implements DevSupportManager {
|
||||
errorCookie != mRedBoxDialog.getErrorCookie()) {
|
||||
return;
|
||||
}
|
||||
mRedBoxDialog.setExceptionDetails(
|
||||
message,
|
||||
StackTraceHelper.convertJsStackTrace(details));
|
||||
StackFrame[] stack = StackTraceHelper.convertJsStackTrace(details);
|
||||
mRedBoxDialog.setExceptionDetails(message, stack);
|
||||
mRedBoxDialog.setErrorCookie(errorCookie);
|
||||
if (mRedBoxHandler != null) {
|
||||
mRedBoxHandler.handleRedbox(message, stack);
|
||||
}
|
||||
mRedBoxDialog.show();
|
||||
}
|
||||
});
|
||||
@ -244,6 +263,9 @@ public class DevSupportManagerImpl implements DevSupportManager {
|
||||
}
|
||||
mRedBoxDialog.setExceptionDetails(message, stack);
|
||||
mRedBoxDialog.setErrorCookie(errorCookie);
|
||||
if (mRedBoxHandler != null) {
|
||||
mRedBoxHandler.handleRedbox(message, stack);
|
||||
}
|
||||
mRedBoxDialog.show();
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
|
||||
|
||||
/**
|
||||
* Interface used by {@link DevSupportManagerImpl} to allow interception on any redboxes
|
||||
* during development and handling the information from the redbox.
|
||||
* The implementation should be passed by {@link #setRedBoxHandler} in {@link ReactInstanceManager}.
|
||||
*/
|
||||
public interface RedBoxHandler {
|
||||
void handleRedbox(String title, StackFrame[] stack);
|
||||
}
|
@ -17,7 +17,7 @@ import com.facebook.react.bridge.ReadableMap;
|
||||
/**
|
||||
* Helper class converting JS and Java stack traces into arrays of {@link StackFrame} objects.
|
||||
*/
|
||||
/* package */ class StackTraceHelper {
|
||||
public class StackTraceHelper {
|
||||
|
||||
/**
|
||||
* Represents a generic entry in a stack trace, be it originally from JS or Java.
|
||||
|
Loading…
x
Reference in New Issue
Block a user