Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RNMobile] Add error boundry handling for Android #59385

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe Android Studio removed this when it linted the file.

import com.facebook.react.bridge.WritableNativeMap;

import org.wordpress.mobile.WPAndroidGlue.MediaOption;
Expand Down Expand Up @@ -65,6 +64,10 @@ interface ConnectionStatusCallback {
void onRequestConnectionStatus(boolean isConnected);
}

interface LogExceptionCallback {
void onLogException(boolean success);
}

// Ref: https://github.com/facebook/react-native/blob/HEAD/Libraries/polyfills/console.js#L376
enum LogLevel {
TRACE(0),
Expand Down Expand Up @@ -190,4 +193,6 @@ void gutenbergDidRequestUnsupportedBlockFallback(ReplaceUnsupportedBlockCallback
void toggleRedoButton(boolean isDisabled);

void requestConnectionStatus(ConnectionStatusCallback connectionStatusCallback);

void logException(GutenbergJsException exception, LogExceptionCallback jsCallback);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.wordpress.mobile.ReactNativeGutenbergBridge

import com.facebook.react.bridge.ReadableMap

data class GutenbergJsException(
var type: String,
var value: String,
jhnstn marked this conversation as resolved.
Show resolved Hide resolved
var stackTrace: List<GutenbergJsExceptionStackTraceElement>,
var context: Map<String, Any> = emptyMap(),
var tags: Map<String,String> = emptyMap(),
var isHandled: Boolean,
var handledBy: String
){
companion object {
@JvmStatic
fun fromReadableMap(rawException: ReadableMap): GutenbergJsException {
val type: String = rawException.getString("type") ?: ""
val value: String = rawException.getString("value") ?: ""
val stackTrace: List<GutenbergJsExceptionStackTraceElement> = rawException.getArray("stackTrace")?.toArrayList()?.map {
val stackTraceElement = it as ReadableMap
GutenbergJsExceptionStackTraceElement(
stackTraceElement.getString("fileName") ?: "",
jhnstn marked this conversation as resolved.
Show resolved Hide resolved
stackTraceElement.getInt("lineNumber"),
jhnstn marked this conversation as resolved.
Show resolved Hide resolved
stackTraceElement.getString("function") ?: ""
)
} ?: emptyList()
val context: Map<String, Any> = rawException.getMap("context")?.toHashMap() ?: emptyMap()
val tags: Map<String, String> = rawException.getMap("tags")?.toHashMap()?.mapValues { it.value.toString() } ?: emptyMap()
val isHandled: Boolean = rawException.getBoolean("isHandled")
val handledBy: String = rawException.getString("handledBy") ?: ""

return GutenbergJsException(
type,
value,
stackTrace,
context,
tags,
isHandled,
handledBy
)
}
}
}

data class GutenbergJsExceptionStackTraceElement(
var fileName: String,
var lineNumber: Int,
var function: String
)
jhnstn marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.facebook.react.modules.core.DeviceEventManagerModule;

import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.ConnectionStatusCallback;
import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.LogExceptionCallback;
import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.MediaType;
import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.OtherMediaOptionsReceivedCallback;
import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.FocalPointPickerTooltipShownCallback;
Expand Down Expand Up @@ -623,4 +624,20 @@ public void hideAndroidSoftKeyboard() {
}
}
}

@ReactMethod
public void logException(final ReadableMap rawException, final Callback jsCallback) {
GutenbergJsException exception = GutenbergJsException.fromReadableMap(rawException);
LogExceptionCallback logExceptionCallback = onLogExceptionCallback(jsCallback);

mGutenbergBridgeJS2Parent.logException(exception, logExceptionCallback);
}

private LogExceptionCallback onLogExceptionCallback(final Callback jsCallback) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm following the same encapsulation used for other callbacks in the bridge, such as ConnectionStatusCallback.

