[url_launcher] Handling the ActivityNotFoundExeption. (#3125)
Catch ActivityNotFoundException and report an error back to the Dart side.
diff --git a/packages/url_launcher/url_launcher/CHANGELOG.md b/packages/url_launcher/url_launcher/CHANGELOG.md
index 995d64c..ab636c6 100644
--- a/packages/url_launcher/url_launcher/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 5.7.8
+
+* Fixed a situation where an app would crash if the url_launcher’s `launch` method can’t find an app to open the provided url. It will now throw a clear Dart PlatformException.
+
## 5.7.7
* Introduce the Link widget with an implementation for native platforms.
diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java
index 0b90dfa..2ca6b7c 100644
--- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java
+++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/MethodCallHandlerImpl.java
@@ -92,6 +92,11 @@
if (launchStatus == LaunchStatus.NO_ACTIVITY) {
result.error("NO_ACTIVITY", "Launching a URL requires a foreground activity.", null);
+ } else if (launchStatus == LaunchStatus.ACTIVITY_NOT_FOUND) {
+ result.error(
+ "ACTIVITY_NOT_FOUND",
+ String.format("No Activity found to handle intent { %s }", url),
+ null);
} else {
result.success(true);
}
diff --git a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java
index 40f2a51..44ecc33 100644
--- a/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java
+++ b/packages/url_launcher/url_launcher/android/src/main/java/io/flutter/plugins/urllauncher/UrlLauncher.java
@@ -1,6 +1,7 @@
package io.flutter.plugins.urllauncher;
import android.app.Activity;
+import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -48,7 +49,8 @@
* @param enableJavaScript Only used if {@param useWebView} is true. Enables JS in the WebView.
* @param enableDomStorage Only used if {@param useWebView} is true. Enables DOM storage in the
* @return {@link LaunchStatus#NO_ACTIVITY} if there's no available {@code applicationContext}.
- * {@link LaunchStatus#OK} otherwise.
+ * {@link LaunchStatus#ACTIVITY_NOT_FOUND} if there's no activity found to handle {@code
+ * launchIntent}. {@link LaunchStatus#OK} otherwise.
*/
LaunchStatus launch(
String url,
@@ -72,7 +74,12 @@
.putExtra(Browser.EXTRA_HEADERS, headersBundle);
}
- activity.startActivity(launchIntent);
+ try {
+ activity.startActivity(launchIntent);
+ } catch (ActivityNotFoundException e) {
+ return LaunchStatus.ACTIVITY_NOT_FOUND;
+ }
+
return LaunchStatus.OK;
}
@@ -87,5 +94,7 @@
OK,
/** No activity was found to launch. */
NO_ACTIVITY,
+ /** No Activity found that can handle given intent. */
+ ACTIVITY_NOT_FOUND,
}
}
diff --git a/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java
index 63ce46f..e759ded 100644
--- a/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java
+++ b/packages/url_launcher/url_launcher/android/src/test/java/io/flutter/plugins/urllauncher/MethodCallHandlerImplTest.java
@@ -8,6 +8,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.os.Bundle;
import androidx.test.core.app.ApplicationProvider;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler;
@@ -106,6 +107,95 @@
}
@Test
+ public void onMethodCall_launchReturnsNoActivityError() {
+ // Setup mock objects
+ urlLauncher = mock(UrlLauncher.class);
+ Result result = mock(Result.class);
+ // Setup expected values
+ String url = "foo";
+ boolean useWebView = false;
+ boolean enableJavaScript = false;
+ boolean enableDomStorage = false;
+ // Setup arguments map send on the method channel
+ Map<String, Object> args = new HashMap<>();
+ args.put("url", url);
+ args.put("useWebView", useWebView);
+ args.put("enableJavaScript", enableJavaScript);
+ args.put("enableDomStorage", enableDomStorage);
+ args.put("headers", new HashMap<>());
+ // Mock the launch method on the urlLauncher class
+ when(urlLauncher.launch(
+ eq(url), any(Bundle.class), eq(useWebView), eq(enableJavaScript), eq(enableDomStorage)))
+ .thenReturn(UrlLauncher.LaunchStatus.NO_ACTIVITY);
+ // Act by calling the "launch" method on the method channel
+ methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
+ methodCallHandler.onMethodCall(new MethodCall("launch", args), result);
+ // Verify the results and assert
+ verify(result, times(1))
+ .error("NO_ACTIVITY", "Launching a URL requires a foreground activity.", null);
+ }
+
+ @Test
+ public void onMethodCall_launchReturnsActivityNotFoundError() {
+ // Setup mock objects
+ urlLauncher = mock(UrlLauncher.class);
+ Result result = mock(Result.class);
+ // Setup expected values
+ String url = "foo";
+ boolean useWebView = false;
+ boolean enableJavaScript = false;
+ boolean enableDomStorage = false;
+ // Setup arguments map send on the method channel
+ Map<String, Object> args = new HashMap<>();
+ args.put("url", url);
+ args.put("useWebView", useWebView);
+ args.put("enableJavaScript", enableJavaScript);
+ args.put("enableDomStorage", enableDomStorage);
+ args.put("headers", new HashMap<>());
+ // Mock the launch method on the urlLauncher class
+ when(urlLauncher.launch(
+ eq(url), any(Bundle.class), eq(useWebView), eq(enableJavaScript), eq(enableDomStorage)))
+ .thenReturn(UrlLauncher.LaunchStatus.ACTIVITY_NOT_FOUND);
+ // Act by calling the "launch" method on the method channel
+ methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
+ methodCallHandler.onMethodCall(new MethodCall("launch", args), result);
+ // Verify the results and assert
+ verify(result, times(1))
+ .error(
+ "ACTIVITY_NOT_FOUND",
+ String.format("No Activity found to handle intent { %s }", url),
+ null);
+ }
+
+ @Test
+ public void onMethodCall_launchReturnsTrue() {
+ // Setup mock objects
+ urlLauncher = mock(UrlLauncher.class);
+ Result result = mock(Result.class);
+ // Setup expected values
+ String url = "foo";
+ boolean useWebView = false;
+ boolean enableJavaScript = false;
+ boolean enableDomStorage = false;
+ // Setup arguments map send on the method channel
+ Map<String, Object> args = new HashMap<>();
+ args.put("url", url);
+ args.put("useWebView", useWebView);
+ args.put("enableJavaScript", enableJavaScript);
+ args.put("enableDomStorage", enableDomStorage);
+ args.put("headers", new HashMap<>());
+ // Mock the launch method on the urlLauncher class
+ when(urlLauncher.launch(
+ eq(url), any(Bundle.class), eq(useWebView), eq(enableJavaScript), eq(enableDomStorage)))
+ .thenReturn(UrlLauncher.LaunchStatus.OK);
+ // Act by calling the "launch" method on the method channel
+ methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
+ methodCallHandler.onMethodCall(new MethodCall("launch", args), result);
+ // Verify the results and assert
+ verify(result, times(1)).success(true);
+ }
+
+ @Test
public void onMethodCall_closeWebView() {
urlLauncher = mock(UrlLauncher.class);
methodCallHandler = new MethodCallHandlerImpl(urlLauncher);
diff --git a/packages/url_launcher/url_launcher/pubspec.yaml b/packages/url_launcher/url_launcher/pubspec.yaml
index cf837b2..7ffc20c 100644
--- a/packages/url_launcher/url_launcher/pubspec.yaml
+++ b/packages/url_launcher/url_launcher/pubspec.yaml
@@ -2,7 +2,7 @@
description: Flutter plugin for launching a URL on Android and iOS. Supports
web, phone, SMS, and email schemes.
homepage: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher
-version: 5.7.7
+version: 5.7.8
flutter:
plugin: