Resolve sendIntent call, reject on exception thrown (#50538)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/50538

Promises created from `Linking.sendIntent` calls never resolve, leaving them dangling. This change fixes the issue in two spots:
1. By calling promise.resolve directly after the startActivity call
1. By wrapping startActivity in a try/catch so any exceptions thrown are forwarded to the promise as a rejection

Changelog: [Android][Fixed] - Ensure Linking.sendIntent promises resolve or reject

Reviewed By: NickGerleman

Differential Revision: D72606918

fbshipit-source-id: cd437bf65bb631bc04f99b4d2e3d637f7e98b25e
This commit is contained in:
Peter Abbondanzo
2025-04-08 08:54:33 -07:00
committed by Facebook GitHub Bot
parent a6f1c71dc5
commit 6609ba98e5
2 changed files with 53 additions and 40 deletions
@@ -202,39 +202,44 @@ public open class IntentModule(reactContext: ReactApplicationContext) :
return
}
if (extras != null) {
for (i in 0..<extras.size()) {
val map = extras.getMap(i) ?: continue
val name = map.getString("key")
val type = map.getType(EXTRA_MAP_KEY_FOR_VALUE)
try {
if (extras != null) {
for (i in 0..<extras.size()) {
val map = extras.getMap(i) ?: continue
val name = map.getString("key")
val type = map.getType(EXTRA_MAP_KEY_FOR_VALUE)
when (type) {
ReadableType.String -> {
intent.putExtra(name, map.getString(EXTRA_MAP_KEY_FOR_VALUE))
}
when (type) {
ReadableType.String -> {
intent.putExtra(name, map.getString(EXTRA_MAP_KEY_FOR_VALUE))
}
ReadableType.Number -> {
// We cannot know from JS if is an Integer or Double
// See: https://github.com/facebook/react-native/issues/4141
// We might need to find a workaround if this is really an issue
val number = map.getDouble(EXTRA_MAP_KEY_FOR_VALUE)
intent.putExtra(name, number)
}
ReadableType.Number -> {
// We cannot know from JS if is an Integer or Double
// See: https://github.com/facebook/react-native/issues/4141
// We might need to find a workaround if this is really an issue
val number = map.getDouble(EXTRA_MAP_KEY_FOR_VALUE)
intent.putExtra(name, number)
}
ReadableType.Boolean -> {
intent.putExtra(name, map.getBoolean(EXTRA_MAP_KEY_FOR_VALUE))
}
ReadableType.Boolean -> {
intent.putExtra(name, map.getBoolean(EXTRA_MAP_KEY_FOR_VALUE))
}
else -> {
promise.reject(
JSApplicationIllegalArgumentException("Extra type for $name not supported."))
return
else -> {
promise.reject(
JSApplicationIllegalArgumentException("Extra type for $name not supported."))
return
}
}
}
}
}
sendOSIntent(intent, true)
sendOSIntent(intent, true)
promise.resolve(null)
} catch (e: Exception) {
promise.reject(e)
}
}
private fun sendOSIntent(intent: Intent, useNewTaskFlag: Boolean) {
@@ -64,25 +64,30 @@ class OpenSettingsExample extends React.Component<Props, any> {
}
}
class SendIntentButton extends React.Component<Props> {
handleIntent = async () => {
const SendIntentButton = ({action, extras}: Props) => {
const [isOpeningIntent, setIsOpeningIntent] = React.useState(false);
const handleIntent = async () => {
setIsOpeningIntent(true);
try {
await Linking.sendIntent(this.props.action, this.props.extras);
await Linking.sendIntent(action, extras);
} catch (e) {
ToastAndroid.show(e.message, ToastAndroid.LONG);
} finally {
setIsOpeningIntent(false);
}
};
render() {
return (
<TouchableOpacity onPress={this.handleIntent}>
<View style={[styles.button, styles.buttonIntent]}>
<RNTesterText style={styles.text}>{this.props.action}</RNTesterText>
</View>
</TouchableOpacity>
);
}
}
return (
<TouchableOpacity onPress={handleIntent}>
<View style={[styles.button, styles.buttonIntent]}>
<RNTesterText style={styles.text}>
{isOpeningIntent ? `Opening ${action}...` : action}
</RNTesterText>
</View>
</TouchableOpacity>
);
};
class IntentAndroidExample extends React.Component {
render() {
@@ -100,12 +105,15 @@ class IntentAndroidExample extends React.Component {
<RNTesterBlock title="Send intents">
<SendIntentButton action="android.intent.action.POWER_USAGE_SUMMARY" />
<RNTesterText style={styles.textSeparator}>
Next one will crash if Facebook app is not installed.
Next one will throw an exception if Facebook app is not installed.
</RNTesterText>
<SendIntentButton
action="android.settings.APP_NOTIFICATION_SETTINGS"
extras={[
{'android.provider.extra.APP_PACKAGE': 'com.facebook.katana'},
{
key: 'android.provider.extra.APP_PACKAGE',
value: 'com.facebook.katana',
},
]}
/>
</RNTesterBlock>