From 606fafacf8eccd9e706dc8884dfc4634c36c2fd6 Mon Sep 17 00:00:00 2001 From: Gregory Moskaliuk Date: Sat, 24 Oct 2026 21:06:06 +0200 Subject: [PATCH] Look up Android image resources without throwing an exception ResourceDrawableIdHelper.getResourceDrawableId first tried to parse the resource name as a number with toInt() and caught the NumberFormatException. Bundled images in Release builds are drawable resources whose names are not numbers, so every such image source threw an exception and filled in its stack trace. Use toIntOrNull() instead, which parses the same way without throwing. Co-Authored-By: Claude Opus 5.5 --- .../imagehelper/ResourceDrawableIdHelper.kt | 9 +-- .../ResourceDrawableIdHelperTest.kt | 75 +++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/imagehelper/ResourceDrawableIdHelperTest.kt diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ResourceDrawableIdHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ResourceDrawableIdHelper.kt index 4881d233306a..1cb91f513f6a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ResourceDrawableIdHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/imagehelper/ResourceDrawableIdHelper.kt @@ -31,11 +31,10 @@ public object ResourceDrawableIdHelper { } val normalizedName = name.lowercase().replace("-", "_") - // name could be a resource id. - try { - return normalizedName.toInt() - } catch (e: NumberFormatException) { - // Do nothing. + // name could be a resource id. Most names are not numbers, so this must not throw: an + // exception would build a stack trace for every image source. + normalizedName.toIntOrNull()?.let { + return it } synchronized(this) { diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/imagehelper/ResourceDrawableIdHelperTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/imagehelper/ResourceDrawableIdHelperTest.kt new file mode 100644 index 000000000000..1c301ae1a4c6 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/imagehelper/ResourceDrawableIdHelperTest.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) Meta Platforms, Inc. and 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.views.imagehelper + +import android.content.Context +import org.assertj.core.api.Assertions.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment + +@RunWith(RobolectricTestRunner::class) +class ResourceDrawableIdHelperTest { + + private lateinit var context: Context + + @Before + fun setUp() { + context = RuntimeEnvironment.getApplication() + ResourceDrawableIdHelper.clear() + } + + @After + fun tearDown() { + ResourceDrawableIdHelper.clear() + } + + @Test + fun returnsZeroForMissingName() { + assertThat(ResourceDrawableIdHelper.getResourceDrawableId(context, null)).isEqualTo(0) + assertThat(ResourceDrawableIdHelper.getResourceDrawableId(context, "")).isEqualTo(0) + } + + @Test + fun returnsNumericNameAsId() { + assertThat(ResourceDrawableIdHelper.getResourceDrawableId(context, "123")).isEqualTo(123) + assertThat(ResourceDrawableIdHelper.getResourceDrawableId(context, "+42")).isEqualTo(42) + } + + @Test + fun looksUpNonNumericNameAsDrawable() { + val expected = + context.resources.getIdentifier( + "redbox_top_border_background", + "drawable", + context.packageName, + ) + assertThat(expected).isGreaterThan(0) + assertThat( + ResourceDrawableIdHelper.getResourceDrawableId( + context, + "Redbox-Top-Border-Background", + ) + ) + .isEqualTo(expected) + } + + @Test + fun looksUpNumberThatDoesNotFitInAnIntAsDrawable() { + assertThat(ResourceDrawableIdHelper.getResourceDrawableId(context, "99999999999")).isEqualTo(0) + } + + @Test + fun returnsZeroForUnknownDrawable() { + assertThat(ResourceDrawableIdHelper.getResourceDrawableId(context, "unknown_image")) + .isEqualTo(0) + } +}