Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Implement for Android
  • Loading branch information
stuartmorgan-g committed Oct 16, 2023
commit 49c459488e07843dc2b31ffe9da04af9d6d2a3b6
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Autogenerated from Pigeon (v10.0.0), do not edit directly.
// Autogenerated from Pigeon (v10.1.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon

package io.flutter.plugins.urllauncher;
Expand All @@ -16,6 +16,10 @@
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** Generated class from Pigeon. */
Expand All @@ -31,7 +35,8 @@ public static class FlutterError extends RuntimeException {
/** The error details. Must be a datatype supported by the api codec. */
public final Object details;

public FlutterError(@NonNull String code, @Nullable String message, @Nullable Object details) {
public FlutterError(@NonNull String code, @Nullable String message, @Nullable Object details)
{
super(message);
this.code = code;
this.details = details;
Expand All @@ -50,15 +55,15 @@ protected static ArrayList<Object> wrapError(@NonNull Throwable exception) {
errorList.add(exception.toString());
errorList.add(exception.getClass().getSimpleName());
errorList.add(
"Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
"Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
}
return errorList;
}

/**
* Configuration options for an in-app WebView.
*
* <p>Generated class from Pigeon that represents data sent in messages.
* Generated class from Pigeon that represents data sent in messages.
*/
public static final class WebViewOptions {
private @NonNull Boolean enableJavaScript;
Expand Down Expand Up @@ -185,27 +190,33 @@ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) {
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface UrlLauncherApi {
/** Returns true if the URL can definitely be launched. */
@NonNull
@NonNull
Boolean canLaunchUrl(@NonNull String url);
/** Opens the URL externally, returning true if successful. */
@NonNull
@NonNull
Boolean launchUrl(@NonNull String url, @NonNull Map<String, String> headers);
/** Opens the URL in an in-app WebView, returning true if it opens successfully. */
@NonNull
Boolean openUrlInWebView(@NonNull String url, @NonNull WebViewOptions options);
/**
* Opens the URL in an in-app Custom Tab or WebView, returning true if it
* opens successfully.
*/
@NonNull
Boolean openUrlInApp(@NonNull String url, @NonNull Boolean allowCustomTab, @NonNull WebViewOptions options);

@NonNull
Boolean supportsCustomTabs();
/** Closes the view opened by [openUrlInSafariViewController]. */
void closeWebView();

/** The codec used by UrlLauncherApi. */
static @NonNull MessageCodec<Object> getCodec() {
return UrlLauncherApiCodec.INSTANCE;
}
/** Sets up an instance of `UrlLauncherApi` to handle messages through the `binaryMessenger`. */
/**Sets up an instance of `UrlLauncherApi` to handle messages through the `binaryMessenger`. */
static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable UrlLauncherApi api) {
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.UrlLauncherApi.canLaunchUrl", getCodec());
binaryMessenger, "dev.flutter.pigeon.url_launcher_android.UrlLauncherApi.canLaunchUrl", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
Expand All @@ -215,7 +226,8 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable UrlLaunche
try {
Boolean output = api.canLaunchUrl(urlArg);
wrapped.add(0, output);
} catch (Throwable exception) {
}
catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
Expand All @@ -228,7 +240,7 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable UrlLaunche
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.UrlLauncherApi.launchUrl", getCodec());
binaryMessenger, "dev.flutter.pigeon.url_launcher_android.UrlLauncherApi.launchUrl", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
Expand All @@ -239,7 +251,8 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable UrlLaunche
try {
Boolean output = api.launchUrl(urlArg, headersArg);
wrapped.add(0, output);
} catch (Throwable exception) {
}
catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
Expand All @@ -252,18 +265,42 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable UrlLaunche
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.UrlLauncherApi.openUrlInWebView", getCodec());
binaryMessenger, "dev.flutter.pigeon.url_launcher_android.UrlLauncherApi.openUrlInApp", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
String urlArg = (String) args.get(0);
WebViewOptions optionsArg = (WebViewOptions) args.get(1);
Boolean allowCustomTabArg = (Boolean) args.get(1);
WebViewOptions optionsArg = (WebViewOptions) args.get(2);
try {
Boolean output = api.openUrlInApp(urlArg, allowCustomTabArg, optionsArg);
wrapped.add(0, output);
}
catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.url_launcher_android.UrlLauncherApi.supportsCustomTabs", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
try {
Boolean output = api.openUrlInWebView(urlArg, optionsArg);
Boolean output = api.supportsCustomTabs();
wrapped.add(0, output);
} catch (Throwable exception) {
}
catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
Expand All @@ -276,15 +313,16 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable UrlLaunche
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.UrlLauncherApi.closeWebView", getCodec());
binaryMessenger, "dev.flutter.pigeon.url_launcher_android.UrlLauncherApi.closeWebView", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
try {
api.closeWebView();
wrapped.add(0, null);
} catch (Throwable exception) {
}
catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.browser.customtabs.CustomTabsClient;
import androidx.browser.customtabs.CustomTabsIntent;
import io.flutter.plugins.urllauncher.Messages.UrlLauncherApi;
import io.flutter.plugins.urllauncher.Messages.WebViewOptions;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;

Expand Down Expand Up @@ -95,14 +97,16 @@ void setActivity(@Nullable Activity activity) {
}

@Override
public @NonNull Boolean openUrlInWebView(@NonNull String url, @NonNull WebViewOptions options) {
public @NonNull Boolean openUrlInApp(
@NonNull String url, @NonNull Boolean allowCustomTab, @NonNull WebViewOptions options) {
ensureActivity();
assert activity != null;

Bundle headersBundle = extractBundle(options.getHeaders());

// Try to launch using Custom Tabs if they have the necessary functionality.
if (!containsRestrictedHeader(options.getHeaders())) {
// Try to launch using Custom Tabs if they have the necessary functionality, unless the caller
// specifically requested a web view.
if (allowCustomTab && !containsRestrictedHeader(options.getHeaders())) {
Uri uri = Uri.parse(url);
if (openCustomTab(activity, uri, headersBundle)) {
return true;
Expand Down Expand Up @@ -131,6 +135,11 @@ public void closeWebView() {
applicationContext.sendBroadcast(new Intent(WebViewActivity.ACTION_CLOSE));
}

@Override
public @NonNull Boolean supportsCustomTabs() {
return CustomTabsClient.getPackageName(applicationContext, Collections.emptyList()) != null;
}

private static boolean openCustomTab(
@NonNull Context context, @NonNull Uri uri, @NonNull Bundle headersBundle) {
CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder().build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public void launch_returnsTrue() {
}

@Test
public void openWebView_opensUrl_inWebView() {
public void openUrlInApp_opensUrlInWebViewIfNecessary() {
Activity activity = mock(Activity.class);
UrlLauncher api = new UrlLauncher(ApplicationProvider.getApplicationContext());
api.setActivity(activity);
Expand All @@ -141,8 +141,9 @@ public void openWebView_opensUrl_inWebView() {
headers.put("key", "value");

boolean result =
api.openUrlInWebView(
api.openUrlInApp(
url,
true,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(enableJavaScript)
.setEnableDomStorage(enableDomStorage)
Expand All @@ -162,20 +163,44 @@ public void openWebView_opensUrl_inWebView() {
}

@Test
public void openWebView_opensUrl_inCustomTabs() {
public void openWebView_opensUrlInWebViewIfRequested() {
Activity activity = mock(Activity.class);
UrlLauncher api = new UrlLauncher(ApplicationProvider.getApplicationContext());
api.setActivity(activity);
String url = "https://flutter.dev";

boolean result =
api.openUrlInWebView(
url,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(false)
.setEnableDomStorage(false)
.setHeaders(new HashMap<>())
.build());
api.openUrlInApp(
url,
false,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(false)
.setEnableDomStorage(false)
.setHeaders(new HashMap<>())
.build());

final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(activity).startActivity(intentCaptor.capture());
assertTrue(result);
assertEquals(url, intentCaptor.getValue().getExtras().getString(WebViewActivity.URL_EXTRA));
}

@Test
public void openWebView_opensUrlInCustomTabs() {
Activity activity = mock(Activity.class);
UrlLauncher api = new UrlLauncher(ApplicationProvider.getApplicationContext());
api.setActivity(activity);
String url = "https://flutter.dev";

boolean result =
api.openUrlInApp(
url,
true,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(false)
.setEnableDomStorage(false)
.setHeaders(new HashMap<>())
.build());

final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(activity).startActivity(intentCaptor.capture(), isNull());
Expand All @@ -185,7 +210,7 @@ public void openWebView_opensUrl_inCustomTabs() {
}

@Test
public void openWebView_opensUrl_inCustomTabs_withCORSAllowedHeader() {
public void openWebView_opensUrlInCustomTabsWithCORSAllowedHeader() {
Activity activity = mock(Activity.class);
UrlLauncher api = new UrlLauncher(ApplicationProvider.getApplicationContext());
api.setActivity(activity);
Expand All @@ -195,8 +220,9 @@ public void openWebView_opensUrl_inCustomTabs_withCORSAllowedHeader() {
headers.put(headerKey, "text/plain");

boolean result =
api.openUrlInWebView(
api.openUrlInApp(
url,
true,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(false)
.setEnableDomStorage(false)
Expand All @@ -214,7 +240,7 @@ public void openWebView_opensUrl_inCustomTabs_withCORSAllowedHeader() {
}

@Test
public void openWebView_fallsbackTo_inWebView() {
public void openWebView_fallsBackToWebViewIfCustomTabFails() {
Activity activity = mock(Activity.class);
UrlLauncher api = new UrlLauncher(ApplicationProvider.getApplicationContext());
api.setActivity(activity);
Expand All @@ -224,8 +250,9 @@ public void openWebView_fallsbackTo_inWebView() {
.startActivity(any(), isNull()); // for custom tabs intent

boolean result =
api.openUrlInWebView(
api.openUrlInApp(
url,
true,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(false)
.setEnableDomStorage(false)
Expand All @@ -251,8 +278,9 @@ public void openWebView_handlesEnableJavaScript() {
HashMap<String, String> headers = new HashMap<>();
headers.put("key", "value");

api.openUrlInWebView(
api.openUrlInApp(
"https://flutter.dev",
true,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(enableJavaScript)
.setEnableDomStorage(false)
Expand All @@ -277,8 +305,9 @@ public void openWebView_handlesHeaders() {
headers.put(key1, "value");
headers.put(key2, "value2");

api.openUrlInWebView(
api.openUrlInApp(
"https://flutter.dev",
true,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(false)
.setEnableDomStorage(false)
Expand All @@ -303,8 +332,9 @@ public void openWebView_handlesEnableDomStorage() {
HashMap<String, String> headers = new HashMap<>();
headers.put("key", "value");

api.openUrlInWebView(
api.openUrlInApp(
"https://flutter.dev",
true,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(false)
.setEnableDomStorage(enableDomStorage)
Expand All @@ -327,8 +357,9 @@ public void openWebView_throwsForNoCurrentActivity() {
assertThrows(
Messages.FlutterError.class,
() ->
api.openUrlInWebView(
api.openUrlInApp(
"https://flutter.dev",
true,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(false)
.setEnableDomStorage(false)
Expand All @@ -350,8 +381,9 @@ public void openWebView_returnsFalse() {
.startActivity(any()); // for webview intent

boolean result =
api.openUrlInWebView(
api.openUrlInApp(
"https://flutter.dev",
true,
new Messages.WebViewOptions.Builder()
.setEnableJavaScript(false)
.setEnableDomStorage(false)
Expand Down
Loading