return new GutenbergBridgeJS2Parent.LogExceptionCallback() {
@Override public void onLogException(boolean success) {
jsCallback.invoke(success);
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@
import org.wordpress.mobile.ReactNativeAztec.ReactAztecPackage;
import org.wordpress.mobile.ReactNativeGutenbergBridge.BuildConfig;
import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent;
import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.LogExceptionCallback;
import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.MediaSelectedCallback;
import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergBridgeJS2Parent.ReplaceUnsupportedBlockCallback;
import org.wordpress.mobile.ReactNativeGutenbergBridge.GutenbergJsException;
import org.wordpress.mobile.ReactNativeGutenbergBridge.RNMedia;
import org.wordpress.mobile.ReactNativeGutenbergBridge.RNReactNativeGutenbergBridgePackage;

Expand Down Expand Up @@ -114,6 +116,8 @@ public class WPAndroidGlueCode {
private OnToggleRedoButtonListener mOnToggleRedoButtonListener;
private OnConnectionStatusEventListener mOnConnectionStatusEventListener;
private OnBackHandlerEventListener mOnBackHandlerEventListener;

private OnDidLogExceptionListener mOnDidLogExceptionListener;
private boolean mIsEditorMounted;

private String mContentHtml = "";
Expand Down Expand Up @@ -225,6 +229,10 @@ public interface OnGutenbergDidRequestEmbedFullscreenPreviewListener {
void gutenbergDidRequestEmbedFullscreenPreview(String html, String title);
}

public interface OnDidLogExceptionListener {
void didLogException(GutenbergJsException exception, LogExceptionCallback onLogExceptionCallback);
}

public interface OnGutenbergDidSendButtonPressedActionListener {
void gutenbergDidSendButtonPressedAction(String buttonType);
}
Expand Down Expand Up @@ -274,6 +282,10 @@ public interface OnBackHandlerEventListener {
void onBackHandler();
}

public interface OnLogExceptionListener {
void onLogException(GutenbergJsException exception);
}

public void mediaSelectionCancelled() {
mAppendsMultipleSelectedToSiblingBlocks = false;
}
Expand Down Expand Up @@ -615,6 +627,12 @@ public void requestConnectionStatus(ConnectionStatusCallback connectionStatusCal
boolean isConnected = mOnConnectionStatusEventListener.onRequestConnectionStatus();
connectionStatusCallback.onRequestConnectionStatus(isConnected);
}

@Override
public void logException(GutenbergJsException exception, LogExceptionCallback logExceptionCallback) {
mOnDidLogExceptionListener.didLogException(exception, logExceptionCallback);
logExceptionCallback.onLogException(true);
}
}, mIsDarkMode);

return Arrays.asList(
Expand Down Expand Up @@ -715,6 +733,7 @@ public void attachToContainer(ViewGroup viewGroup,
OnToggleRedoButtonListener onToggleRedoButtonListener,
OnConnectionStatusEventListener onConnectionStatusEventListener,
OnBackHandlerEventListener onBackHandlerEventListener,
OnDidLogExceptionListener onDidLogExceptionListener,
boolean isDarkMode) {
MutableContextWrapper contextWrapper = (MutableContextWrapper) mReactRootView.getContext();
contextWrapper.setBaseContext(viewGroup.getContext());
Expand Down Expand Up @@ -742,6 +761,7 @@ public void attachToContainer(ViewGroup viewGroup,
mOnToggleRedoButtonListener = onToggleRedoButtonListener;
mOnConnectionStatusEventListener = onConnectionStatusEventListener;
mOnBackHandlerEventListener = onBackHandlerEventListener;
mOnDidLogExceptionListener = onDidLogExceptionListener;

sAddCookiesInterceptor.setOnAuthHeaderRequestedListener(onAuthHeaderRequestedListener);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,12 @@ public void toggleRedoButton(boolean isDisabled) {
public void requestConnectionStatus(ConnectionStatusCallback connectionStatusCallback) {
connectionStatusCallback.onRequestConnectionStatus(true);
}

@Override
public void logException(final ReadableMap exception, LogExceptionCallback logExceptionCallback) {
Log.d("LogException", String.format("Gutenberg requested logging exception: %s", exception));
logExceptionCallback.onLogException();
}
}, isDarkMode());

return new DefaultReactNativeHost(this) {
Expand Down
Loading