Skip to content

Commit

Permalink
Avoid crash by handling missing views in dispatchViewManagerCommand
Browse files Browse the repository at this point in the history
  • Loading branch information
hsource committed May 10, 2022
1 parent 2a274c1 commit 9c16573
Showing 1 changed file with 42 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
import com.facebook.react.uimanager.events.EventDispatcher;
Expand Down Expand Up @@ -742,13 +743,21 @@ public void clearJSResponder() {
@Deprecated
public void dispatchViewManagerCommand(
int reactTag, int commandId, @Nullable ReadableArray commandArgs) {
assertViewExists(reactTag, "dispatchViewManagerCommand: " + commandId);
boolean viewExists = checkOrAssertViewExists(reactTag, "dispatchViewManagerCommand: " + commandId);
if (!viewExists) {
return;
}

mOperationsQueue.enqueueDispatchCommand(reactTag, commandId, commandArgs);
}

public void dispatchViewManagerCommand(
int reactTag, String commandId, @Nullable ReadableArray commandArgs) {
assertViewExists(reactTag, "dispatchViewManagerCommand: " + commandId);
boolean viewExists = checkOrAssertViewExists(reactTag, "dispatchViewManagerCommand: " + commandId);
if (!viewExists) {
return;
}

mOperationsQueue.enqueueDispatchCommand(reactTag, commandId, commandArgs);
}

Expand All @@ -763,7 +772,11 @@ public void dispatchViewManagerCommand(
* no arguments if the menu is dismissed
*/
public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) {
assertViewExists(reactTag, "showPopupMenu");
boolean viewExists = checkOrAssertViewExists(reactTag, "showPopupMenu");
if (!viewExists) {
return;
}

mOperationsQueue.enqueueShowPopupMenu(reactTag, items, error, success);
}

Expand Down Expand Up @@ -867,15 +880,32 @@ private void measureLayoutRelativeToVerifiedAncestor(
outputBuffer[3] = node.getScreenHeight();
}

private void assertViewExists(int reactTag, String operationNameForExceptionMessage) {
if (mShadowNodeRegistry.getNode(reactTag) == null) {
throw new IllegalViewOperationException(
"Unable to execute operation "
+ operationNameForExceptionMessage
+ " on view with "
+ "tag: "
+ reactTag
+ ", since the view does not exists");
/**
* Returns whether a view identified by the tag exists. In debug mode, this
* will throw whenever the view doesn't exist. In production, it'll log a
* warning. Callers should use this and just return if the view doesn't exist
* to avoid crashing.
*/
private boolean checkOrAssertViewExists(int reactTag, String operationNameForExceptionMessage) {
boolean viewExists = mShadowNodeRegistry.getNode(reactTag) != null;
if (viewExists) {
return true;
}

String message = "Unable to execute operation "
+ operationNameForExceptionMessage
+ " on view with "
+ "tag: "
+ reactTag
+ ", since the view does not exists";

if (ReactBuildConfig.DEBUG) {
throw new IllegalViewOperationException(message);
} else {
if (!viewExists) {
FLog.w(ReactConstants.TAG, message);
}
return false;
}
}

Expand Down

0 comments on commit 9c16573

Please sign in to comment.