Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/url_launcher/url_launcher/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ private void onLaunch(MethodCall call, Result result, String url) {

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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -48,7 +49,8 @@ boolean canLaunch(String url) {
* @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,
Expand All @@ -72,7 +74,12 @@ LaunchStatus launch(
.putExtra(Browser.EXTRA_HEADERS, headersBundle);
}

activity.startActivity(launchIntent);
try {
activity.startActivity(launchIntent);
} catch (ActivityNotFoundException e) {
return LaunchStatus.ACTIVITY_NOT_FOUND;
}

return LaunchStatus.OK;
}

Expand All @@ -87,5 +94,7 @@ enum LaunchStatus {
OK,
/** No activity was found to launch. */
NO_ACTIVITY,
/** No Activity found that can handle given intent. */
ACTIVITY_NOT_FOUND,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -105,6 +106,95 @@ public void onMethodCall_canLaunchReturnsFalse() {
verify(result, times(1)).success(false);
}

@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);
Expand Down
2 changes: 1 addition & 1 deletion packages/url_launcher/url_launcher/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: url_launcher
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:
Expand Down