From a086da4177d9890389ce07044185200257214616 Mon Sep 17 00:00:00 2001 From: Adam Kapos Date: Wed, 28 Oct 2026 10:34:44 +0200 Subject: [PATCH] Fix Linking.openSettings() rejecting on Android when there is no current activity openSettings wrapped getCurrentActivity() in checkNotNull, so it rejected with "Could not open the Settings: Required value was null" whenever the React context had no activity. The intent already carries FLAG_ACTIVITY_NEW_TASK, so start it from the application context then, as sendOSIntent does. --- .../react/modules/intent/IntentModule.kt | 9 ++++++--- .../react/modules/intent/IntentModuleTest.kt | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.kt index d3338be3ddc6..d3881a6e770c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.kt @@ -7,7 +7,6 @@ package com.facebook.react.modules.intent -import android.app.Activity import android.content.Intent import android.net.Uri import android.nfc.NfcAdapter @@ -169,7 +168,7 @@ public open class IntentModule(reactContext: ReactApplicationContext) : override fun openSettings(promise: Promise) { try { val intent = Intent() - val currentActivity: Activity = checkNotNull(reactApplicationContext.getCurrentActivity()) + val currentActivity = reactApplicationContext.getCurrentActivity() val selfPackageName = reactApplicationContext.packageName intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) @@ -178,7 +177,11 @@ public open class IntentModule(reactContext: ReactApplicationContext) : intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) - currentActivity.startActivity(intent) + if (currentActivity != null) { + currentActivity.startActivity(intent) + } else { + reactApplicationContext.startActivity(intent) + } promise.resolve(true) } catch (e: Exception) { diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/modules/intent/IntentModuleTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/modules/intent/IntentModuleTest.kt index 6528449969bd..9dbe70fefd74 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/modules/intent/IntentModuleTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/modules/intent/IntentModuleTest.kt @@ -7,6 +7,8 @@ package com.facebook.react.modules.intent +import android.content.Intent +import android.provider.Settings import com.facebook.react.bridge.LifecycleEventListener import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext @@ -65,6 +67,21 @@ class IntentModuleTest { assertThat(promise.rejected).isEqualTo(0) } + @Test + fun openSettings_withNullActivity_startsSettingsFromApplicationContext() { + whenever(context.currentActivity).thenReturn(null) + + val promise = SimplePromise() + intentModule.openSettings(promise) + + val intentCaptor = argumentCaptor() + verify(context).startActivity(intentCaptor.capture()) + assertThat(intentCaptor.firstValue.action) + .isEqualTo(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + assertThat(promise.resolved).isEqualTo(1) + assertThat(promise.rejected).isEqualTo(0) + } + internal class SimplePromise : Promise { companion object { private const val ERROR_DEFAULT_CODE = "EUNSPECIFIED"