From 55c151acc935291acd1256daa75123389bc714db Mon Sep 17 00:00:00 2001 From: Alan Lee Date: Thu, 18 Jul 2024 09:06:09 -0700 Subject: [PATCH] provide default implementation for ReactHostDelegate.handleInstanceException() Summary: [ReactHostDelegate.handleInstanceException()](https://github.com/facebook/react-native/blob/a6f5e5adebed3d9da411f99548e2d8ce96636e16/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHostDelegate.kt#L48) is a no-op so providing a default implementation for this. As a simplified solution, just throw a `RuntimeException` (on non-debug bulid) in this case. Below is the justification. 1) We may want to consider using `ExceptionsManagerModule` TurboModule in OSS to report the exception but current implementation just [throws JavaScriptException](https://github.com/facebook/react-native/blob/a6f5e5adebed3d9da411f99548e2d8ce96636e16/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java#L67) when it is fatal 2) If the exception happens during ReactInstance initialization then we may not have Turbo Module initialized and may not be able to access it. While we might want to fix how this works in longer term but for now just throw an Exception and let the app handle it. 3) In debug build, `DevSupportManager` is called before `handleInstanceException()` which would display a RedBox so don't throw when it is a debug build. So it seems to best for now to just throw an exception so it can be handled by the app than silently ignoring it. Changelog: [General][Android] - provide default implementation for ReactHostDelegate.handleInstanceException() Differential Revision: D59847543 --- .../facebook/react/defaults/DefaultReactHostDelegate.kt | 7 ++++++- .../java/com/facebook/react/runtime/ReactHostImpl.java | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHostDelegate.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHostDelegate.kt index 3c50cac823e6f7..98337f96099686 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHostDelegate.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultReactHostDelegate.kt @@ -12,6 +12,7 @@ import com.facebook.react.ReactPackage import com.facebook.react.ReactPackageTurboModuleManagerDelegate import com.facebook.react.bridge.JSBundleLoader import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.common.build.ReactBuildConfig import com.facebook.react.fabric.ReactNativeConfig import com.facebook.react.runtime.BindingsInstaller import com.facebook.react.runtime.JSRuntimeFactory @@ -45,7 +46,11 @@ public class DefaultReactHostDelegate( override val jsRuntimeFactory: JSRuntimeFactory = HermesInstance(), override val bindingsInstaller: BindingsInstaller? = null, private val reactNativeConfig: ReactNativeConfig = ReactNativeConfig.DEFAULT_CONFIG, - private val exceptionHandler: (Exception) -> Unit = {}, + private val exceptionHandler: (Exception) -> Unit = { + if (!ReactBuildConfig.DEBUG) { + throw RuntimeException("Unrecoverable error occurred while running React Native!", it) + } + }, override val turboModuleManagerDelegateBuilder: ReactPackageTurboModuleManagerDelegate.Builder ) : ReactHostDelegate { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java index 06d0fadfc1c5fd..61c9e5d40caf54 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.java @@ -895,7 +895,11 @@ private Task getOrCreateStartTask() { .continueWithTask( (task) -> { if (task.isFaulted()) { - mReactHostDelegate.handleInstanceException(task.getError()); + Exception ex = task.getError(); + if (mUseDevSupport) { + mDevSupportManager.handleException(ex); + } + mReactHostDelegate.handleInstanceException(ex); // Wait for destroy to finish return getOrCreateDestroyTask( "getOrCreateStartTask() failure: " + task.getError().getMessage(),