[webview_flutter_android] Copies Android implementation of webview_flutter from v4_webview (#6851)
* new android release
* Version bump
* update all plugins config
* fix lints and add action item to changelog
diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
index fbb502c..a7a820d 100644
--- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 3.0.0
+
+* **BREAKING CHANGE** Updates platform implementation to `2.0.0` release of
+ `webview_flutter_platform_interface`. See
+ [webview_flutter](https://pub.dev/packages/webview_flutter/versions/4.0.0) for updated usage.
+
## 2.10.4
* Updates code for `no_leading_underscores_for_local_identifiers` lint.
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerFlutterApiImpl.java
index 1981d8e..0d4797e 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerFlutterApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerFlutterApiImpl.java
@@ -47,20 +47,6 @@
callback);
}
- /**
- * Communicates to Dart that the reference to a {@link DownloadListener} was removed.
- *
- * @param downloadListener the instance whose reference will be removed
- * @param callback reply callback with return value from Dart
- */
- public void dispose(DownloadListener downloadListener, Reply<Void> callback) {
- if (instanceManager.containsInstance(downloadListener)) {
- dispose(getIdentifierForListener(downloadListener), callback);
- } else {
- callback.reply(null);
- }
- }
-
private long getIdentifierForListener(DownloadListener listener) {
final Long identifier = instanceManager.getIdentifierForStrongReference(listener);
if (identifier == null) {
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java
index ed0c2ae..a9cbcbd 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/DownloadListenerHostApiImpl.java
@@ -6,7 +6,6 @@
import android.webkit.DownloadListener;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi;
/**
@@ -21,11 +20,9 @@
/**
* Implementation of {@link DownloadListener} that passes arguments of callback methods to Dart.
- *
- * <p>No messages are sent to Dart after {@link DownloadListenerImpl#release} is called.
*/
- public static class DownloadListenerImpl implements DownloadListener, Releasable {
- @Nullable private DownloadListenerFlutterApiImpl flutterApi;
+ public static class DownloadListenerImpl implements DownloadListener {
+ private final DownloadListenerFlutterApiImpl flutterApi;
/**
* Creates a {@link DownloadListenerImpl} that passes arguments of callbacks methods to Dart.
@@ -43,18 +40,8 @@
String contentDisposition,
String mimetype,
long contentLength) {
- if (flutterApi != null) {
- flutterApi.onDownloadStart(
- this, url, userAgent, contentDisposition, mimetype, contentLength, reply -> {});
- }
- }
-
- @Override
- public void release() {
- if (flutterApi != null) {
- flutterApi.dispose(this, reply -> {});
- }
- flutterApi = null;
+ flutterApi.onDownloadStart(
+ this, url, userAgent, contentDisposition, mimetype, contentLength, reply -> {});
}
}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java
index 9a6b1c4..15c80cc 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java
@@ -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 (v4.0.2), do not edit directly.
+// Autogenerated from Pigeon (v4.2.3), do not edit directly.
// See also: https://pub.dev/packages/pigeon
package io.flutter.plugins.webviewflutter;
@@ -17,6 +17,7 @@
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;
@@ -342,22 +343,22 @@
void error(Throwable error);
}
-
- private static class JavaObjectHostApiCodec extends StandardMessageCodec {
- public static final JavaObjectHostApiCodec INSTANCE = new JavaObjectHostApiCodec();
-
- private JavaObjectHostApiCodec() {}
- }
-
- /** Generated interface from Pigeon that represents a handler of messages from Flutter. */
+ /**
+ * Handles methods calls to the native Java Object class.
+ *
+ * <p>Also handles calls to remove the reference to an instance with `dispose`.
+ *
+ * <p>See https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html.
+ *
+ * <p>Generated interface from Pigeon that represents a handler of messages from Flutter.
+ */
public interface JavaObjectHostApi {
void dispose(@NonNull Long identifier);
/** The codec used by JavaObjectHostApi. */
static MessageCodec<Object> getCodec() {
- return JavaObjectHostApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
-
/**
* Sets up an instance of `JavaObjectHostApi` to handle messages through the `binaryMessenger`.
*/
@@ -372,6 +373,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number identifierArg = (Number) args.get(0);
if (identifierArg == null) {
throw new NullPointerException("identifierArg unexpectedly null.");
@@ -389,14 +391,13 @@
}
}
}
-
- private static class JavaObjectFlutterApiCodec extends StandardMessageCodec {
- public static final JavaObjectFlutterApiCodec INSTANCE = new JavaObjectFlutterApiCodec();
-
- private JavaObjectFlutterApiCodec() {}
- }
-
- /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
+ /**
+ * Handles callbacks methods for the native Java Object class.
+ *
+ * <p>See https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html.
+ *
+ * <p>Generated class from Pigeon that represents Flutter messages that can be called from Java.
+ */
public static class JavaObjectFlutterApi {
private final BinaryMessenger binaryMessenger;
@@ -407,9 +408,9 @@
public interface Reply<T> {
void reply(T reply);
}
-
+ /** The codec used by JavaObjectFlutterApi. */
static MessageCodec<Object> getCodec() {
- return JavaObjectFlutterApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
public void dispose(@NonNull Long identifierArg, Reply<Void> callback) {
@@ -417,19 +418,12 @@
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.JavaObjectFlutterApi.dispose", getCodec());
channel.send(
- new ArrayList<Object>(Arrays.asList(identifierArg)),
+ new ArrayList<Object>(Collections.singletonList(identifierArg)),
channelReply -> {
callback.reply(null);
});
}
}
-
- private static class CookieManagerHostApiCodec extends StandardMessageCodec {
- public static final CookieManagerHostApiCodec INSTANCE = new CookieManagerHostApiCodec();
-
- private CookieManagerHostApiCodec() {}
- }
-
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface CookieManagerHostApi {
void clearCookies(Result<Boolean> result);
@@ -438,9 +432,8 @@
/** The codec used by CookieManagerHostApi. */
static MessageCodec<Object> getCodec() {
- return CookieManagerHostApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
-
/**
* Sets up an instance of `CookieManagerHostApi` to handle messages through the
* `binaryMessenger`.
@@ -490,6 +483,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
String urlArg = (String) args.get(0);
if (urlArg == null) {
throw new NullPointerException("urlArg unexpectedly null.");
@@ -518,7 +512,7 @@
private WebViewHostApiCodec() {}
@Override
- protected Object readValueOfType(byte type, ByteBuffer buffer) {
+ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) {
switch (type) {
case (byte) 128:
return WebViewPoint.fromMap((Map<String, Object>) readValue(buffer));
@@ -529,7 +523,7 @@
}
@Override
- protected void writeValue(ByteArrayOutputStream stream, Object value) {
+ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) {
if (value instanceof WebViewPoint) {
stream.write(128);
writeValue(stream, ((WebViewPoint) value).toMap());
@@ -543,8 +537,6 @@
public interface WebViewHostApi {
void create(@NonNull Long instanceId, @NonNull Boolean useHybridComposition);
- void dispose(@NonNull Long instanceId);
-
void loadData(
@NonNull Long instanceId,
@NonNull String data,
@@ -619,7 +611,6 @@
static MessageCodec<Object> getCodec() {
return WebViewHostApiCodec.INSTANCE;
}
-
/** Sets up an instance of `WebViewHostApi` to handle messages through the `binaryMessenger`. */
static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) {
{
@@ -632,6 +623,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -656,31 +648,6 @@
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
- binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.dispose", getCodec());
- if (api != null) {
- channel.setMessageHandler(
- (message, reply) -> {
- Map<String, Object> wrapped = new HashMap<>();
- try {
- ArrayList<Object> args = (ArrayList<Object>) message;
- Number instanceIdArg = (Number) args.get(0);
- if (instanceIdArg == null) {
- throw new NullPointerException("instanceIdArg unexpectedly null.");
- }
- api.dispose((instanceIdArg == null) ? null : instanceIdArg.longValue());
- wrapped.put("result", null);
- } catch (Error | RuntimeException exception) {
- wrapped.put("error", wrapError(exception));
- }
- reply.reply(wrapped);
- });
- } else {
- channel.setMessageHandler(null);
- }
- }
- {
- BasicMessageChannel<Object> channel =
- new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.loadData", getCodec());
if (api != null) {
channel.setMessageHandler(
@@ -688,6 +655,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -725,6 +693,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -764,6 +733,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -800,6 +770,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -834,6 +805,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -860,6 +832,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -886,6 +859,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -912,6 +886,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -937,6 +912,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -962,6 +938,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -987,6 +964,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1020,6 +998,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1064,6 +1043,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1090,6 +1070,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1126,6 +1107,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1162,6 +1144,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1188,6 +1171,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1214,6 +1198,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1243,6 +1228,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Boolean enabledArg = (Boolean) args.get(0);
if (enabledArg == null) {
throw new NullPointerException("enabledArg unexpectedly null.");
@@ -1268,6 +1254,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1303,6 +1290,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1339,6 +1327,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1375,6 +1364,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1405,6 +1395,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1435,6 +1426,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1458,19 +1450,10 @@
}
}
}
-
- private static class WebSettingsHostApiCodec extends StandardMessageCodec {
- public static final WebSettingsHostApiCodec INSTANCE = new WebSettingsHostApiCodec();
-
- private WebSettingsHostApiCodec() {}
- }
-
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface WebSettingsHostApi {
void create(@NonNull Long instanceId, @NonNull Long webViewInstanceId);
- void dispose(@NonNull Long instanceId);
-
void setDomStorageEnabled(@NonNull Long instanceId, @NonNull Boolean flag);
void setJavaScriptCanOpenWindowsAutomatically(@NonNull Long instanceId, @NonNull Boolean flag);
@@ -1497,9 +1480,8 @@
/** The codec used by WebSettingsHostApi. */
static MessageCodec<Object> getCodec() {
- return WebSettingsHostApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
-
/**
* Sets up an instance of `WebSettingsHostApi` to handle messages through the `binaryMessenger`.
*/
@@ -1514,6 +1496,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1538,31 +1521,6 @@
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
- binaryMessenger, "dev.flutter.pigeon.WebSettingsHostApi.dispose", getCodec());
- if (api != null) {
- channel.setMessageHandler(
- (message, reply) -> {
- Map<String, Object> wrapped = new HashMap<>();
- try {
- ArrayList<Object> args = (ArrayList<Object>) message;
- Number instanceIdArg = (Number) args.get(0);
- if (instanceIdArg == null) {
- throw new NullPointerException("instanceIdArg unexpectedly null.");
- }
- api.dispose((instanceIdArg == null) ? null : instanceIdArg.longValue());
- wrapped.put("result", null);
- } catch (Error | RuntimeException exception) {
- wrapped.put("error", wrapError(exception));
- }
- reply.reply(wrapped);
- });
- } else {
- channel.setMessageHandler(null);
- }
- }
- {
- BasicMessageChannel<Object> channel =
- new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled",
getCodec());
@@ -1572,6 +1530,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1604,6 +1563,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1636,6 +1596,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1668,6 +1629,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1700,6 +1662,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1730,6 +1693,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1762,6 +1726,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1794,6 +1759,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1826,6 +1792,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1858,6 +1825,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1890,6 +1858,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1922,6 +1891,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1944,23 +1914,14 @@
}
}
}
-
- private static class JavaScriptChannelHostApiCodec extends StandardMessageCodec {
- public static final JavaScriptChannelHostApiCodec INSTANCE =
- new JavaScriptChannelHostApiCodec();
-
- private JavaScriptChannelHostApiCodec() {}
- }
-
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface JavaScriptChannelHostApi {
void create(@NonNull Long instanceId, @NonNull String channelName);
/** The codec used by JavaScriptChannelHostApi. */
static MessageCodec<Object> getCodec() {
- return JavaScriptChannelHostApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
-
/**
* Sets up an instance of `JavaScriptChannelHostApi` to handle messages through the
* `binaryMessenger`.
@@ -1976,6 +1937,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -1998,14 +1960,6 @@
}
}
}
-
- private static class JavaScriptChannelFlutterApiCodec extends StandardMessageCodec {
- public static final JavaScriptChannelFlutterApiCodec INSTANCE =
- new JavaScriptChannelFlutterApiCodec();
-
- private JavaScriptChannelFlutterApiCodec() {}
- }
-
/** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
public static class JavaScriptChannelFlutterApi {
private final BinaryMessenger binaryMessenger;
@@ -2017,22 +1971,9 @@
public interface Reply<T> {
void reply(T reply);
}
-
+ /** The codec used by JavaScriptChannelFlutterApi. */
static MessageCodec<Object> getCodec() {
- return JavaScriptChannelFlutterApiCodec.INSTANCE;
- }
-
- public void dispose(@NonNull Long instanceIdArg, Reply<Void> callback) {
- BasicMessageChannel<Object> channel =
- new BasicMessageChannel<>(
- binaryMessenger,
- "dev.flutter.pigeon.JavaScriptChannelFlutterApi.dispose",
- getCodec());
- channel.send(
- new ArrayList<Object>(Arrays.asList(instanceIdArg)),
- channelReply -> {
- callback.reply(null);
- });
+ return new StandardMessageCodec();
}
public void postMessage(
@@ -2049,22 +1990,17 @@
});
}
}
-
- private static class WebViewClientHostApiCodec extends StandardMessageCodec {
- public static final WebViewClientHostApiCodec INSTANCE = new WebViewClientHostApiCodec();
-
- private WebViewClientHostApiCodec() {}
- }
-
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface WebViewClientHostApi {
- void create(@NonNull Long instanceId, @NonNull Boolean shouldOverrideUrlLoading);
+ void create(@NonNull Long instanceId);
+
+ void setSynchronousReturnValueForShouldOverrideUrlLoading(
+ @NonNull Long instanceId, @NonNull Boolean value);
/** The codec used by WebViewClientHostApi. */
static MessageCodec<Object> getCodec() {
- return WebViewClientHostApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
-
/**
* Sets up an instance of `WebViewClientHostApi` to handle messages through the
* `binaryMessenger`.
@@ -2080,18 +2016,45 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
}
- Boolean shouldOverrideUrlLoadingArg = (Boolean) args.get(1);
- if (shouldOverrideUrlLoadingArg == null) {
- throw new NullPointerException(
- "shouldOverrideUrlLoadingArg unexpectedly null.");
+ api.create((instanceIdArg == null) ? null : instanceIdArg.longValue());
+ wrapped.put("result", null);
+ } catch (Error | RuntimeException exception) {
+ wrapped.put("error", wrapError(exception));
+ }
+ reply.reply(wrapped);
+ });
+ } else {
+ channel.setMessageHandler(null);
+ }
+ }
+ {
+ BasicMessageChannel<Object> channel =
+ new BasicMessageChannel<>(
+ binaryMessenger,
+ "dev.flutter.pigeon.WebViewClientHostApi.setSynchronousReturnValueForShouldOverrideUrlLoading",
+ getCodec());
+ if (api != null) {
+ channel.setMessageHandler(
+ (message, reply) -> {
+ Map<String, Object> wrapped = new HashMap<>();
+ try {
+ ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
+ Number instanceIdArg = (Number) args.get(0);
+ if (instanceIdArg == null) {
+ throw new NullPointerException("instanceIdArg unexpectedly null.");
}
- api.create(
- (instanceIdArg == null) ? null : instanceIdArg.longValue(),
- shouldOverrideUrlLoadingArg);
+ Boolean valueArg = (Boolean) args.get(1);
+ if (valueArg == null) {
+ throw new NullPointerException("valueArg unexpectedly null.");
+ }
+ api.setSynchronousReturnValueForShouldOverrideUrlLoading(
+ (instanceIdArg == null) ? null : instanceIdArg.longValue(), valueArg);
wrapped.put("result", null);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
@@ -2111,7 +2074,7 @@
private WebViewClientFlutterApiCodec() {}
@Override
- protected Object readValueOfType(byte type, ByteBuffer buffer) {
+ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) {
switch (type) {
case (byte) 128:
return WebResourceErrorData.fromMap((Map<String, Object>) readValue(buffer));
@@ -2125,7 +2088,7 @@
}
@Override
- protected void writeValue(ByteArrayOutputStream stream, Object value) {
+ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) {
if (value instanceof WebResourceErrorData) {
stream.write(128);
writeValue(stream, ((WebResourceErrorData) value).toMap());
@@ -2149,22 +2112,11 @@
public interface Reply<T> {
void reply(T reply);
}
-
+ /** The codec used by WebViewClientFlutterApi. */
static MessageCodec<Object> getCodec() {
return WebViewClientFlutterApiCodec.INSTANCE;
}
- public void dispose(@NonNull Long instanceIdArg, Reply<Void> callback) {
- BasicMessageChannel<Object> channel =
- new BasicMessageChannel<>(
- binaryMessenger, "dev.flutter.pigeon.WebViewClientFlutterApi.dispose", getCodec());
- channel.send(
- new ArrayList<Object>(Arrays.asList(instanceIdArg)),
- channelReply -> {
- callback.reply(null);
- });
- }
-
public void onPageStarted(
@NonNull Long instanceIdArg,
@NonNull Long webViewInstanceIdArg,
@@ -2275,22 +2227,14 @@
});
}
}
-
- private static class DownloadListenerHostApiCodec extends StandardMessageCodec {
- public static final DownloadListenerHostApiCodec INSTANCE = new DownloadListenerHostApiCodec();
-
- private DownloadListenerHostApiCodec() {}
- }
-
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface DownloadListenerHostApi {
void create(@NonNull Long instanceId);
/** The codec used by DownloadListenerHostApi. */
static MessageCodec<Object> getCodec() {
- return DownloadListenerHostApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
-
/**
* Sets up an instance of `DownloadListenerHostApi` to handle messages through the
* `binaryMessenger`.
@@ -2306,6 +2250,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -2323,14 +2268,6 @@
}
}
}
-
- private static class DownloadListenerFlutterApiCodec extends StandardMessageCodec {
- public static final DownloadListenerFlutterApiCodec INSTANCE =
- new DownloadListenerFlutterApiCodec();
-
- private DownloadListenerFlutterApiCodec() {}
- }
-
/** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
public static class DownloadListenerFlutterApi {
private final BinaryMessenger binaryMessenger;
@@ -2342,20 +2279,9 @@
public interface Reply<T> {
void reply(T reply);
}
-
+ /** The codec used by DownloadListenerFlutterApi. */
static MessageCodec<Object> getCodec() {
- return DownloadListenerFlutterApiCodec.INSTANCE;
- }
-
- public void dispose(@NonNull Long instanceIdArg, Reply<Void> callback) {
- BasicMessageChannel<Object> channel =
- new BasicMessageChannel<>(
- binaryMessenger, "dev.flutter.pigeon.DownloadListenerFlutterApi.dispose", getCodec());
- channel.send(
- new ArrayList<Object>(Arrays.asList(instanceIdArg)),
- channelReply -> {
- callback.reply(null);
- });
+ return new StandardMessageCodec();
}
public void onDownloadStart(
@@ -2385,22 +2311,14 @@
});
}
}
-
- private static class WebChromeClientHostApiCodec extends StandardMessageCodec {
- public static final WebChromeClientHostApiCodec INSTANCE = new WebChromeClientHostApiCodec();
-
- private WebChromeClientHostApiCodec() {}
- }
-
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface WebChromeClientHostApi {
- void create(@NonNull Long instanceId, @NonNull Long webViewClientInstanceId);
+ void create(@NonNull Long instanceId);
/** The codec used by WebChromeClientHostApi. */
static MessageCodec<Object> getCodec() {
- return WebChromeClientHostApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
-
/**
* Sets up an instance of `WebChromeClientHostApi` to handle messages through the
* `binaryMessenger`.
@@ -2416,19 +2334,12 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
}
- Number webViewClientInstanceIdArg = (Number) args.get(1);
- if (webViewClientInstanceIdArg == null) {
- throw new NullPointerException("webViewClientInstanceIdArg unexpectedly null.");
- }
- api.create(
- (instanceIdArg == null) ? null : instanceIdArg.longValue(),
- (webViewClientInstanceIdArg == null)
- ? null
- : webViewClientInstanceIdArg.longValue());
+ api.create((instanceIdArg == null) ? null : instanceIdArg.longValue());
wrapped.put("result", null);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
@@ -2441,14 +2352,6 @@
}
}
}
-
- private static class FlutterAssetManagerHostApiCodec extends StandardMessageCodec {
- public static final FlutterAssetManagerHostApiCodec INSTANCE =
- new FlutterAssetManagerHostApiCodec();
-
- private FlutterAssetManagerHostApiCodec() {}
- }
-
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface FlutterAssetManagerHostApi {
@NonNull
@@ -2459,9 +2362,8 @@
/** The codec used by FlutterAssetManagerHostApi. */
static MessageCodec<Object> getCodec() {
- return FlutterAssetManagerHostApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
-
/**
* Sets up an instance of `FlutterAssetManagerHostApi` to handle messages through the
* `binaryMessenger`.
@@ -2477,6 +2379,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
String pathArg = (String) args.get(0);
if (pathArg == null) {
throw new NullPointerException("pathArg unexpectedly null.");
@@ -2504,6 +2407,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
String nameArg = (String) args.get(0);
if (nameArg == null) {
throw new NullPointerException("nameArg unexpectedly null.");
@@ -2521,14 +2425,6 @@
}
}
}
-
- private static class WebChromeClientFlutterApiCodec extends StandardMessageCodec {
- public static final WebChromeClientFlutterApiCodec INSTANCE =
- new WebChromeClientFlutterApiCodec();
-
- private WebChromeClientFlutterApiCodec() {}
- }
-
/** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
public static class WebChromeClientFlutterApi {
private final BinaryMessenger binaryMessenger;
@@ -2540,20 +2436,9 @@
public interface Reply<T> {
void reply(T reply);
}
-
+ /** The codec used by WebChromeClientFlutterApi. */
static MessageCodec<Object> getCodec() {
- return WebChromeClientFlutterApiCodec.INSTANCE;
- }
-
- public void dispose(@NonNull Long instanceIdArg, Reply<Void> callback) {
- BasicMessageChannel<Object> channel =
- new BasicMessageChannel<>(
- binaryMessenger, "dev.flutter.pigeon.WebChromeClientFlutterApi.dispose", getCodec());
- channel.send(
- new ArrayList<Object>(Arrays.asList(instanceIdArg)),
- channelReply -> {
- callback.reply(null);
- });
+ return new StandardMessageCodec();
}
public void onProgressChanged(
@@ -2573,13 +2458,6 @@
});
}
}
-
- private static class WebStorageHostApiCodec extends StandardMessageCodec {
- public static final WebStorageHostApiCodec INSTANCE = new WebStorageHostApiCodec();
-
- private WebStorageHostApiCodec() {}
- }
-
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface WebStorageHostApi {
void create(@NonNull Long instanceId);
@@ -2588,9 +2466,8 @@
/** The codec used by WebStorageHostApi. */
static MessageCodec<Object> getCodec() {
- return WebStorageHostApiCodec.INSTANCE;
+ return new StandardMessageCodec();
}
-
/**
* Sets up an instance of `WebStorageHostApi` to handle messages through the `binaryMessenger`.
*/
@@ -2605,6 +2482,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -2630,6 +2508,7 @@
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
+ assert args != null;
Number instanceIdArg = (Number) args.get(0);
if (instanceIdArg == null) {
throw new NullPointerException("instanceIdArg unexpectedly null.");
@@ -2648,7 +2527,8 @@
}
}
- private static Map<String, Object> wrapError(Throwable exception) {
+ @NonNull
+ private static Map<String, Object> wrapError(@NonNull Throwable exception) {
Map<String, Object> errorMap = new HashMap<>();
errorMap.put("message", exception.toString());
errorMap.put("code", exception.getClass().getSimpleName());
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java
index ce6f2b8..cf2c262 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannel.java
@@ -8,7 +8,6 @@
import android.os.Looper;
import android.webkit.JavascriptInterface;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
/**
* Added as a JavaScript interface to the WebView for any JavaScript channel that the Dart code sets
@@ -16,13 +15,11 @@
*
* <p>Exposes a single method named `postMessage` to JavaScript, which sends a message to the Dart
* code.
- *
- * <p>No messages are sent to Dart after {@link JavaScriptChannel#release} is called.
*/
-public class JavaScriptChannel implements Releasable {
+public class JavaScriptChannel {
private final Handler platformThreadHandler;
final String javaScriptChannelName;
- @Nullable private JavaScriptChannelFlutterApiImpl flutterApi;
+ private final JavaScriptChannelFlutterApiImpl flutterApi;
/**
* Creates a {@link JavaScriptChannel} that passes arguments of callback methods to Dart.
@@ -46,9 +43,7 @@
public void postMessage(final String message) {
final Runnable postMessageRunnable =
() -> {
- if (flutterApi != null) {
- flutterApi.postMessage(JavaScriptChannel.this, message, reply -> {});
- }
+ flutterApi.postMessage(JavaScriptChannel.this, message, reply -> {});
};
if (platformThreadHandler.getLooper() == Looper.myLooper()) {
@@ -57,12 +52,4 @@
platformThreadHandler.post(postMessageRunnable);
}
}
-
- @Override
- public void release() {
- if (flutterApi != null) {
- flutterApi.dispose(this, reply -> {});
- }
- flutterApi = null;
- }
}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelFlutterApiImpl.java
index dbac833..ca08926 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelFlutterApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/JavaScriptChannelFlutterApiImpl.java
@@ -33,20 +33,6 @@
super.postMessage(getIdentifierForJavaScriptChannel(javaScriptChannel), messageArg, callback);
}
- /**
- * Communicates to Dart that the reference to a {@link JavaScriptChannel} was removed.
- *
- * @param javaScriptChannel The instance whose reference will be removed.
- * @param callback Reply callback with return value from Dart.
- */
- public void dispose(JavaScriptChannel javaScriptChannel, Reply<Void> callback) {
- if (instanceManager.containsInstance(javaScriptChannel)) {
- dispose(getIdentifierForJavaScriptChannel(javaScriptChannel), callback);
- } else {
- callback.reply(null);
- }
- }
-
private long getIdentifierForJavaScriptChannel(JavaScriptChannel javaScriptChannel) {
final Long identifier = instanceManager.getIdentifierForStrongReference(javaScriptChannel);
if (identifier == null) {
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java
deleted file mode 100644
index 9c4ed76..0000000
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/Releasable.java
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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.
-
-package io.flutter.plugins.webviewflutter;
-
-/**
- * Represents a resource, or a holder of resources, which may be released once they are no longer
- * needed.
- */
-interface Releasable {
- /** Notify that that the reference to an object will be removed by a holder. */
- void release();
-}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java
index 28d63ec..cf263e2 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientFlutterApiImpl.java
@@ -40,20 +40,6 @@
getIdentifierForClient(webChromeClient), webViewIdentifier, progress, callback);
}
- /**
- * Communicates to Dart that the reference to a {@link WebChromeClient}} was removed.
- *
- * @param webChromeClient the instance whose reference will be removed
- * @param callback reply callback with return value from Dart
- */
- public void dispose(WebChromeClient webChromeClient, Reply<Void> callback) {
- if (instanceManager.containsInstance(webChromeClient)) {
- dispose(getIdentifierForClient(webChromeClient), callback);
- } else {
- callback.reply(null);
- }
- }
-
private long getIdentifierForClient(WebChromeClient webChromeClient) {
final Long identifier = instanceManager.getIdentifierForStrongReference(webChromeClient);
if (identifier == null) {
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java
index 0f50c82..7b5241e 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebChromeClientHostApiImpl.java
@@ -29,20 +29,17 @@
/**
* Implementation of {@link WebChromeClient} that passes arguments of callback methods to Dart.
*/
- public static class WebChromeClientImpl extends WebChromeClient implements Releasable {
- @Nullable private WebChromeClientFlutterApiImpl flutterApi;
- private WebViewClient webViewClient;
+ public static class WebChromeClientImpl extends WebChromeClient {
+ private final WebChromeClientFlutterApiImpl flutterApi;
+ @Nullable private WebViewClient webViewClient;
/**
* Creates a {@link WebChromeClient} that passes arguments of callbacks methods to Dart.
*
* @param flutterApi handles sending messages to Dart
- * @param webViewClient receives forwarded calls from {@link WebChromeClient#onCreateWindow}
*/
- public WebChromeClientImpl(
- @NonNull WebChromeClientFlutterApiImpl flutterApi, WebViewClient webViewClient) {
+ public WebChromeClientImpl(@NonNull WebChromeClientFlutterApiImpl flutterApi) {
this.flutterApi = flutterApi;
- this.webViewClient = webViewClient;
}
@Override
@@ -67,6 +64,14 @@
@VisibleForTesting
boolean onCreateWindow(
final WebView view, Message resultMsg, @Nullable WebView onCreateWindowWebView) {
+ // WebChromeClient requires a WebViewClient because of a bug fix that makes
+ // calls to WebViewClient.requestLoading/WebViewClient.urlLoading when a new
+ // window is opened. This is to make sure a url opened by `Window.open` has
+ // a secure url.
+ if (webViewClient == null) {
+ return false;
+ }
+
final WebViewClient windowWebViewClient =
new WebViewClient() {
@RequiresApi(api = Build.VERSION_CODES.N)
@@ -102,9 +107,7 @@
@Override
public void onProgressChanged(WebView view, int progress) {
- if (flutterApi != null) {
- flutterApi.onProgressChanged(this, view, (long) progress, reply -> {});
- }
+ flutterApi.onProgressChanged(this, view, (long) progress, reply -> {});
}
/**
@@ -113,17 +116,9 @@
*
* @param webViewClient the forwarding {@link WebViewClient}
*/
- public void setWebViewClient(WebViewClient webViewClient) {
+ public void setWebViewClient(@NonNull WebViewClient webViewClient) {
this.webViewClient = webViewClient;
}
-
- @Override
- public void release() {
- if (flutterApi != null) {
- flutterApi.dispose(this, reply -> {});
- }
- flutterApi = null;
- }
}
/** Handles creating {@link WebChromeClient}s for a {@link WebChromeClientHostApiImpl}. */
@@ -132,12 +127,10 @@
* Creates a {@link DownloadListenerHostApiImpl.DownloadListenerImpl}.
*
* @param flutterApi handles sending messages to Dart
- * @param webViewClient receives forwarded calls from {@link WebChromeClient#onCreateWindow}
- * @return the created {@link DownloadListenerHostApiImpl.DownloadListenerImpl}
+ * @return the created {@link WebChromeClientHostApiImpl.WebChromeClientImpl}
*/
- public WebChromeClientImpl createWebChromeClient(
- WebChromeClientFlutterApiImpl flutterApi, WebViewClient webViewClient) {
- return new WebChromeClientImpl(flutterApi, webViewClient);
+ public WebChromeClientImpl createWebChromeClient(WebChromeClientFlutterApiImpl flutterApi) {
+ return new WebChromeClientImpl(flutterApi);
}
}
@@ -158,11 +151,9 @@
}
@Override
- public void create(Long instanceId, Long webViewClientInstanceId) {
- final WebViewClient webViewClient =
- (WebViewClient) instanceManager.getInstance(webViewClientInstanceId);
+ public void create(Long instanceId) {
final WebChromeClient webChromeClient =
- webChromeClientCreator.createWebChromeClient(flutterApi, webViewClient);
+ webChromeClientCreator.createWebChromeClient(flutterApi);
instanceManager.addDartCreatedInstance(webChromeClient, instanceId);
}
}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java
index 5b6f9e7..98fd4fc 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebSettingsHostApiImpl.java
@@ -50,11 +50,6 @@
}
@Override
- public void dispose(Long instanceId) {
- instanceManager.remove(instanceId);
- }
-
- @Override
public void setDomStorageEnabled(Long instanceId, Boolean flag) {
final WebSettings webSettings = (WebSettings) instanceManager.getInstance(instanceId);
webSettings.setDomStorageEnabled(flag);
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java
index c23e8e7..0dc0bbb 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientFlutterApiImpl.java
@@ -197,20 +197,6 @@
urlLoading(getIdentifierForClient(webViewClient), webViewIdentifier, urlArg, callback);
}
- /**
- * Communicates to Dart that the reference to a {@link WebViewClient} was removed.
- *
- * @param webViewClient the instance whose reference will be removed
- * @param callback reply callback with return value from Dart
- */
- public void dispose(WebViewClient webViewClient, Reply<Void> callback) {
- if (instanceManager.containsInstance(webViewClient)) {
- dispose(getIdentifierForClient(webViewClient), callback);
- } else {
- callback.reply(null);
- }
- }
-
private long getIdentifierForClient(WebViewClient webViewClient) {
final Long identifier = instanceManager.getIdentifierForStrongReference(webViewClient);
if (identifier == null) {
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java
index 4833ee9..09a34f2 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewClientHostApiImpl.java
@@ -14,10 +14,10 @@
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.webkit.WebResourceErrorCompat;
import androidx.webkit.WebViewClientCompat;
+import java.util.Objects;
/**
* Host api implementation for {@link WebViewClient}.
@@ -29,73 +29,53 @@
private final WebViewClientCreator webViewClientCreator;
private final WebViewClientFlutterApiImpl flutterApi;
- /**
- * An interface implemented by a class that extends {@link WebViewClient} and {@link Releasable}.
- */
- public interface ReleasableWebViewClient extends Releasable {}
-
/** Implementation of {@link WebViewClient} that passes arguments of callback methods to Dart. */
@RequiresApi(Build.VERSION_CODES.N)
- public static class WebViewClientImpl extends WebViewClient implements ReleasableWebViewClient {
- @Nullable private WebViewClientFlutterApiImpl flutterApi;
- private final boolean shouldOverrideUrlLoading;
+ public static class WebViewClientImpl extends WebViewClient {
+ private final WebViewClientFlutterApiImpl flutterApi;
+ private boolean returnValueForShouldOverrideUrlLoading = false;
/**
* Creates a {@link WebViewClient} that passes arguments of callbacks methods to Dart.
*
* @param flutterApi handles sending messages to Dart
- * @param shouldOverrideUrlLoading whether loading a url should be overridden
*/
- public WebViewClientImpl(
- @NonNull WebViewClientFlutterApiImpl flutterApi, boolean shouldOverrideUrlLoading) {
- this.shouldOverrideUrlLoading = shouldOverrideUrlLoading;
+ public WebViewClientImpl(@NonNull WebViewClientFlutterApiImpl flutterApi) {
this.flutterApi = flutterApi;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
- if (flutterApi != null) {
- flutterApi.onPageStarted(this, view, url, reply -> {});
- }
+ flutterApi.onPageStarted(this, view, url, reply -> {});
}
@Override
public void onPageFinished(WebView view, String url) {
- if (flutterApi != null) {
- flutterApi.onPageFinished(this, view, url, reply -> {});
- }
+ flutterApi.onPageFinished(this, view, url, reply -> {});
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
- if (flutterApi != null) {
- flutterApi.onReceivedRequestError(this, view, request, error, reply -> {});
- }
+ flutterApi.onReceivedRequestError(this, view, request, error, reply -> {});
}
@Override
public void onReceivedError(
WebView view, int errorCode, String description, String failingUrl) {
- if (flutterApi != null) {
- flutterApi.onReceivedError(
- this, view, (long) errorCode, description, failingUrl, reply -> {});
- }
+ flutterApi.onReceivedError(
+ this, view, (long) errorCode, description, failingUrl, reply -> {});
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
- if (flutterApi != null) {
- flutterApi.requestLoading(this, view, request, reply -> {});
- }
- return shouldOverrideUrlLoading;
+ flutterApi.requestLoading(this, view, request, reply -> {});
+ return returnValueForShouldOverrideUrlLoading;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- if (flutterApi != null) {
- flutterApi.urlLoading(this, view, url, reply -> {});
- }
- return shouldOverrideUrlLoading;
+ flutterApi.urlLoading(this, view, url, reply -> {});
+ return returnValueForShouldOverrideUrlLoading;
}
@Override
@@ -105,11 +85,9 @@
// truly lost.
}
- public void release() {
- if (flutterApi != null) {
- flutterApi.dispose(this, reply -> {});
- }
- flutterApi = null;
+ /** Sets return value for {@link #shouldOverrideUrlLoading}. */
+ public void setReturnValueForShouldOverrideUrlLoading(boolean value) {
+ returnValueForShouldOverrideUrlLoading = value;
}
}
@@ -117,29 +95,22 @@
* Implementation of {@link WebViewClientCompat} that passes arguments of callback methods to
* Dart.
*/
- public static class WebViewClientCompatImpl extends WebViewClientCompat
- implements ReleasableWebViewClient {
- private @Nullable WebViewClientFlutterApiImpl flutterApi;
- private final boolean shouldOverrideUrlLoading;
+ public static class WebViewClientCompatImpl extends WebViewClientCompat {
+ private final WebViewClientFlutterApiImpl flutterApi;
+ private boolean returnValueForShouldOverrideUrlLoading = false;
- public WebViewClientCompatImpl(
- @NonNull WebViewClientFlutterApiImpl flutterApi, boolean shouldOverrideUrlLoading) {
- this.shouldOverrideUrlLoading = shouldOverrideUrlLoading;
+ public WebViewClientCompatImpl(@NonNull WebViewClientFlutterApiImpl flutterApi) {
this.flutterApi = flutterApi;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
- if (flutterApi != null) {
- flutterApi.onPageStarted(this, view, url, reply -> {});
- }
+ flutterApi.onPageStarted(this, view, url, reply -> {});
}
@Override
public void onPageFinished(WebView view, String url) {
- if (flutterApi != null) {
- flutterApi.onPageFinished(this, view, url, reply -> {});
- }
+ flutterApi.onPageFinished(this, view, url, reply -> {});
}
// This method is only called when the WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR feature is
@@ -151,36 +122,28 @@
@NonNull WebView view,
@NonNull WebResourceRequest request,
@NonNull WebResourceErrorCompat error) {
- if (flutterApi != null) {
- flutterApi.onReceivedRequestError(this, view, request, error, reply -> {});
- }
+ flutterApi.onReceivedRequestError(this, view, request, error, reply -> {});
}
@Override
public void onReceivedError(
WebView view, int errorCode, String description, String failingUrl) {
- if (flutterApi != null) {
- flutterApi.onReceivedError(
- this, view, (long) errorCode, description, failingUrl, reply -> {});
- }
+ flutterApi.onReceivedError(
+ this, view, (long) errorCode, description, failingUrl, reply -> {});
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(
@NonNull WebView view, @NonNull WebResourceRequest request) {
- if (flutterApi != null) {
- flutterApi.requestLoading(this, view, request, reply -> {});
- }
- return shouldOverrideUrlLoading;
+ flutterApi.requestLoading(this, view, request, reply -> {});
+ return returnValueForShouldOverrideUrlLoading;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
- if (flutterApi != null) {
- flutterApi.urlLoading(this, view, url, reply -> {});
- }
- return shouldOverrideUrlLoading;
+ flutterApi.urlLoading(this, view, url, reply -> {});
+ return returnValueForShouldOverrideUrlLoading;
}
@Override
@@ -190,11 +153,9 @@
// truly lost.
}
- public void release() {
- if (flutterApi != null) {
- flutterApi.dispose(this, reply -> {});
- }
- flutterApi = null;
+ /** Sets return value for {@link #shouldOverrideUrlLoading}. */
+ public void setReturnValueForShouldOverrideUrlLoading(boolean value) {
+ returnValueForShouldOverrideUrlLoading = value;
}
}
@@ -206,8 +167,7 @@
* @param flutterApi handles sending messages to Dart
* @return the created {@link WebViewClient}
*/
- public WebViewClient createWebViewClient(
- WebViewClientFlutterApiImpl flutterApi, boolean shouldOverrideUrlLoading) {
+ public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi) {
// WebViewClientCompat is used to get
// shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
// invoked by the webview on older Android devices, without it pages that use iframes will
@@ -217,9 +177,9 @@
// to bug https://bugs.chromium.org/p/chromium/issues/detail?id=925887. Also, see
// https://github.com/flutter/flutter/issues/29446.
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- return new WebViewClientImpl(flutterApi, shouldOverrideUrlLoading);
+ return new WebViewClientImpl(flutterApi);
} else {
- return new WebViewClientCompatImpl(flutterApi, shouldOverrideUrlLoading);
+ return new WebViewClientCompatImpl(flutterApi);
}
}
}
@@ -241,9 +201,24 @@
}
@Override
- public void create(Long instanceId, Boolean shouldOverrideUrlLoading) {
- final WebViewClient webViewClient =
- webViewClientCreator.createWebViewClient(flutterApi, shouldOverrideUrlLoading);
+ public void create(@NonNull Long instanceId) {
+ final WebViewClient webViewClient = webViewClientCreator.createWebViewClient(flutterApi);
instanceManager.addDartCreatedInstance(webViewClient, instanceId);
}
+
+ @Override
+ public void setSynchronousReturnValueForShouldOverrideUrlLoading(
+ @NonNull Long instanceId, @NonNull Boolean value) {
+ final WebViewClient webViewClient =
+ Objects.requireNonNull(instanceManager.getInstance(instanceId));
+ if (webViewClient instanceof WebViewClientCompatImpl) {
+ ((WebViewClientCompatImpl) webViewClient).setReturnValueForShouldOverrideUrlLoading(value);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
+ && webViewClient instanceof WebViewClientImpl) {
+ ((WebViewClientImpl) webViewClient).setReturnValueForShouldOverrideUrlLoading(value);
+ } else {
+ throw new IllegalStateException(
+ "This WebViewClient doesn't support setting the returnValueForShouldOverrideUrlLoading.");
+ }
+ }
}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java
index fe7615c..1c5a550 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java
@@ -17,6 +17,7 @@
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.CookieManagerHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.FlutterAssetManagerHostApi;
+import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaObjectHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebSettingsHostApi;
@@ -77,15 +78,22 @@
Context context,
View containerView,
FlutterAssetManager flutterAssetManager) {
-
- instanceManager = InstanceManager.open(identifier -> {});
+ instanceManager =
+ InstanceManager.open(
+ identifier ->
+ new GeneratedAndroidWebView.JavaObjectFlutterApi(binaryMessenger)
+ .dispose(identifier, reply -> {}));
viewRegistry.registerViewFactory(
"plugins.flutter.io/webview", new FlutterWebViewFactory(instanceManager));
webViewHostApi =
new WebViewHostApiImpl(
- instanceManager, new WebViewHostApiImpl.WebViewProxy(), context, containerView);
+ instanceManager,
+ binaryMessenger,
+ new WebViewHostApiImpl.WebViewProxy(),
+ context,
+ containerView);
javaScriptChannelHostApi =
new JavaScriptChannelHostApiImpl(
instanceManager,
@@ -93,6 +101,7 @@
new JavaScriptChannelFlutterApiImpl(binaryMessenger, instanceManager),
new Handler(context.getMainLooper()));
+ JavaObjectHostApi.setup(binaryMessenger, new JavaObjectHostApiImpl(instanceManager));
WebViewHostApi.setup(binaryMessenger, webViewHostApi);
JavaScriptChannelHostApi.setup(binaryMessenger, javaScriptChannelHostApi);
WebViewClientHostApi.setup(
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java
index 778ad61..2fd9905 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewHostApiImpl.java
@@ -14,12 +14,10 @@
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;
-import io.flutter.plugins.webviewflutter.DownloadListenerHostApiImpl.DownloadListenerImpl;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewHostApi;
import io.flutter.plugins.webviewflutter.WebChromeClientHostApiImpl.WebChromeClientImpl;
-import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.ReleasableWebViewClient;
-import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -33,6 +31,7 @@
private final WebViewProxy webViewProxy;
// Only used with WebView using virtual displays.
@Nullable private final View containerView;
+ private final BinaryMessenger binaryMessenger;
private Context context;
@@ -42,10 +41,14 @@
* Creates a {@link WebViewPlatformView}.
*
* @param context an Activity Context to access application assets
+ * @param binaryMessenger used to communicate with Dart over asynchronous messages
+ * @param instanceManager mangages instances used to communicate with the corresponding objects
+ * in Dart
* @return the created {@link WebViewPlatformView}
*/
- public WebViewPlatformView createWebView(Context context) {
- return new WebViewPlatformView(context);
+ public WebViewPlatformView createWebView(
+ Context context, BinaryMessenger binaryMessenger, InstanceManager instanceManager) {
+ return new WebViewPlatformView(context, binaryMessenger, instanceManager);
}
/**
@@ -56,8 +59,12 @@
* @return the created {@link InputAwareWebViewPlatformView}
*/
public InputAwareWebViewPlatformView createInputAwareWebView(
- Context context, @Nullable View containerView) {
- return new InputAwareWebViewPlatformView(context, containerView);
+ Context context,
+ BinaryMessenger binaryMessenger,
+ InstanceManager instanceManager,
+ @Nullable View containerView) {
+ return new InputAwareWebViewPlatformView(
+ context, binaryMessenger, instanceManager, containerView);
}
/**
@@ -70,51 +77,26 @@
}
}
- private static class ReleasableValue<T extends Releasable> {
- @Nullable private T value;
-
- ReleasableValue() {}
-
- ReleasableValue(@Nullable T value) {
- this.value = value;
- }
-
- void set(@Nullable T newValue) {
- release();
- value = newValue;
- }
-
- @Nullable
- T get() {
- return value;
- }
-
- void release() {
- if (value != null) {
- value.release();
- }
- value = null;
- }
- }
-
/** Implementation of {@link WebView} that can be used as a Flutter {@link PlatformView}s. */
- public static class WebViewPlatformView extends WebView implements PlatformView, Releasable {
- private final ReleasableValue<WebViewClientHostApiImpl.ReleasableWebViewClient>
- currentWebViewClient = new ReleasableValue<>();
- private final ReleasableValue<DownloadListenerImpl> currentDownloadListener =
- new ReleasableValue<>();
- private final ReleasableValue<WebChromeClientImpl> currentWebChromeClient =
- new ReleasableValue<>();
- private final Map<String, ReleasableValue<JavaScriptChannel>> javaScriptInterfaces =
- new HashMap<>();
+ public static class WebViewPlatformView extends WebView implements PlatformView {
+ private WebViewClient currentWebViewClient;
+ private WebChromeClientImpl currentWebChromeClient;
/**
* Creates a {@link WebViewPlatformView}.
*
* @param context an Activity Context to access application assets. This value cannot be null.
*/
- public WebViewPlatformView(Context context) {
+ public WebViewPlatformView(
+ Context context, BinaryMessenger binaryMessenger, InstanceManager instanceManager) {
super(context);
+ currentWebViewClient = new WebViewClient();
+ currentWebChromeClient =
+ new WebChromeClientImpl(
+ new WebChromeClientFlutterApiImpl(binaryMessenger, instanceManager));
+
+ setWebViewClient(currentWebViewClient);
+ setWebChromeClient(currentWebChromeClient);
}
@Override
@@ -130,56 +112,18 @@
@Override
public void setWebViewClient(WebViewClient webViewClient) {
super.setWebViewClient(webViewClient);
- currentWebViewClient.set((ReleasableWebViewClient) webViewClient);
-
- final WebChromeClientImpl webChromeClient = currentWebChromeClient.get();
- if (webChromeClient != null) {
- ((WebChromeClientImpl) webChromeClient).setWebViewClient(webViewClient);
- }
- }
-
- @Override
- public void setDownloadListener(DownloadListener listener) {
- super.setDownloadListener(listener);
- currentDownloadListener.set((DownloadListenerImpl) listener);
+ currentWebViewClient = webViewClient;
+ currentWebChromeClient.setWebViewClient(webViewClient);
}
@Override
public void setWebChromeClient(WebChromeClient client) {
super.setWebChromeClient(client);
- currentWebChromeClient.set((WebChromeClientImpl) client);
- }
-
- @SuppressLint("JavascriptInterface")
- @Override
- public void addJavascriptInterface(Object object, String name) {
- super.addJavascriptInterface(object, name);
- if (object instanceof JavaScriptChannel) {
- final ReleasableValue<JavaScriptChannel> javaScriptChannel = javaScriptInterfaces.get(name);
- if (javaScriptChannel != null && javaScriptChannel.get() != object) {
- javaScriptChannel.release();
- }
- javaScriptInterfaces.put(name, new ReleasableValue<>((JavaScriptChannel) object));
+ if (!(client instanceof WebChromeClientImpl)) {
+ throw new AssertionError("Client must be a WebChromeClientImpl.");
}
- }
-
- @Override
- public void removeJavascriptInterface(@NonNull String name) {
- super.removeJavascriptInterface(name);
- final ReleasableValue<JavaScriptChannel> javaScriptChannel = javaScriptInterfaces.get(name);
- javaScriptChannel.release();
- javaScriptInterfaces.remove(name);
- }
-
- @Override
- public void release() {
- currentWebViewClient.release();
- currentDownloadListener.release();
- currentWebChromeClient.release();
- for (ReleasableValue<JavaScriptChannel> channel : javaScriptInterfaces.values()) {
- channel.release();
- }
- javaScriptInterfaces.clear();
+ currentWebChromeClient = (WebChromeClientImpl) client;
+ currentWebChromeClient.setWebViewClient(currentWebViewClient);
}
}
@@ -189,23 +133,28 @@
*/
@SuppressLint("ViewConstructor")
public static class InputAwareWebViewPlatformView extends InputAwareWebView
- implements PlatformView, Releasable {
- private final ReleasableValue<WebViewClientHostApiImpl.ReleasableWebViewClient>
- currentWebViewClient = new ReleasableValue<>();
- private final ReleasableValue<DownloadListenerImpl> currentDownloadListener =
- new ReleasableValue<>();
- private final ReleasableValue<WebChromeClientImpl> currentWebChromeClient =
- new ReleasableValue<>();
- private final Map<String, ReleasableValue<JavaScriptChannel>> javaScriptInterfaces =
- new HashMap<>();
+ implements PlatformView {
+ private WebViewClient currentWebViewClient;
+ private WebChromeClientImpl currentWebChromeClient;
/**
* Creates a {@link InputAwareWebViewPlatformView}.
*
* @param context an Activity Context to access application assets. This value cannot be null.
*/
- public InputAwareWebViewPlatformView(Context context, View containerView) {
+ public InputAwareWebViewPlatformView(
+ Context context,
+ BinaryMessenger binaryMessenger,
+ InstanceManager instanceManager,
+ View containerView) {
super(context, containerView);
+ currentWebViewClient = new WebViewClient();
+ currentWebChromeClient =
+ new WebChromeClientImpl(
+ new WebChromeClientFlutterApiImpl(binaryMessenger, instanceManager));
+
+ setWebViewClient(currentWebViewClient);
+ setWebChromeClient(currentWebChromeClient);
}
@Override
@@ -242,56 +191,18 @@
@Override
public void setWebViewClient(WebViewClient webViewClient) {
super.setWebViewClient(webViewClient);
- currentWebViewClient.set((ReleasableWebViewClient) webViewClient);
-
- final WebChromeClientImpl webChromeClient = currentWebChromeClient.get();
- if (webChromeClient != null) {
- webChromeClient.setWebViewClient(webViewClient);
- }
- }
-
- @Override
- public void setDownloadListener(DownloadListener listener) {
- super.setDownloadListener(listener);
- currentDownloadListener.set((DownloadListenerImpl) listener);
+ currentWebViewClient = webViewClient;
+ currentWebChromeClient.setWebViewClient(webViewClient);
}
@Override
public void setWebChromeClient(WebChromeClient client) {
super.setWebChromeClient(client);
- currentWebChromeClient.set((WebChromeClientImpl) client);
- }
-
- @SuppressLint("JavascriptInterface")
- @Override
- public void addJavascriptInterface(Object object, String name) {
- super.addJavascriptInterface(object, name);
- if (object instanceof JavaScriptChannel) {
- final ReleasableValue<JavaScriptChannel> javaScriptChannel = javaScriptInterfaces.get(name);
- if (javaScriptChannel != null && javaScriptChannel.get() != object) {
- javaScriptChannel.release();
- }
- javaScriptInterfaces.put(name, new ReleasableValue<>((JavaScriptChannel) object));
+ if (!(client instanceof WebChromeClientImpl)) {
+ throw new AssertionError("Client must be a WebChromeClientImpl.");
}
- }
-
- @Override
- public void removeJavascriptInterface(@NonNull String name) {
- super.removeJavascriptInterface(name);
- final ReleasableValue<JavaScriptChannel> javaScriptChannel = javaScriptInterfaces.get(name);
- javaScriptChannel.release();
- javaScriptInterfaces.remove(name);
- }
-
- @Override
- public void release() {
- currentWebViewClient.release();
- currentDownloadListener.release();
- currentWebChromeClient.release();
- for (ReleasableValue<JavaScriptChannel> channel : javaScriptInterfaces.values()) {
- channel.release();
- }
- javaScriptInterfaces.clear();
+ currentWebChromeClient = (WebChromeClientImpl) client;
+ currentWebChromeClient.setWebViewClient(currentWebViewClient);
}
}
@@ -299,16 +210,19 @@
* Creates a host API that handles creating {@link WebView}s and invoking its methods.
*
* @param instanceManager maintains instances stored to communicate with Dart objects
+ * @param binaryMessenger used to communicate with Dart over asynchronous messages
* @param webViewProxy handles creating {@link WebView}s and calling its static methods
* @param context an Activity Context to access application assets. This value cannot be null.
* @param containerView parent of the webView
*/
public WebViewHostApiImpl(
InstanceManager instanceManager,
+ BinaryMessenger binaryMessenger,
WebViewProxy webViewProxy,
Context context,
@Nullable View containerView) {
this.instanceManager = instanceManager;
+ this.binaryMessenger = binaryMessenger;
this.webViewProxy = webViewProxy;
this.context = context;
this.containerView = containerView;
@@ -332,23 +246,15 @@
final WebView webView =
useHybridComposition
- ? webViewProxy.createWebView(context)
- : webViewProxy.createInputAwareWebView(context, containerView);
+ ? webViewProxy.createWebView(context, binaryMessenger, instanceManager)
+ : webViewProxy.createInputAwareWebView(
+ context, binaryMessenger, instanceManager, containerView);
displayListenerProxy.onPostWebViewInitialization(displayManager);
instanceManager.addDartCreatedInstance(webView, instanceId);
}
@Override
- public void dispose(Long instanceId) {
- final WebView instance = (WebView) instanceManager.getInstance(instanceId);
- if (instance != null) {
- ((Releasable) instance).release();
- instanceManager.remove(instanceId);
- }
- }
-
- @Override
public void loadData(Long instanceId, String data, String mimeType, String encoding) {
final WebView webView = (WebView) instanceManager.getInstance(instanceId);
webView.loadData(data, mimeType, encoding);
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java
index da25dac..caffbb9 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/DownloadListenerTest.java
@@ -6,11 +6,8 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import android.webkit.DownloadListener;
import io.flutter.plugins.webviewflutter.DownloadListenerHostApiImpl.DownloadListenerCreator;
import io.flutter.plugins.webviewflutter.DownloadListenerHostApiImpl.DownloadListenerImpl;
import org.junit.After;
@@ -67,11 +64,5 @@
eq("mimetype"),
eq(54L),
any());
-
- reset(mockFlutterApi);
- downloadListener.release();
- downloadListener.onDownloadStart("", "", "", "", 23);
- verify(mockFlutterApi, never())
- .onDownloadStart((DownloadListener) any(), any(), any(), any(), any(), eq(23), any());
}
}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java
index 4bde211..c9a5e64 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/JavaScriptChannelTest.java
@@ -6,8 +6,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import android.os.Handler;
@@ -62,10 +60,5 @@
public void postMessage() {
javaScriptChannel.postMessage("A message post.");
verify(mockFlutterApi).postMessage(eq(javaScriptChannel), eq("A message post."), any());
-
- reset(mockFlutterApi);
- javaScriptChannel.release();
- javaScriptChannel.postMessage("a message");
- verify(mockFlutterApi, never()).postMessage((JavaScriptChannel) any(), any(), any());
}
}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java
index 03d48d1..e821537 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebChromeClientTest.java
@@ -10,13 +10,11 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.net.Uri;
import android.os.Message;
-import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebView.WebViewTransport;
@@ -50,21 +48,20 @@
instanceManager = InstanceManager.open(identifier -> {});
instanceManager.addDartCreatedInstance(mockWebView, 0L);
- instanceManager.addDartCreatedInstance(mockWebViewClient, 1L);
final WebChromeClientCreator webChromeClientCreator =
new WebChromeClientCreator() {
@Override
public WebChromeClientImpl createWebChromeClient(
- WebChromeClientFlutterApiImpl flutterApi, WebViewClient webViewClient) {
- webChromeClient = super.createWebChromeClient(flutterApi, webViewClient);
+ WebChromeClientFlutterApiImpl flutterApi) {
+ webChromeClient = super.createWebChromeClient(flutterApi);
return webChromeClient;
}
};
hostApiImpl =
new WebChromeClientHostApiImpl(instanceManager, webChromeClientCreator, mockFlutterApi);
- hostApiImpl.create(2L, 1L);
+ hostApiImpl.create(2L);
}
@After
@@ -76,11 +73,6 @@
public void onProgressChanged() {
webChromeClient.onProgressChanged(mockWebView, 23);
verify(mockFlutterApi).onProgressChanged(eq(webChromeClient), eq(mockWebView), eq(23L), any());
-
- reset(mockFlutterApi);
- webChromeClient.release();
- webChromeClient.onProgressChanged(mockWebView, 11);
- verify(mockFlutterApi, never()).onProgressChanged((WebChromeClient) any(), any(), any(), any());
}
@Test
@@ -91,6 +83,7 @@
final Message message = new Message();
message.obj = mock(WebViewTransport.class);
+ webChromeClient.setWebViewClient(mockWebViewClient);
assertTrue(webChromeClient.onCreateWindow(mockWebView, message, mockOnCreateWindowWebView));
/// Capture the WebViewClient used with onCreateWindow WebView.
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java
index 5d0cb70..3267291 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewClientTest.java
@@ -8,8 +8,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -35,6 +33,8 @@
@Mock public WebView mockWebView;
+ @Mock public WebViewClientCompatImpl mockWebViewClient;
+
InstanceManager instanceManager;
WebViewClientHostApiImpl hostApiImpl;
WebViewClientCompatImpl webViewClient;
@@ -48,18 +48,15 @@
final WebViewClientCreator webViewClientCreator =
new WebViewClientCreator() {
@Override
- public WebViewClient createWebViewClient(
- WebViewClientFlutterApiImpl flutterApi, boolean shouldOverrideUrlLoading) {
- webViewClient =
- (WebViewClientCompatImpl)
- super.createWebViewClient(flutterApi, shouldOverrideUrlLoading);
+ public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi) {
+ webViewClient = (WebViewClientCompatImpl) super.createWebViewClient(flutterApi);
return webViewClient;
}
};
hostApiImpl =
new WebViewClientHostApiImpl(instanceManager, webViewClientCreator, mockFlutterApi);
- hostApiImpl.create(1L, true);
+ hostApiImpl.create(1L);
}
@After
@@ -72,11 +69,6 @@
webViewClient.onPageStarted(mockWebView, "https://www.google.com", null);
verify(mockFlutterApi)
.onPageStarted(eq(webViewClient), eq(mockWebView), eq("https://www.google.com"), any());
-
- reset(mockFlutterApi);
- webViewClient.release();
- webViewClient.onPageStarted(mockWebView, "", null);
- verify(mockFlutterApi, never()).onPageStarted((WebViewClient) any(), any(), any(), any());
}
@Test
@@ -90,12 +82,6 @@
eq("description"),
eq("https://www.google.com"),
any());
-
- reset(mockFlutterApi);
- webViewClient.release();
- webViewClient.onReceivedError(mockWebView, 33, "", "");
- verify(mockFlutterApi, never())
- .onReceivedError((WebViewClient) any(), any(), any(), any(), any(), any());
}
@Test
@@ -103,11 +89,6 @@
webViewClient.shouldOverrideUrlLoading(mockWebView, "https://www.google.com");
verify(mockFlutterApi)
.urlLoading(eq(webViewClient), eq(mockWebView), eq("https://www.google.com"), any());
-
- reset(mockFlutterApi);
- webViewClient.release();
- webViewClient.shouldOverrideUrlLoading(mockWebView, "");
- verify(mockFlutterApi, never()).urlLoading((WebViewClient) any(), any(), any(), any());
}
@Test
@@ -125,4 +106,23 @@
WebViewClientFlutterApiImpl.createWebResourceRequestData(mockRequest);
assertEquals(data.getRequestHeaders(), new HashMap<String, String>());
}
+
+ @Test
+ public void setReturnValueForShouldOverrideUrlLoading() {
+ final WebViewClientHostApiImpl webViewClientHostApi =
+ new WebViewClientHostApiImpl(
+ instanceManager,
+ new WebViewClientCreator() {
+ @Override
+ public WebViewClient createWebViewClient(WebViewClientFlutterApiImpl flutterApi) {
+ return mockWebViewClient;
+ }
+ },
+ mockFlutterApi);
+
+ instanceManager.addDartCreatedInstance(mockWebViewClient, 0);
+ webViewClientHostApi.setSynchronousReturnValueForShouldOverrideUrlLoading(0L, false);
+
+ verify(mockWebViewClient).setReturnValueForShouldOverrideUrlLoading(false);
+ }
}
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java
index 30bc256..ecaab77 100644
--- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebViewTest.java
@@ -15,10 +15,7 @@
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebViewClient;
-import io.flutter.plugins.webviewflutter.DownloadListenerHostApiImpl.DownloadListenerImpl;
-import io.flutter.plugins.webviewflutter.WebChromeClientHostApiImpl.WebChromeClientImpl;
-import io.flutter.plugins.webviewflutter.WebViewClientHostApiImpl.WebViewClientImpl;
-import io.flutter.plugins.webviewflutter.WebViewHostApiImpl.InputAwareWebViewPlatformView;
+import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.webviewflutter.WebViewHostApiImpl.WebViewPlatformView;
import java.util.HashMap;
import org.junit.After;
@@ -39,6 +36,8 @@
@Mock Context mockContext;
+ @Mock BinaryMessenger mockBinaryMessenger;
+
InstanceManager testInstanceManager;
WebViewHostApiImpl testHostApiImpl;
@@ -46,9 +45,11 @@
public void setUp() {
testInstanceManager = InstanceManager.open(identifier -> {});
- when(mockWebViewProxy.createWebView(mockContext)).thenReturn(mockWebView);
+ when(mockWebViewProxy.createWebView(mockContext, mockBinaryMessenger, testInstanceManager))
+ .thenReturn(mockWebView);
testHostApiImpl =
- new WebViewHostApiImpl(testInstanceManager, mockWebViewProxy, mockContext, null);
+ new WebViewHostApiImpl(
+ testInstanceManager, mockBinaryMessenger, mockWebViewProxy, mockContext, null);
testHostApiImpl.create(0L, true);
}
@@ -58,112 +59,6 @@
}
@Test
- public void releaseWebView() {
- final WebViewPlatformView webView = new WebViewPlatformView(mockContext);
-
- final WebViewClientImpl mockWebViewClient = mock(WebViewClientImpl.class);
- final WebChromeClientImpl mockWebChromeClient = mock(WebChromeClientImpl.class);
- final DownloadListenerImpl mockDownloadListener = mock(DownloadListenerImpl.class);
- final JavaScriptChannel mockJavaScriptChannel = mock(JavaScriptChannel.class);
-
- webView.setWebViewClient(mockWebViewClient);
- webView.setWebChromeClient(mockWebChromeClient);
- webView.setDownloadListener(mockDownloadListener);
- webView.addJavascriptInterface(mockJavaScriptChannel, "jchannel");
-
- webView.release();
-
- verify(mockWebViewClient).release();
- verify(mockWebChromeClient).release();
- verify(mockDownloadListener).release();
- verify(mockJavaScriptChannel).release();
- }
-
- @Test
- public void releaseWebViewDependents() {
- final WebViewPlatformView webView = new WebViewPlatformView(mockContext);
-
- final WebViewClientImpl mockWebViewClient = mock(WebViewClientImpl.class);
- final WebChromeClientImpl mockWebChromeClient = mock(WebChromeClientImpl.class);
- final DownloadListenerImpl mockDownloadListener = mock(DownloadListenerImpl.class);
- final JavaScriptChannel mockJavaScriptChannel = mock(JavaScriptChannel.class);
- final JavaScriptChannel mockJavaScriptChannel2 = mock(JavaScriptChannel.class);
-
- webView.setWebViewClient(mockWebViewClient);
- webView.setWebChromeClient(mockWebChromeClient);
- webView.setDownloadListener(mockDownloadListener);
- webView.addJavascriptInterface(mockJavaScriptChannel, "jchannel");
-
- // Release should be called on the object added above.
- webView.addJavascriptInterface(mockJavaScriptChannel2, "jchannel");
- verify(mockJavaScriptChannel).release();
-
- webView.setWebViewClient(null);
- webView.setWebChromeClient(null);
- webView.setDownloadListener(null);
- webView.removeJavascriptInterface("jchannel");
-
- verify(mockWebViewClient).release();
- verify(mockWebChromeClient).release();
- verify(mockDownloadListener).release();
- verify(mockJavaScriptChannel2).release();
- }
-
- @Test
- public void releaseInputAwareWebView() {
- final InputAwareWebViewPlatformView webView =
- new InputAwareWebViewPlatformView(mockContext, null);
-
- final WebViewClientImpl mockWebViewClient = mock(WebViewClientImpl.class);
- final WebChromeClientImpl mockWebChromeClient = mock(WebChromeClientImpl.class);
- final DownloadListenerImpl mockDownloadListener = mock(DownloadListenerImpl.class);
- final JavaScriptChannel mockJavaScriptChannel = mock(JavaScriptChannel.class);
-
- webView.setWebViewClient(mockWebViewClient);
- webView.setWebChromeClient(mockWebChromeClient);
- webView.setDownloadListener(mockDownloadListener);
- webView.addJavascriptInterface(mockJavaScriptChannel, "jchannel");
-
- webView.release();
-
- verify(mockWebViewClient).release();
- verify(mockWebChromeClient).release();
- verify(mockDownloadListener).release();
- verify(mockJavaScriptChannel).release();
- }
-
- @Test
- public void releaseInputAwareWebViewDependents() {
- final InputAwareWebViewPlatformView webView =
- new InputAwareWebViewPlatformView(mockContext, null);
-
- final WebViewClientImpl mockWebViewClient = mock(WebViewClientImpl.class);
- final WebChromeClientImpl mockWebChromeClient = mock(WebChromeClientImpl.class);
- final DownloadListenerImpl mockDownloadListener = mock(DownloadListenerImpl.class);
- final JavaScriptChannel mockJavaScriptChannel = mock(JavaScriptChannel.class);
- final JavaScriptChannel mockJavaScriptChannel2 = mock(JavaScriptChannel.class);
-
- webView.setWebViewClient(mockWebViewClient);
- webView.setWebChromeClient(mockWebChromeClient);
- webView.setDownloadListener(mockDownloadListener);
- webView.addJavascriptInterface(mockJavaScriptChannel, "jchannel");
-
- // Release should be called on the object added above.
- webView.addJavascriptInterface(mockJavaScriptChannel2, "jchannel");
- verify(mockJavaScriptChannel).release();
-
- webView.setWebViewClient(null);
- webView.setWebChromeClient(null);
- webView.setDownloadListener(null);
- webView.removeJavascriptInterface("jchannel");
-
- verify(mockWebViewClient).release();
- verify(mockWebChromeClient).release();
- verify(mockDownloadListener).release();
- verify(mockJavaScriptChannel2).release();
- }
-
- @Test
public void loadData() {
testHostApiImpl.loadData(
0L, "VGhpcyBkYXRhIGlzIGJhc2U2NCBlbmNvZGVkLg==", "text/plain", "base64");
diff --git a/packages/webview_flutter/webview_flutter_android/example/integration_test/legacy/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_android/example/integration_test/legacy/webview_flutter_test.dart
new file mode 100644
index 0000000..57d3399
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/example/integration_test/legacy/webview_flutter_test.dart
@@ -0,0 +1,1567 @@
+// 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.
+
+// This test is run using `flutter drive` by the CI (see /script/tool/README.md
+// in this repository for details on driving that tooling manually), but can
+// also be run using `flutter test` directly during development.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+// TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231)
+// ignore: unnecessary_import
+import 'dart:typed_data';
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+import 'package:webview_flutter_android/src/instance_manager.dart';
+import 'package:webview_flutter_android/src/weak_reference_utils.dart';
+import 'package:webview_flutter_android/src/webview_flutter_android_legacy.dart';
+import 'package:webview_flutter_android_example/legacy/navigation_decision.dart';
+import 'package:webview_flutter_android_example/legacy/navigation_request.dart';
+import 'package:webview_flutter_android_example/legacy/web_view.dart';
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
+
+Future<void> main() async {
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+ final HttpServer server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
+ server.forEach((HttpRequest request) {
+ if (request.uri.path == '/hello.txt') {
+ request.response.writeln('Hello, world.');
+ } else if (request.uri.path == '/secondary.txt') {
+ request.response.writeln('How are you today?');
+ } else if (request.uri.path == '/headers') {
+ request.response.writeln('${request.headers}');
+ } else if (request.uri.path == '/favicon.ico') {
+ request.response.statusCode = HttpStatus.notFound;
+ } else {
+ fail('unexpected request: ${request.method} ${request.uri}');
+ }
+ request.response.close();
+ });
+ final String prefixUrl = 'http://${server.address.address}:${server.port}';
+ final String primaryUrl = '$prefixUrl/hello.txt';
+ final String secondaryUrl = '$prefixUrl/secondary.txt';
+ final String headersUrl = '$prefixUrl/headers';
+
+ testWidgets('initialUrl', (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final Completer<void> pageFinishedCompleter = Completer<void>();
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: primaryUrl,
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ onPageFinished: pageFinishedCompleter.complete,
+ ),
+ ),
+ ),
+ );
+
+ final WebViewController controller = await controllerCompleter.future;
+ await pageFinishedCompleter.future;
+
+ final String? currentUrl = await controller.currentUrl();
+ expect(currentUrl, primaryUrl);
+ });
+
+ testWidgets('loadUrl', (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final StreamController<String> pageLoads = StreamController<String>();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: primaryUrl,
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ onPageFinished: (String url) {
+ pageLoads.add(url);
+ },
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+
+ await controller.loadUrl(secondaryUrl);
+ await expectLater(
+ pageLoads.stream.firstWhere((String url) => url == secondaryUrl),
+ completion(secondaryUrl),
+ );
+ });
+
+ testWidgets(
+ 'withWeakRefenceTo allows encapsulating class to be garbage collected',
+ (WidgetTester tester) async {
+ final Completer<int> gcCompleter = Completer<int>();
+ final InstanceManager instanceManager = InstanceManager(
+ onWeakReferenceRemoved: gcCompleter.complete,
+ );
+
+ ClassWithCallbackClass? instance = ClassWithCallbackClass();
+ instanceManager.addHostCreatedInstance(instance.callbackClass, 0);
+ instance = null;
+
+ // Force garbage collection.
+ await IntegrationTestWidgetsFlutterBinding.instance
+ .watchPerformance(() async {
+ await tester.pumpAndSettle();
+ });
+
+ final int gcIdentifier = await gcCompleter.future;
+ expect(gcIdentifier, 0);
+ }, timeout: const Timeout(Duration(seconds: 10)));
+
+ testWidgets('evaluateJavascript', (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: primaryUrl,
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ final String result = await controller.evaluateJavascript('1 + 1');
+ expect(result, equals('2'));
+ });
+
+ testWidgets('loadUrl with headers', (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final StreamController<String> pageStarts = StreamController<String>();
+ final StreamController<String> pageLoads = StreamController<String>();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: primaryUrl,
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageStarted: (String url) {
+ pageStarts.add(url);
+ },
+ onPageFinished: (String url) {
+ pageLoads.add(url);
+ },
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ final Map<String, String> headers = <String, String>{
+ 'test_header': 'flutter_test_header'
+ };
+ await controller.loadUrl(headersUrl, headers: headers);
+ final String? currentUrl = await controller.currentUrl();
+ expect(currentUrl, headersUrl);
+
+ await pageStarts.stream.firstWhere((String url) => url == currentUrl);
+ await pageLoads.stream.firstWhere((String url) => url == currentUrl);
+
+ final String content = await controller
+ .runJavascriptReturningResult('document.documentElement.innerText');
+ expect(content.contains('flutter_test_header'), isTrue);
+ });
+
+ testWidgets('JavascriptChannel', (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final Completer<void> pageStarted = Completer<void>();
+ final Completer<void> pageLoaded = Completer<void>();
+ final Completer<String> channelCompleter = Completer<String>();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ // This is the data URL for: '<!DOCTYPE html>'
+ initialUrl:
+ 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ javascriptChannels: <JavascriptChannel>{
+ JavascriptChannel(
+ name: 'Echo',
+ onMessageReceived: (JavascriptMessage message) {
+ channelCompleter.complete(message.message);
+ },
+ ),
+ },
+ onPageStarted: (String url) {
+ pageStarted.complete(null);
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ await pageStarted.future;
+ await pageLoaded.future;
+
+ expect(channelCompleter.isCompleted, isFalse);
+ await controller.runJavascript('Echo.postMessage("hello");');
+
+ await expectLater(channelCompleter.future, completion('hello'));
+ });
+
+ testWidgets('resize webview', (WidgetTester tester) async {
+ final Completer<void> initialResizeCompleter = Completer<void>();
+ final Completer<void> buttonTapResizeCompleter = Completer<void>();
+ final Completer<void> onPageFinished = Completer<void>();
+
+ bool resizeButtonTapped = false;
+ await tester.pumpWidget(ResizableWebView(
+ onResize: (_) {
+ if (resizeButtonTapped) {
+ buttonTapResizeCompleter.complete();
+ } else {
+ initialResizeCompleter.complete();
+ }
+ },
+ onPageFinished: () => onPageFinished.complete(),
+ ));
+ await onPageFinished.future;
+ // Wait for a potential call to resize after page is loaded.
+ await initialResizeCompleter.future.timeout(
+ const Duration(seconds: 3),
+ onTimeout: () => null,
+ );
+
+ resizeButtonTapped = true;
+ await tester.tap(find.byKey(const ValueKey<String>('resizeButton')));
+ await tester.pumpAndSettle();
+ expect(buttonTapResizeCompleter.future, completes);
+ });
+
+ testWidgets('set custom userAgent', (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter1 =
+ Completer<WebViewController>();
+ final GlobalKey globalKey = GlobalKey();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: globalKey,
+ initialUrl: 'about:blank',
+ javascriptMode: JavascriptMode.unrestricted,
+ userAgent: 'Custom_User_Agent1',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter1.complete(controller);
+ },
+ ),
+ ),
+ );
+ final WebViewController controller1 = await controllerCompleter1.future;
+ final String customUserAgent1 = await _getUserAgent(controller1);
+ expect(customUserAgent1, 'Custom_User_Agent1');
+ // rebuild the WebView with a different user agent.
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: globalKey,
+ initialUrl: 'about:blank',
+ javascriptMode: JavascriptMode.unrestricted,
+ userAgent: 'Custom_User_Agent2',
+ ),
+ ),
+ );
+
+ final String customUserAgent2 = await _getUserAgent(controller1);
+ expect(customUserAgent2, 'Custom_User_Agent2');
+ });
+
+ testWidgets('use default platform userAgent after webView is rebuilt',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final GlobalKey globalKey = GlobalKey();
+ // Build the webView with no user agent to get the default platform user agent.
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: globalKey,
+ initialUrl: primaryUrl,
+ javascriptMode: JavascriptMode.unrestricted,
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ final String defaultPlatformUserAgent = await _getUserAgent(controller);
+ // rebuild the WebView with a custom user agent.
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: globalKey,
+ initialUrl: 'about:blank',
+ javascriptMode: JavascriptMode.unrestricted,
+ userAgent: 'Custom_User_Agent',
+ ),
+ ),
+ );
+ final String customUserAgent = await _getUserAgent(controller);
+ expect(customUserAgent, 'Custom_User_Agent');
+ // rebuilds the WebView with no user agent.
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: globalKey,
+ initialUrl: 'about:blank',
+ javascriptMode: JavascriptMode.unrestricted,
+ ),
+ ),
+ );
+
+ final String customUserAgent2 = await _getUserAgent(controller);
+ expect(customUserAgent2, defaultPlatformUserAgent);
+ });
+
+ group('Video playback policy', () {
+ late String videoTestBase64;
+ setUpAll(() async {
+ final ByteData videoData =
+ await rootBundle.load('assets/sample_video.mp4');
+ final String base64VideoData =
+ base64Encode(Uint8List.view(videoData.buffer));
+ final String videoTest = '''
+ <!DOCTYPE html><html>
+ <head><title>Video auto play</title>
+ <script type="text/javascript">
+ function play() {
+ var video = document.getElementById("video");
+ video.play();
+ video.addEventListener('timeupdate', videoTimeUpdateHandler, false);
+ }
+ function videoTimeUpdateHandler(e) {
+ var video = document.getElementById("video");
+ VideoTestTime.postMessage(video.currentTime);
+ }
+ function isPaused() {
+ var video = document.getElementById("video");
+ return video.paused;
+ }
+ function isFullScreen() {
+ var video = document.getElementById("video");
+ return video.webkitDisplayingFullscreen;
+ }
+ </script>
+ </head>
+ <body onload="play();">
+ <video controls playsinline autoplay id="video">
+ <source src="data:video/mp4;charset=utf-8;base64,$base64VideoData">
+ </video>
+ </body>
+ </html>
+ ''';
+ videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest));
+ });
+
+ testWidgets('Auto media playback', (WidgetTester tester) async {
+ Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ Completer<void> pageLoaded = Completer<void>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+ ),
+ ),
+ );
+ WebViewController controller = await controllerCompleter.future;
+ await pageLoaded.future;
+
+ String isPaused =
+ await controller.runJavascriptReturningResult('isPaused();');
+ expect(isPaused, _webviewBool(false));
+
+ controllerCompleter = Completer<WebViewController>();
+ pageLoaded = Completer<void>();
+
+ // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ ),
+ ),
+ );
+
+ controller = await controllerCompleter.future;
+ await pageLoaded.future;
+
+ isPaused = await controller.runJavascriptReturningResult('isPaused();');
+ expect(isPaused, _webviewBool(true));
+ });
+
+ testWidgets('Changes to initialMediaPlaybackPolicy are ignored',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ Completer<void> pageLoaded = Completer<void>();
+
+ final GlobalKey key = GlobalKey();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: key,
+ initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ await pageLoaded.future;
+
+ String isPaused =
+ await controller.runJavascriptReturningResult('isPaused();');
+ expect(isPaused, _webviewBool(false));
+
+ pageLoaded = Completer<void>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: key,
+ initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ ),
+ ),
+ );
+
+ await controller.reload();
+
+ await pageLoaded.future;
+
+ isPaused = await controller.runJavascriptReturningResult('isPaused();');
+ expect(isPaused, _webviewBool(false));
+ });
+
+ testWidgets('Video plays inline when allowsInlineMediaPlayback is true',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final Completer<void> pageLoaded = Completer<void>();
+ final Completer<void> videoPlaying = Completer<void>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ javascriptChannels: <JavascriptChannel>{
+ JavascriptChannel(
+ name: 'VideoTestTime',
+ onMessageReceived: (JavascriptMessage message) {
+ final double currentTime = double.parse(message.message);
+ // Let it play for at least 1 second to make sure the related video's properties are set.
+ if (currentTime > 1 && !videoPlaying.isCompleted) {
+ videoPlaying.complete(null);
+ }
+ },
+ ),
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+ allowsInlineMediaPlayback: true,
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ await pageLoaded.future;
+
+ // Pump once to trigger the video play.
+ await tester.pump();
+
+ // Makes sure we get the correct event that indicates the video is actually playing.
+ await videoPlaying.future;
+
+ final String fullScreen =
+ await controller.runJavascriptReturningResult('isFullScreen();');
+ expect(fullScreen, _webviewBool(false));
+ });
+ });
+
+ group('Audio playback policy', () {
+ late String audioTestBase64;
+ setUpAll(() async {
+ final ByteData audioData =
+ await rootBundle.load('assets/sample_audio.ogg');
+ final String base64AudioData =
+ base64Encode(Uint8List.view(audioData.buffer));
+ final String audioTest = '''
+ <!DOCTYPE html><html>
+ <head><title>Audio auto play</title>
+ <script type="text/javascript">
+ function play() {
+ var audio = document.getElementById("audio");
+ audio.play();
+ }
+ function isPaused() {
+ var audio = document.getElementById("audio");
+ return audio.paused;
+ }
+ </script>
+ </head>
+ <body onload="play();">
+ <audio controls id="audio">
+ <source src="data:audio/ogg;charset=utf-8;base64,$base64AudioData">
+ </audio>
+ </body>
+ </html>
+ ''';
+ audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest));
+ });
+
+ testWidgets('Auto media playback', (WidgetTester tester) async {
+ Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ Completer<void> pageStarted = Completer<void>();
+ Completer<void> pageLoaded = Completer<void>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageStarted: (String url) {
+ pageStarted.complete(null);
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+ ),
+ ),
+ );
+ WebViewController controller = await controllerCompleter.future;
+ await pageStarted.future;
+ await pageLoaded.future;
+
+ String isPaused =
+ await controller.runJavascriptReturningResult('isPaused();');
+ expect(isPaused, _webviewBool(false));
+
+ controllerCompleter = Completer<WebViewController>();
+ pageStarted = Completer<void>();
+ pageLoaded = Completer<void>();
+
+ // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageStarted: (String url) {
+ pageStarted.complete(null);
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ ),
+ ),
+ );
+
+ controller = await controllerCompleter.future;
+ await pageStarted.future;
+ await pageLoaded.future;
+
+ isPaused = await controller.runJavascriptReturningResult('isPaused();');
+ expect(isPaused, _webviewBool(true));
+ });
+
+ testWidgets('Changes to initialMediaPlaybackPolicy are ignored',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ Completer<void> pageStarted = Completer<void>();
+ Completer<void> pageLoaded = Completer<void>();
+
+ final GlobalKey key = GlobalKey();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: key,
+ initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageStarted: (String url) {
+ pageStarted.complete(null);
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ await pageStarted.future;
+ await pageLoaded.future;
+
+ String isPaused =
+ await controller.runJavascriptReturningResult('isPaused();');
+ expect(isPaused, _webviewBool(false));
+
+ pageStarted = Completer<void>();
+ pageLoaded = Completer<void>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: key,
+ initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageStarted: (String url) {
+ pageStarted.complete(null);
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ ),
+ ),
+ );
+
+ await controller.reload();
+
+ await pageStarted.future;
+ await pageLoaded.future;
+
+ isPaused = await controller.runJavascriptReturningResult('isPaused();');
+ expect(isPaused, _webviewBool(false));
+ });
+ });
+
+ testWidgets('getTitle', (WidgetTester tester) async {
+ const String getTitleTest = '''
+ <!DOCTYPE html><html>
+ <head><title>Some title</title>
+ </head>
+ <body>
+ </body>
+ </html>
+ ''';
+ final String getTitleTestBase64 =
+ base64Encode(const Utf8Encoder().convert(getTitleTest));
+ final Completer<void> pageStarted = Completer<void>();
+ final Completer<void> pageLoaded = Completer<void>();
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ onPageStarted: (String url) {
+ pageStarted.complete(null);
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ ),
+ ),
+ );
+
+ final WebViewController controller = await controllerCompleter.future;
+ await pageStarted.future;
+ await pageLoaded.future;
+
+ final String? title = await controller.getTitle();
+ expect(title, 'Some title');
+ });
+
+ group('Programmatic Scroll', () {
+ testWidgets('setAndGetScrollPosition', (WidgetTester tester) async {
+ const String scrollTestPage = '''
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <style>
+ body {
+ height: 100%;
+ width: 100%;
+ }
+ #container{
+ width:5000px;
+ height:5000px;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="container"/>
+ </body>
+ </html>
+ ''';
+
+ final String scrollTestPageBase64 =
+ base64Encode(const Utf8Encoder().convert(scrollTestPage));
+
+ final Completer<void> pageLoaded = Completer<void>();
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ initialUrl:
+ 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ ),
+ ),
+ );
+
+ final WebViewController controller = await controllerCompleter.future;
+ await pageLoaded.future;
+
+ await tester.pumpAndSettle(const Duration(seconds: 3));
+
+ int scrollPosX = await controller.getScrollX();
+ int scrollPosY = await controller.getScrollY();
+
+ // Check scrollTo()
+ const int X_SCROLL = 123;
+ const int Y_SCROLL = 321;
+ // Get the initial position; this ensures that scrollTo is actually
+ // changing something, but also gives the native view's scroll position
+ // time to settle.
+ expect(scrollPosX, isNot(X_SCROLL));
+ expect(scrollPosX, isNot(Y_SCROLL));
+
+ await controller.scrollTo(X_SCROLL, Y_SCROLL);
+ scrollPosX = await controller.getScrollX();
+ scrollPosY = await controller.getScrollY();
+ expect(scrollPosX, X_SCROLL);
+ expect(scrollPosY, Y_SCROLL);
+
+ // Check scrollBy() (on top of scrollTo())
+ await controller.scrollBy(X_SCROLL, Y_SCROLL);
+ scrollPosX = await controller.getScrollX();
+ scrollPosY = await controller.getScrollY();
+ expect(scrollPosX, X_SCROLL * 2);
+ expect(scrollPosY, Y_SCROLL * 2);
+ });
+ });
+
+ group('SurfaceAndroidWebView', () {
+ setUpAll(() {
+ WebView.platform = SurfaceAndroidWebView();
+ });
+
+ tearDownAll(() {
+ WebView.platform = AndroidWebView();
+ });
+
+ testWidgets('setAndGetScrollPosition', (WidgetTester tester) async {
+ const String scrollTestPage = '''
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <style>
+ body {
+ height: 100%;
+ width: 100%;
+ }
+ #container{
+ width:5000px;
+ height:5000px;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="container"/>
+ </body>
+ </html>
+ ''';
+
+ final String scrollTestPageBase64 =
+ base64Encode(const Utf8Encoder().convert(scrollTestPage));
+
+ final Completer<void> pageLoaded = Completer<void>();
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ initialUrl:
+ 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ ),
+ ),
+ );
+
+ final WebViewController controller = await controllerCompleter.future;
+ await pageLoaded.future;
+
+ await tester.pumpAndSettle(const Duration(seconds: 3));
+
+ // Check scrollTo()
+ const int X_SCROLL = 123;
+ const int Y_SCROLL = 321;
+
+ await controller.scrollTo(X_SCROLL, Y_SCROLL);
+ int scrollPosX = await controller.getScrollX();
+ int scrollPosY = await controller.getScrollY();
+ expect(X_SCROLL, scrollPosX);
+ expect(Y_SCROLL, scrollPosY);
+
+ // Check scrollBy() (on top of scrollTo())
+ await controller.scrollBy(X_SCROLL, Y_SCROLL);
+ scrollPosX = await controller.getScrollX();
+ scrollPosY = await controller.getScrollY();
+ expect(X_SCROLL * 2, scrollPosX);
+ expect(Y_SCROLL * 2, scrollPosY);
+ });
+
+ testWidgets('inputs are scrolled into view when focused',
+ (WidgetTester tester) async {
+ const String scrollTestPage = '''
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <style>
+ input {
+ margin: 10000px 0;
+ }
+ #viewport {
+ position: fixed;
+ top:0;
+ bottom:0;
+ left:0;
+ right:0;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="viewport"></div>
+ <input type="text" id="inputEl">
+ </body>
+ </html>
+ ''';
+
+ final String scrollTestPageBase64 =
+ base64Encode(const Utf8Encoder().convert(scrollTestPage));
+
+ final Completer<void> pageLoaded = Completer<void>();
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+
+ await tester.runAsync(() async {
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: SizedBox(
+ width: 200,
+ height: 200,
+ child: WebView(
+ initialUrl:
+ 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ ),
+ ),
+ ),
+ );
+ await Future<void>.delayed(const Duration(milliseconds: 20));
+ await tester.pump();
+ });
+
+ final WebViewController controller = await controllerCompleter.future;
+ await pageLoaded.future;
+ final String viewportRectJSON = await _runJavaScriptReturningResult(
+ controller, 'JSON.stringify(viewport.getBoundingClientRect())');
+ final Map<String, dynamic> viewportRectRelativeToViewport =
+ jsonDecode(viewportRectJSON) as Map<String, dynamic>;
+
+ // Check that the input is originally outside of the viewport.
+
+ final String initialInputClientRectJSON =
+ await _runJavaScriptReturningResult(
+ controller, 'JSON.stringify(inputEl.getBoundingClientRect())');
+ final Map<String, dynamic> initialInputClientRectRelativeToViewport =
+ jsonDecode(initialInputClientRectJSON) as Map<String, dynamic>;
+
+ expect(
+ initialInputClientRectRelativeToViewport['bottom'] <=
+ viewportRectRelativeToViewport['bottom'],
+ isFalse);
+
+ await controller.runJavascript('inputEl.focus()');
+
+ // Check that focusing the input brought it into view.
+
+ final String lastInputClientRectJSON =
+ await _runJavaScriptReturningResult(
+ controller, 'JSON.stringify(inputEl.getBoundingClientRect())');
+ final Map<String, dynamic> lastInputClientRectRelativeToViewport =
+ jsonDecode(lastInputClientRectJSON) as Map<String, dynamic>;
+
+ expect(
+ lastInputClientRectRelativeToViewport['top'] >=
+ viewportRectRelativeToViewport['top'],
+ isTrue);
+ expect(
+ lastInputClientRectRelativeToViewport['bottom'] <=
+ viewportRectRelativeToViewport['bottom'],
+ isTrue);
+
+ expect(
+ lastInputClientRectRelativeToViewport['left'] >=
+ viewportRectRelativeToViewport['left'],
+ isTrue);
+ expect(
+ lastInputClientRectRelativeToViewport['right'] <=
+ viewportRectRelativeToViewport['right'],
+ isTrue);
+ });
+ });
+
+ group('NavigationDelegate', () {
+ const String blankPage = '<!DOCTYPE html><head></head><body></body></html>';
+ final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,'
+ '${base64Encode(const Utf8Encoder().convert(blankPage))}';
+
+ testWidgets('can allow requests', (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final StreamController<String> pageLoads =
+ StreamController<String>.broadcast();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: blankPageEncoded,
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ navigationDelegate: (NavigationRequest request) {
+ return (request.url.contains('youtube.com'))
+ ? NavigationDecision.prevent
+ : NavigationDecision.navigate;
+ },
+ onPageFinished: (String url) => pageLoads.add(url),
+ ),
+ ),
+ );
+
+ await pageLoads.stream.first; // Wait for initial page load.
+ final WebViewController controller = await controllerCompleter.future;
+ await controller.runJavascript('location.href = "$secondaryUrl"');
+
+ await pageLoads.stream.first; // Wait for the next page load.
+ final String? currentUrl = await controller.currentUrl();
+ expect(currentUrl, secondaryUrl);
+ });
+
+ testWidgets('onWebResourceError', (WidgetTester tester) async {
+ final Completer<WebResourceError> errorCompleter =
+ Completer<WebResourceError>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: 'https://www.notawebsite..com',
+ onWebResourceError: (WebResourceError error) {
+ errorCompleter.complete(error);
+ },
+ ),
+ ),
+ );
+
+ final WebResourceError error = await errorCompleter.future;
+ expect(error, isNotNull);
+
+ expect(error.errorType, isNotNull);
+ expect(
+ error.failingUrl?.startsWith('https://www.notawebsite..com'), isTrue);
+ });
+
+ testWidgets('onWebResourceError is not called with valid url',
+ (WidgetTester tester) async {
+ final Completer<WebResourceError> errorCompleter =
+ Completer<WebResourceError>();
+ final Completer<void> pageFinishCompleter = Completer<void>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl:
+ 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
+ onWebResourceError: (WebResourceError error) {
+ errorCompleter.complete(error);
+ },
+ onPageFinished: (_) => pageFinishCompleter.complete(),
+ ),
+ ),
+ );
+
+ expect(errorCompleter.future, doesNotComplete);
+ await pageFinishCompleter.future;
+ });
+
+ testWidgets(
+ 'onWebResourceError only called for main frame',
+ (WidgetTester tester) async {
+ const String iframeTest = '''
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>WebResourceError test</title>
+ </head>
+ <body>
+ <iframe src="https://notawebsite..com"></iframe>
+ </body>
+ </html>
+ ''';
+ final String iframeTestBase64 =
+ base64Encode(const Utf8Encoder().convert(iframeTest));
+
+ final Completer<WebResourceError> errorCompleter =
+ Completer<WebResourceError>();
+ final Completer<void> pageFinishCompleter = Completer<void>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl:
+ 'data:text/html;charset=utf-8;base64,$iframeTestBase64',
+ onWebResourceError: (WebResourceError error) {
+ errorCompleter.complete(error);
+ },
+ onPageFinished: (_) => pageFinishCompleter.complete(),
+ ),
+ ),
+ );
+
+ expect(errorCompleter.future, doesNotComplete);
+ await pageFinishCompleter.future;
+ },
+ );
+
+ testWidgets('can block requests', (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final StreamController<String> pageLoads =
+ StreamController<String>.broadcast();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: blankPageEncoded,
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ navigationDelegate: (NavigationRequest request) {
+ return (request.url.contains('youtube.com'))
+ ? NavigationDecision.prevent
+ : NavigationDecision.navigate;
+ },
+ onPageFinished: (String url) => pageLoads.add(url),
+ ),
+ ),
+ );
+
+ await pageLoads.stream.first; // Wait for initial page load.
+ final WebViewController controller = await controllerCompleter.future;
+ await controller
+ .runJavascript('location.href = "https://www.youtube.com/"');
+
+ // There should never be any second page load, since our new URL is
+ // blocked. Still wait for a potential page change for some time in order
+ // to give the test a chance to fail.
+ await pageLoads.stream.first
+ .timeout(const Duration(milliseconds: 500), onTimeout: () => '');
+ final String? currentUrl = await controller.currentUrl();
+ expect(currentUrl, isNot(contains('youtube.com')));
+ });
+
+ testWidgets('supports asynchronous decisions', (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final StreamController<String> pageLoads =
+ StreamController<String>.broadcast();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: blankPageEncoded,
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ navigationDelegate: (NavigationRequest request) async {
+ NavigationDecision decision = NavigationDecision.prevent;
+ decision = await Future<NavigationDecision>.delayed(
+ const Duration(milliseconds: 10),
+ () => NavigationDecision.navigate);
+ return decision;
+ },
+ onPageFinished: (String url) => pageLoads.add(url),
+ ),
+ ),
+ );
+
+ await pageLoads.stream.first; // Wait for initial page load.
+ final WebViewController controller = await controllerCompleter.future;
+ await controller.runJavascript('location.href = "$secondaryUrl"');
+
+ await pageLoads.stream.first; // Wait for second page to load.
+ final String? currentUrl = await controller.currentUrl();
+ expect(currentUrl, secondaryUrl);
+ });
+ });
+
+ testWidgets('launches with gestureNavigationEnabled on iOS',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: SizedBox(
+ width: 400,
+ height: 300,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: primaryUrl,
+ gestureNavigationEnabled: true,
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ ),
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ final String? currentUrl = await controller.currentUrl();
+ expect(currentUrl, primaryUrl);
+ });
+
+ testWidgets('target _blank opens in same window',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final Completer<void> pageLoaded = Completer<void>();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageFinished: (String url) {
+ pageLoaded.complete(null);
+ },
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ await controller.runJavascript('window.open("$primaryUrl", "_blank")');
+ await pageLoaded.future;
+ final String? currentUrl = await controller.currentUrl();
+ expect(currentUrl, primaryUrl);
+ });
+
+ testWidgets(
+ 'can open new window and go back',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ Completer<void> pageLoaded = Completer<void>();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageFinished: (String url) {
+ pageLoaded.complete();
+ },
+ initialUrl: primaryUrl,
+ ),
+ ),
+ );
+ final WebViewController controller = await controllerCompleter.future;
+ expect(controller.currentUrl(), completion(primaryUrl));
+ await pageLoaded.future;
+ pageLoaded = Completer<void>();
+
+ await controller.runJavascript('window.open("$secondaryUrl")');
+ await pageLoaded.future;
+ pageLoaded = Completer<void>();
+ expect(controller.currentUrl(), completion(secondaryUrl));
+
+ expect(controller.canGoBack(), completion(true));
+ await controller.goBack();
+ await pageLoaded.future;
+ await expectLater(controller.currentUrl(), completion(primaryUrl));
+ },
+ );
+
+ testWidgets(
+ 'JavaScript does not run in parent window',
+ (WidgetTester tester) async {
+ const String iframe = '''
+ <!DOCTYPE html>
+ <script>
+ window.onload = () => {
+ window.open(`javascript:
+ var elem = document.createElement("p");
+ elem.innerHTML = "<b>Executed JS in parent origin: " + window.location.origin + "</b>";
+ document.body.append(elem);
+ `);
+ };
+ </script>
+ ''';
+ final String iframeTestBase64 =
+ base64Encode(const Utf8Encoder().convert(iframe));
+
+ final String openWindowTest = '''
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>XSS test</title>
+ </head>
+ <body>
+ <iframe
+ onload="window.iframeLoaded = true;"
+ src="data:text/html;charset=utf-8;base64,$iframeTestBase64"></iframe>
+ </body>
+ </html>
+ ''';
+ final String openWindowTestBase64 =
+ base64Encode(const Utf8Encoder().convert(openWindowTest));
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final Completer<void> pageLoadCompleter = Completer<void>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ javascriptMode: JavascriptMode.unrestricted,
+ initialUrl:
+ 'data:text/html;charset=utf-8;base64,$openWindowTestBase64',
+ onPageFinished: (String url) {
+ pageLoadCompleter.complete();
+ },
+ ),
+ ),
+ );
+
+ final WebViewController controller = await controllerCompleter.future;
+ await pageLoadCompleter.future;
+
+ final String iframeLoaded =
+ await controller.runJavascriptReturningResult('iframeLoaded');
+ expect(iframeLoaded, 'true');
+
+ final String elementText = await controller.runJavascriptReturningResult(
+ 'document.querySelector("p") && document.querySelector("p").textContent',
+ );
+ expect(elementText, 'null');
+ },
+ );
+
+ testWidgets(
+ 'clearCache should clear local storage',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+
+ Completer<void> pageLoadCompleter = Completer<void>();
+
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: primaryUrl,
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageFinished: (_) => pageLoadCompleter.complete(),
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ ),
+ ),
+ );
+
+ await pageLoadCompleter.future;
+ pageLoadCompleter = Completer<void>();
+
+ final WebViewController controller = await controllerCompleter.future;
+ await controller.runJavascript('localStorage.setItem("myCat", "Tom");');
+ final String myCatItem = await controller.runJavascriptReturningResult(
+ 'localStorage.getItem("myCat");',
+ );
+ expect(myCatItem, '"Tom"');
+
+ await controller.clearCache();
+ await pageLoadCompleter.future;
+
+ final String nullItem = await controller.runJavascriptReturningResult(
+ 'localStorage.getItem("myCat");',
+ );
+ expect(nullItem, 'null');
+ },
+ );
+}
+
+// JavaScript booleans evaluate to different string values on Android and iOS.
+// This utility method returns the string boolean value of the current platform.
+String _webviewBool(bool value) {
+ if (defaultTargetPlatform == TargetPlatform.iOS) {
+ return value ? '1' : '0';
+ }
+ return value ? 'true' : 'false';
+}
+
+/// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests.
+Future<String> _getUserAgent(WebViewController controller) async {
+ return _runJavaScriptReturningResult(controller, 'navigator.userAgent;');
+}
+
+Future<String> _runJavaScriptReturningResult(
+ WebViewController controller,
+ String js,
+) async {
+ return jsonDecode(await controller.runJavascriptReturningResult(js))
+ as String;
+}
+
+class ResizableWebView extends StatefulWidget {
+ const ResizableWebView({
+ Key? key,
+ required this.onResize,
+ required this.onPageFinished,
+ }) : super(key: key);
+
+ final JavascriptMessageHandler onResize;
+ final VoidCallback onPageFinished;
+
+ @override
+ State<StatefulWidget> createState() => ResizableWebViewState();
+}
+
+class ResizableWebViewState extends State<ResizableWebView> {
+ double webViewWidth = 200;
+ double webViewHeight = 200;
+
+ static const String resizePage = '''
+ <!DOCTYPE html><html>
+ <head><title>Resize test</title>
+ <script type="text/javascript">
+ function onResize() {
+ Resize.postMessage("resize");
+ }
+ function onLoad() {
+ window.onresize = onResize;
+ }
+ </script>
+ </head>
+ <body onload="onLoad();" bgColor="blue">
+ </body>
+ </html>
+ ''';
+
+ @override
+ Widget build(BuildContext context) {
+ final String resizeTestBase64 =
+ base64Encode(const Utf8Encoder().convert(resizePage));
+ return Directionality(
+ textDirection: TextDirection.ltr,
+ child: Column(
+ children: <Widget>[
+ SizedBox(
+ width: webViewWidth,
+ height: webViewHeight,
+ child: WebView(
+ initialUrl:
+ 'data:text/html;charset=utf-8;base64,$resizeTestBase64',
+ javascriptChannels: <JavascriptChannel>{
+ JavascriptChannel(
+ name: 'Resize',
+ onMessageReceived: widget.onResize,
+ ),
+ },
+ onPageFinished: (_) => widget.onPageFinished(),
+ javascriptMode: JavascriptMode.unrestricted,
+ ),
+ ),
+ TextButton(
+ key: const Key('resizeButton'),
+ onPressed: () {
+ setState(() {
+ webViewWidth += 100.0;
+ webViewHeight += 100.0;
+ });
+ },
+ child: const Text('ResizeButton'),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class CopyableObjectWithCallback with Copyable {
+ CopyableObjectWithCallback(this.callback);
+
+ final VoidCallback callback;
+
+ @override
+ CopyableObjectWithCallback copy() {
+ return CopyableObjectWithCallback(callback);
+ }
+}
+
+class ClassWithCallbackClass {
+ ClassWithCallbackClass() {
+ callbackClass = CopyableObjectWithCallback(
+ withWeakRefenceTo(
+ this,
+ (WeakReference<ClassWithCallbackClass> weakReference) {
+ return () {
+ // Weak reference to `this` in callback.
+ // ignore: unnecessary_statements
+ weakReference;
+ };
+ },
+ ),
+ );
+ }
+
+ late final CopyableObjectWithCallback callbackClass;
+}
diff --git a/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart
index 69c1a46..2265aeb 100644
--- a/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/example/integration_test/webview_flutter_test.dart
@@ -18,11 +18,9 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
-import 'package:webview_flutter_android/webview_android.dart';
-import 'package:webview_flutter_android/webview_surface_android.dart';
-import 'package:webview_flutter_android_example/navigation_decision.dart';
-import 'package:webview_flutter_android_example/navigation_request.dart';
-import 'package:webview_flutter_android_example/web_view.dart';
+import 'package:webview_flutter_android/src/instance_manager.dart';
+import 'package:webview_flutter_android/src/weak_reference_utils.dart';
+import 'package:webview_flutter_android/webview_flutter_android.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
Future<void> main() async {
@@ -48,164 +46,169 @@
final String secondaryUrl = '$prefixUrl/secondary.txt';
final String headersUrl = '$prefixUrl/headers';
- testWidgets('initialUrl', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final Completer<void> pageFinishedCompleter = Completer<void>();
+ testWidgets('loadRequest', (WidgetTester tester) async {
+ final Completer<void> pageFinished = Completer<void>();
+
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageFinished.complete()),
+ )
+ ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
await tester.pumpWidget(
- MaterialApp(
- home: Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: primaryUrl,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- onPageFinished: pageFinishedCompleter.complete,
- ),
- ),
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
),
);
- final WebViewController controller = await controllerCompleter.future;
- await pageFinishedCompleter.future;
+ await pageFinished.future;
final String? currentUrl = await controller.currentUrl();
expect(currentUrl, primaryUrl);
});
- testWidgets('loadUrl', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final StreamController<String> pageLoads = StreamController<String>();
+ testWidgets(
+ 'withWeakRefenceTo allows encapsulating class to be garbage collected',
+ (WidgetTester tester) async {
+ final Completer<int> gcCompleter = Completer<int>();
+ final InstanceManager instanceManager = InstanceManager(
+ onWeakReferenceRemoved: gcCompleter.complete,
+ );
+
+ ClassWithCallbackClass? instance = ClassWithCallbackClass();
+ instanceManager.addHostCreatedInstance(instance.callbackClass, 0);
+ instance = null;
+
+ // Force garbage collection.
+ await IntegrationTestWidgetsFlutterBinding.instance
+ .watchPerformance(() async {
+ await tester.pumpAndSettle();
+ });
+
+ final int gcIdentifier = await gcCompleter.future;
+ expect(gcIdentifier, 0);
+ }, timeout: const Timeout(Duration(seconds: 10)));
+
+ testWidgets('runJavaScriptReturningResult', (WidgetTester tester) async {
+ final Completer<void> pageFinished = Completer<void>();
+
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageFinished.complete()),
+ )
+ ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: primaryUrl,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- onPageFinished: (String url) {
- pageLoads.add(url);
- },
- ),
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
),
);
- final WebViewController controller = await controllerCompleter.future;
- await controller.loadUrl(secondaryUrl);
+ await pageFinished.future;
+
await expectLater(
- pageLoads.stream.firstWhere((String url) => url == secondaryUrl),
- completion(secondaryUrl),
+ controller.runJavaScriptReturningResult('1 + 1'),
+ completion(2),
);
});
- testWidgets('evaluateJavascript', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: primaryUrl,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- final String result = await controller.evaluateJavascript('1 + 1');
- expect(result, equals('2'));
- });
-
- testWidgets('loadUrl with headers', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final StreamController<String> pageStarts = StreamController<String>();
- final StreamController<String> pageLoads = StreamController<String>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: primaryUrl,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarts.add(url);
- },
- onPageFinished: (String url) {
- pageLoads.add(url);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
+ testWidgets('loadRequest with headers', (WidgetTester tester) async {
final Map<String, String> headers = <String, String>{
'test_header': 'flutter_test_header'
};
- await controller.loadUrl(headersUrl, headers: headers);
- final String? currentUrl = await controller.currentUrl();
- expect(currentUrl, headersUrl);
- await pageStarts.stream.firstWhere((String url) => url == currentUrl);
- await pageLoads.stream.firstWhere((String url) => url == currentUrl);
+ final StreamController<String> pageLoads = StreamController<String>();
- final String content = await controller
- .runJavascriptReturningResult('document.documentElement.innerText');
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((String url) => pageLoads.add(url)),
+ )
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(headersUrl),
+ headers: headers,
+ ),
+ );
+
+ await tester.pumpWidget(
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ),
+ );
+
+ await pageLoads.stream.firstWhere((String url) => url == headersUrl);
+
+ final String content = await controller.runJavaScriptReturningResult(
+ 'document.documentElement.innerText',
+ ) as String;
expect(content.contains('flutter_test_header'), isTrue);
});
testWidgets('JavascriptChannel', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final Completer<void> pageStarted = Completer<void>();
- final Completer<void> pageLoaded = Completer<void>();
+ final Completer<void> pageFinished = Completer<void>();
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageFinished.complete()),
+ );
+
final Completer<String> channelCompleter = Completer<String>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- // This is the data URL for: '<!DOCTYPE html>'
- initialUrl:
- 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- javascriptChannels: <JavascriptChannel>{
- JavascriptChannel(
- name: 'Echo',
- onMessageReceived: (JavascriptMessage message) {
- channelCompleter.complete(message.message);
- },
- ),
- },
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
+ await controller.addJavaScriptChannel(
+ JavaScriptChannelParams(
+ name: 'Echo',
+ onMessageReceived: (JavaScriptMessage message) {
+ channelCompleter.complete(message.message);
+ },
),
);
- final WebViewController controller = await controllerCompleter.future;
- await pageStarted.future;
- await pageLoaded.future;
- expect(channelCompleter.isCompleted, isFalse);
- await controller.runJavascript('Echo.postMessage("hello");');
+ await controller.loadHtmlString(
+ 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
+ );
+ await tester.pumpWidget(
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ),
+ );
+
+ await pageFinished.future;
+
+ await controller.runJavaScript('Echo.postMessage("hello");');
await expectLater(channelCompleter.future, completion('hello'));
});
@@ -216,7 +219,7 @@
bool resizeButtonTapped = false;
await tester.pumpWidget(ResizableWebView(
- onResize: (_) {
+ onResize: () {
if (resizeButtonTapped) {
buttonTapResizeCompleter.complete();
} else {
@@ -225,6 +228,7 @@
},
onPageFinished: () => onPageFinished.complete(),
));
+
await onPageFinished.future;
// Wait for a potential call to resize after page is loaded.
await initialResizeCompleter.future.timeout(
@@ -233,98 +237,42 @@
);
resizeButtonTapped = true;
+
await tester.tap(find.byKey(const ValueKey<String>('resizeButton')));
await tester.pumpAndSettle();
- expect(buttonTapResizeCompleter.future, completes);
+
+ await expectLater(buttonTapResizeCompleter.future, completes);
});
testWidgets('set custom userAgent', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter1 =
- Completer<WebViewController>();
- final GlobalKey globalKey = GlobalKey();
+ final Completer<void> pageFinished = Completer<void>();
+
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageFinished.complete()),
+ )
+ ..setUserAgent('Custom_User_Agent1')
+ ..loadRequest(LoadRequestParams(uri: Uri.parse('about:blank')));
+
await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: globalKey,
- initialUrl: 'about:blank',
- javascriptMode: JavascriptMode.unrestricted,
- userAgent: 'Custom_User_Agent1',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter1.complete(controller);
- },
- ),
- ),
- );
- final WebViewController controller1 = await controllerCompleter1.future;
- final String customUserAgent1 = await _getUserAgent(controller1);
- expect(customUserAgent1, 'Custom_User_Agent1');
- // rebuild the WebView with a different user agent.
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: globalKey,
- initialUrl: 'about:blank',
- javascriptMode: JavascriptMode.unrestricted,
- userAgent: 'Custom_User_Agent2',
- ),
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
),
);
- final String customUserAgent2 = await _getUserAgent(controller1);
- expect(customUserAgent2, 'Custom_User_Agent2');
- });
+ await pageFinished.future;
- testWidgets('use default platform userAgent after webView is rebuilt',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- final GlobalKey globalKey = GlobalKey();
- // Build the webView with no user agent to get the default platform user agent.
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: globalKey,
- initialUrl: primaryUrl,
- javascriptMode: JavascriptMode.unrestricted,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- final String defaultPlatformUserAgent = await _getUserAgent(controller);
- // rebuild the WebView with a custom user agent.
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: globalKey,
- initialUrl: 'about:blank',
- javascriptMode: JavascriptMode.unrestricted,
- userAgent: 'Custom_User_Agent',
- ),
- ),
- );
final String customUserAgent = await _getUserAgent(controller);
- expect(customUserAgent, 'Custom_User_Agent');
- // rebuilds the WebView with no user agent.
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: globalKey,
- initialUrl: 'about:blank',
- javascriptMode: JavascriptMode.unrestricted,
- ),
- ),
- );
-
- final String customUserAgent2 = await _getUserAgent(controller);
- expect(customUserAgent2, defaultPlatformUserAgent);
+ expect(customUserAgent, 'Custom_User_Agent1');
});
group('Video playback policy', () {
@@ -335,201 +283,160 @@
final String base64VideoData =
base64Encode(Uint8List.view(videoData.buffer));
final String videoTest = '''
- <!DOCTYPE html><html>
- <head><title>Video auto play</title>
- <script type="text/javascript">
- function play() {
- var video = document.getElementById("video");
- video.play();
- video.addEventListener('timeupdate', videoTimeUpdateHandler, false);
- }
- function videoTimeUpdateHandler(e) {
- var video = document.getElementById("video");
- VideoTestTime.postMessage(video.currentTime);
- }
- function isPaused() {
- var video = document.getElementById("video");
- return video.paused;
- }
- function isFullScreen() {
- var video = document.getElementById("video");
- return video.webkitDisplayingFullscreen;
- }
- </script>
- </head>
- <body onload="play();">
- <video controls playsinline autoplay id="video">
- <source src="data:video/mp4;charset=utf-8;base64,$base64VideoData">
- </video>
- </body>
- </html>
- ''';
+ <!DOCTYPE html><html>
+ <head><title>Video auto play</title>
+ <script type="text/javascript">
+ function play() {
+ var video = document.getElementById("video");
+ video.play();
+ video.addEventListener('timeupdate', videoTimeUpdateHandler, false);
+ }
+ function videoTimeUpdateHandler(e) {
+ var video = document.getElementById("video");
+ VideoTestTime.postMessage(video.currentTime);
+ }
+ function isPaused() {
+ var video = document.getElementById("video");
+ return video.paused;
+ }
+ function isFullScreen() {
+ var video = document.getElementById("video");
+ return video.webkitDisplayingFullscreen;
+ }
+ </script>
+ </head>
+ <body onload="play();">
+ <video controls playsinline autoplay id="video">
+ <source src="data:video/mp4;charset=utf-8;base64,$base64VideoData">
+ </video>
+ </body>
+ </html>
+ ''';
videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest));
});
testWidgets('Auto media playback', (WidgetTester tester) async {
- Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
Completer<void> pageLoaded = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+ PlatformWebViewController controller = AndroidWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ AndroidNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoaded.complete()),
+ )
+ ..setMediaPlaybackRequiresUserGesture(false)
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+ ),
),
- ),
- );
- WebViewController controller = await controllerCompleter.future;
- await pageLoaded.future;
+ );
- String isPaused =
- await controller.runJavascriptReturningResult('isPaused();');
- expect(isPaused, _webviewBool(false));
-
- controllerCompleter = Completer<WebViewController>();
- pageLoaded = Completer<void>();
-
- // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy
await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
),
);
- controller = await controllerCompleter.future;
await pageLoaded.future;
- isPaused = await controller.runJavascriptReturningResult('isPaused();');
- expect(isPaused, _webviewBool(true));
- });
-
- testWidgets('Changes to initialMediaPlaybackPolicy are ignored',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- Completer<void> pageLoaded = Completer<void>();
-
- final GlobalKey key = GlobalKey();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: key,
- initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- await pageLoaded.future;
-
- String isPaused =
- await controller.runJavascriptReturningResult('isPaused();');
- expect(isPaused, _webviewBool(false));
+ bool isPaused =
+ await controller.runJavaScriptReturningResult('isPaused();') as bool;
+ expect(isPaused, false);
pageLoaded = Completer<void>();
+ controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoaded.complete()),
+ )
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+ ),
+ ),
+ );
await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: key,
- initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
),
);
- await controller.reload();
-
await pageLoaded.future;
- isPaused = await controller.runJavascriptReturningResult('isPaused();');
- expect(isPaused, _webviewBool(false));
+ isPaused =
+ await controller.runJavaScriptReturningResult('isPaused();') as bool;
+ expect(isPaused, true);
});
- testWidgets('Video plays inline when allowsInlineMediaPlayback is true',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
+ testWidgets('Video plays inline', (WidgetTester tester) async {
final Completer<void> pageLoaded = Completer<void>();
final Completer<void> videoPlaying = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
+ final PlatformWebViewController controller = AndroidWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ AndroidNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoaded.complete()),
+ )
+ ..addJavaScriptChannel(
+ JavaScriptChannelParams(
+ name: 'VideoTestTime',
+ onMessageReceived: (JavaScriptMessage message) {
+ final double currentTime = double.parse(message.message);
+ // Let it play for at least 1 second to make sure the related video's properties are set.
+ if (currentTime > 1 && !videoPlaying.isCompleted) {
+ videoPlaying.complete(null);
+ }
},
- javascriptMode: JavascriptMode.unrestricted,
- javascriptChannels: <JavascriptChannel>{
- JavascriptChannel(
- name: 'VideoTestTime',
- onMessageReceived: (JavascriptMessage message) {
- final double currentTime = double.parse(message.message);
- // Let it play for at least 1 second to make sure the related video's properties are set.
- if (currentTime > 1 && !videoPlaying.isCompleted) {
- videoPlaying.complete(null);
- }
- },
- ),
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
- allowsInlineMediaPlayback: true,
),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- await pageLoaded.future;
+ )
+ ..setMediaPlaybackRequiresUserGesture(false)
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,$videoTestBase64',
+ ),
+ ),
+ );
- // Pump once to trigger the video play.
- await tester.pump();
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
+
+ await pageLoaded.future;
// Makes sure we get the correct event that indicates the video is actually playing.
await videoPlaying.future;
- final String fullScreen =
- await controller.runJavascriptReturningResult('isFullScreen();');
- expect(fullScreen, _webviewBool(false));
+ final bool fullScreen = await controller
+ .runJavaScriptReturningResult('isFullScreen();') as bool;
+ expect(fullScreen, false);
});
});
@@ -565,138 +472,75 @@
});
testWidgets('Auto media playback', (WidgetTester tester) async {
- Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- Completer<void> pageStarted = Completer<void>();
Completer<void> pageLoaded = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
+ PlatformWebViewController controller = AndroidWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ AndroidNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoaded.complete()),
+ )
+ ..setMediaPlaybackRequiresUserGesture(false)
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+ ),
),
+ );
+
+ await tester.pumpWidget(
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
),
);
- WebViewController controller = await controllerCompleter.future;
- await pageStarted.future;
+
await pageLoaded.future;
- String isPaused =
- await controller.runJavascriptReturningResult('isPaused();');
- expect(isPaused, _webviewBool(false));
+ bool isPaused =
+ await controller.runJavaScriptReturningResult('isPaused();') as bool;
+ expect(isPaused, false);
- controllerCompleter = Completer<WebViewController>();
- pageStarted = Completer<void>();
pageLoaded = Completer<void>();
-
- // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
+ controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoaded.complete()),
+ )
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,$audioTestBase64',
+ ),
),
+ );
+
+ await tester.pumpWidget(
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
),
);
- controller = await controllerCompleter.future;
- await pageStarted.future;
await pageLoaded.future;
- isPaused = await controller.runJavascriptReturningResult('isPaused();');
- expect(isPaused, _webviewBool(true));
- });
-
- testWidgets('Changes to initialMediaPlaybackPolicy are ignored',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- Completer<void> pageStarted = Completer<void>();
- Completer<void> pageLoaded = Completer<void>();
-
- final GlobalKey key = GlobalKey();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: key,
- initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- await pageStarted.future;
- await pageLoaded.future;
-
- String isPaused =
- await controller.runJavascriptReturningResult('isPaused();');
- expect(isPaused, _webviewBool(false));
-
- pageStarted = Completer<void>();
- pageLoaded = Completer<void>();
-
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: key,
- initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
- ),
- );
-
- await controller.reload();
-
- await pageStarted.future;
- await pageLoaded.future;
-
- isPaused = await controller.runJavascriptReturningResult('isPaused();');
- expect(isPaused, _webviewBool(false));
+ isPaused =
+ await controller.runJavaScriptReturningResult('isPaused();') as bool;
+ expect(isPaused, true);
});
});
@@ -711,33 +555,43 @@
''';
final String getTitleTestBase64 =
base64Encode(const Utf8Encoder().convert(getTitleTest));
- final Completer<void> pageStarted = Completer<void>();
final Completer<void> pageLoaded = Completer<void>();
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
+
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoaded.complete()),
+ )
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,$getTitleTestBase64',
+ ),
+ ),
+ );
await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- onPageStarted: (String url) {
- pageStarted.complete(null);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
+ Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
),
);
- final WebViewController controller = await controllerCompleter.future;
- await pageStarted.future;
await pageLoaded.future;
+ // On at least iOS, it does not appear to be guaranteed that the native
+ // code has the title when the page load completes. Execute some JavaScript
+ // before checking the title to ensure that the page has been fully parsed
+ // and processed.
+ await controller.runJavaScript('1;');
+
final String? title = await controller.getTitle();
expect(title, 'Some title');
});
@@ -769,32 +623,36 @@
base64Encode(const Utf8Encoder().convert(scrollTestPage));
final Completer<void> pageLoaded = Completer<void>();
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
-
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- initialUrl:
- 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoaded.complete()),
+ )
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
+ ),
),
- ),
- );
+ );
- final WebViewController controller = await controllerCompleter.future;
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
+
await pageLoaded.future;
await tester.pumpAndSettle(const Duration(seconds: 3));
- int scrollPosX = await controller.getScrollX();
- int scrollPosY = await controller.getScrollY();
+ Offset scrollPos = await controller.getScrollPosition();
// Check scrollTo()
const int X_SCROLL = 123;
@@ -802,206 +660,19 @@
// Get the initial position; this ensures that scrollTo is actually
// changing something, but also gives the native view's scroll position
// time to settle.
- expect(scrollPosX, isNot(X_SCROLL));
- expect(scrollPosX, isNot(Y_SCROLL));
+ expect(scrollPos.dx, isNot(X_SCROLL));
+ expect(scrollPos.dy, isNot(Y_SCROLL));
await controller.scrollTo(X_SCROLL, Y_SCROLL);
- scrollPosX = await controller.getScrollX();
- scrollPosY = await controller.getScrollY();
- expect(scrollPosX, X_SCROLL);
- expect(scrollPosY, Y_SCROLL);
+ scrollPos = await controller.getScrollPosition();
+ expect(scrollPos.dx, X_SCROLL);
+ expect(scrollPos.dy, Y_SCROLL);
// Check scrollBy() (on top of scrollTo())
await controller.scrollBy(X_SCROLL, Y_SCROLL);
- scrollPosX = await controller.getScrollX();
- scrollPosY = await controller.getScrollY();
- expect(scrollPosX, X_SCROLL * 2);
- expect(scrollPosY, Y_SCROLL * 2);
- });
- });
-
- group('SurfaceAndroidWebView', () {
- setUpAll(() {
- WebView.platform = SurfaceAndroidWebView();
- });
-
- tearDownAll(() {
- WebView.platform = AndroidWebView();
- });
-
- testWidgets('setAndGetScrollPosition', (WidgetTester tester) async {
- const String scrollTestPage = '''
- <!DOCTYPE html>
- <html>
- <head>
- <style>
- body {
- height: 100%;
- width: 100%;
- }
- #container{
- width:5000px;
- height:5000px;
- }
- </style>
- </head>
- <body>
- <div id="container"/>
- </body>
- </html>
- ''';
-
- final String scrollTestPageBase64 =
- base64Encode(const Utf8Encoder().convert(scrollTestPage));
-
- final Completer<void> pageLoaded = Completer<void>();
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
-
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- initialUrl:
- 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
- ),
- );
-
- final WebViewController controller = await controllerCompleter.future;
- await pageLoaded.future;
-
- await tester.pumpAndSettle(const Duration(seconds: 3));
-
- // Check scrollTo()
- const int X_SCROLL = 123;
- const int Y_SCROLL = 321;
-
- await controller.scrollTo(X_SCROLL, Y_SCROLL);
- int scrollPosX = await controller.getScrollX();
- int scrollPosY = await controller.getScrollY();
- expect(X_SCROLL, scrollPosX);
- expect(Y_SCROLL, scrollPosY);
-
- // Check scrollBy() (on top of scrollTo())
- await controller.scrollBy(X_SCROLL, Y_SCROLL);
- scrollPosX = await controller.getScrollX();
- scrollPosY = await controller.getScrollY();
- expect(X_SCROLL * 2, scrollPosX);
- expect(Y_SCROLL * 2, scrollPosY);
- });
-
- testWidgets('inputs are scrolled into view when focused',
- (WidgetTester tester) async {
- const String scrollTestPage = '''
- <!DOCTYPE html>
- <html>
- <head>
- <style>
- input {
- margin: 10000px 0;
- }
- #viewport {
- position: fixed;
- top:0;
- bottom:0;
- left:0;
- right:0;
- }
- </style>
- </head>
- <body>
- <div id="viewport"></div>
- <input type="text" id="inputEl">
- </body>
- </html>
- ''';
-
- final String scrollTestPageBase64 =
- base64Encode(const Utf8Encoder().convert(scrollTestPage));
-
- final Completer<void> pageLoaded = Completer<void>();
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
-
- await tester.runAsync(() async {
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: SizedBox(
- width: 200,
- height: 200,
- child: WebView(
- initialUrl:
- 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64',
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- javascriptMode: JavascriptMode.unrestricted,
- ),
- ),
- ),
- );
- await Future<void>.delayed(const Duration(milliseconds: 20));
- await tester.pump();
- });
-
- final WebViewController controller = await controllerCompleter.future;
- await pageLoaded.future;
- final String viewportRectJSON = await _runJavaScriptReturningResult(
- controller, 'JSON.stringify(viewport.getBoundingClientRect())');
- final Map<String, dynamic> viewportRectRelativeToViewport =
- jsonDecode(viewportRectJSON) as Map<String, dynamic>;
-
- // Check that the input is originally outside of the viewport.
-
- final String initialInputClientRectJSON =
- await _runJavaScriptReturningResult(
- controller, 'JSON.stringify(inputEl.getBoundingClientRect())');
- final Map<String, dynamic> initialInputClientRectRelativeToViewport =
- jsonDecode(initialInputClientRectJSON) as Map<String, dynamic>;
-
- expect(
- initialInputClientRectRelativeToViewport['bottom'] <=
- viewportRectRelativeToViewport['bottom'],
- isFalse);
-
- await controller.runJavascript('inputEl.focus()');
-
- // Check that focusing the input brought it into view.
-
- final String lastInputClientRectJSON =
- await _runJavaScriptReturningResult(
- controller, 'JSON.stringify(inputEl.getBoundingClientRect())');
- final Map<String, dynamic> lastInputClientRectRelativeToViewport =
- jsonDecode(lastInputClientRectJSON) as Map<String, dynamic>;
-
- expect(
- lastInputClientRectRelativeToViewport['top'] >=
- viewportRectRelativeToViewport['top'],
- isTrue);
- expect(
- lastInputClientRectRelativeToViewport['bottom'] <=
- viewportRectRelativeToViewport['bottom'],
- isTrue);
-
- expect(
- lastInputClientRectRelativeToViewport['left'] >=
- viewportRectRelativeToViewport['left'],
- isTrue);
- expect(
- lastInputClientRectRelativeToViewport['right'] <=
- viewportRectRelativeToViewport['right'],
- isTrue);
+ scrollPos = await controller.getScrollPosition();
+ expect(scrollPos.dx, X_SCROLL * 2);
+ expect(scrollPos.dy, Y_SCROLL * 2);
});
});
@@ -1011,33 +682,38 @@
'${base64Encode(const Utf8Encoder().convert(blankPage))}';
testWidgets('can allow requests', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
final StreamController<String> pageLoads =
StreamController<String>.broadcast();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: blankPageEncoded,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- navigationDelegate: (NavigationRequest request) {
- return (request.url.contains('youtube.com'))
+
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )
+ ..setOnPageFinished((String url) => pageLoads.add(url))
+ ..setOnNavigationRequest((NavigationRequest navigationRequest) {
+ return (navigationRequest.url.contains('youtube.com'))
? NavigationDecision.prevent
: NavigationDecision.navigate;
- },
- onPageFinished: (String url) => pageLoads.add(url),
- ),
- ),
- );
+ }),
+ )
+ ..loadRequest(
+ LoadRequestParams(uri: Uri.parse(blankPageEncoded)),
+ );
+
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
await pageLoads.stream.first; // Wait for initial page load.
- final WebViewController controller = await controllerCompleter.future;
- await controller.runJavascript('location.href = "$secondaryUrl"');
+ await controller.runJavaScript('location.href = "$secondaryUrl"');
await pageLoads.stream.first; // Wait for the next page load.
final String? currentUrl = await controller.currentUrl();
@@ -1048,25 +724,39 @@
final Completer<WebResourceError> errorCompleter =
Completer<WebResourceError>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: 'https://www.notawebsite..com',
- onWebResourceError: (WebResourceError error) {
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnWebResourceError((WebResourceError error) {
errorCompleter.complete(error);
- },
- ),
- ),
- );
+ }),
+ )
+ ..loadRequest(
+ LoadRequestParams(uri: Uri.parse('https://www.notawebsite..com')),
+ );
+
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
final WebResourceError error = await errorCompleter.future;
expect(error, isNotNull);
expect(error.errorType, isNotNull);
expect(
- error.failingUrl?.startsWith('https://www.notawebsite..com'), isTrue);
+ (error as AndroidWebResourceError)
+ .failingUrl
+ ?.startsWith('https://www.notawebsite..com'),
+ isTrue,
+ );
});
testWidgets('onWebResourceError is not called with valid url',
@@ -1075,95 +765,71 @@
Completer<WebResourceError>();
final Completer<void> pageFinishCompleter = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl:
- 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
- onWebResourceError: (WebResourceError error) {
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )
+ ..setOnPageFinished((_) => pageFinishCompleter.complete())
+ ..setOnWebResourceError((WebResourceError error) {
errorCompleter.complete(error);
- },
- onPageFinished: (_) => pageFinishCompleter.complete(),
+ }),
+ )
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+',
+ ),
),
- ),
- );
+ );
+
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
expect(errorCompleter.future, doesNotComplete);
await pageFinishCompleter.future;
});
- testWidgets(
- 'onWebResourceError only called for main frame',
- (WidgetTester tester) async {
- const String iframeTest = '''
- <!DOCTYPE html>
- <html>
- <head>
- <title>WebResourceError test</title>
- </head>
- <body>
- <iframe src="https://notawebsite..com"></iframe>
- </body>
- </html>
- ''';
- final String iframeTestBase64 =
- base64Encode(const Utf8Encoder().convert(iframeTest));
-
- final Completer<WebResourceError> errorCompleter =
- Completer<WebResourceError>();
- final Completer<void> pageFinishCompleter = Completer<void>();
-
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl:
- 'data:text/html;charset=utf-8;base64,$iframeTestBase64',
- onWebResourceError: (WebResourceError error) {
- errorCompleter.complete(error);
- },
- onPageFinished: (_) => pageFinishCompleter.complete(),
- ),
- ),
- );
-
- expect(errorCompleter.future, doesNotComplete);
- await pageFinishCompleter.future;
- },
- );
-
testWidgets('can block requests', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
final StreamController<String> pageLoads =
StreamController<String>.broadcast();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: blankPageEncoded,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- navigationDelegate: (NavigationRequest request) {
- return (request.url.contains('youtube.com'))
+
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )
+ ..setOnPageFinished((String url) => pageLoads.add(url))
+ ..setOnNavigationRequest((NavigationRequest navigationRequest) {
+ return (navigationRequest.url.contains('youtube.com'))
? NavigationDecision.prevent
: NavigationDecision.navigate;
- },
- onPageFinished: (String url) => pageLoads.add(url),
- ),
- ),
- );
+ }),
+ )
+ ..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));
+
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
await pageLoads.stream.first; // Wait for initial page load.
- final WebViewController controller = await controllerCompleter.future;
await controller
- .runJavascript('location.href = "https://www.youtube.com/"');
+ .runJavaScript('location.href = "https://www.youtube.com/"');
// There should never be any second page load, since our new URL is
// blocked. Still wait for a potential page change for some time in order
@@ -1175,35 +841,39 @@
});
testWidgets('supports asynchronous decisions', (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
final StreamController<String> pageLoads =
StreamController<String>.broadcast();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: blankPageEncoded,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- navigationDelegate: (NavigationRequest request) async {
+
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )
+ ..setOnPageFinished((String url) => pageLoads.add(url))
+ ..setOnNavigationRequest(
+ (NavigationRequest navigationRequest) async {
NavigationDecision decision = NavigationDecision.prevent;
decision = await Future<NavigationDecision>.delayed(
const Duration(milliseconds: 10),
() => NavigationDecision.navigate);
return decision;
- },
- onPageFinished: (String url) => pageLoads.add(url),
- ),
- ),
- );
+ }),
+ )
+ ..loadRequest(LoadRequestParams(uri: Uri.parse(blankPageEncoded)));
+
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
await pageLoads.stream.first; // Wait for initial page load.
- final WebViewController controller = await controllerCompleter.future;
- await controller.runJavascript('location.href = "$secondaryUrl"');
+ await controller.runJavaScript('location.href = "$secondaryUrl"');
await pageLoads.stream.first; // Wait for second page to load.
final String? currentUrl = await controller.currentUrl();
@@ -1211,54 +881,27 @@
});
});
- testWidgets('launches with gestureNavigationEnabled on iOS',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: SizedBox(
- width: 400,
- height: 300,
- child: WebView(
- key: GlobalKey(),
- initialUrl: primaryUrl,
- gestureNavigationEnabled: true,
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- ),
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- final String? currentUrl = await controller.currentUrl();
- expect(currentUrl, primaryUrl);
- });
-
testWidgets('target _blank opens in same window',
(WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
final Completer<void> pageLoaded = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageFinished: (String url) {
- pageLoaded.complete(null);
- },
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
- await controller.runJavascript('window.open("$primaryUrl", "_blank")');
+
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoaded.complete()));
+
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
+
+ await controller.runJavaScript('window.open("$primaryUrl", "_blank")');
await pageLoaded.future;
final String? currentUrl = await controller.currentUrl();
expect(currentUrl, primaryUrl);
@@ -1267,31 +910,30 @@
testWidgets(
'can open new window and go back',
(WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
Completer<void> pageLoaded = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- onPageFinished: (String url) {
- pageLoaded.complete();
- },
- initialUrl: primaryUrl,
- ),
- ),
- );
- final WebViewController controller = await controllerCompleter.future;
+
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoaded.complete()))
+ ..loadRequest(LoadRequestParams(uri: Uri.parse(primaryUrl)));
+
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
+
expect(controller.currentUrl(), completion(primaryUrl));
await pageLoaded.future;
pageLoaded = Completer<void>();
- await controller.runJavascript('window.open("$secondaryUrl")');
+ await controller.runJavaScript('window.open("$secondaryUrl")');
await pageLoaded.future;
pageLoaded = Completer<void>();
expect(controller.currentUrl(), completion(secondaryUrl));
@@ -1336,105 +978,56 @@
''';
final String openWindowTestBase64 =
base64Encode(const Utf8Encoder().convert(openWindowTest));
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
+
final Completer<void> pageLoadCompleter = Completer<void>();
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- javascriptMode: JavascriptMode.unrestricted,
- initialUrl:
- 'data:text/html;charset=utf-8;base64,$openWindowTestBase64',
- onPageFinished: (String url) {
- pageLoadCompleter.complete();
- },
+ final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => pageLoadCompleter.complete()))
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,$openWindowTestBase64',
+ ),
),
- ),
- );
+ );
- final WebViewController controller = await controllerCompleter.future;
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) {
+ return PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context);
+ },
+ ));
+
await pageLoadCompleter.future;
- final String iframeLoaded =
- await controller.runJavascriptReturningResult('iframeLoaded');
- expect(iframeLoaded, 'true');
+ final bool iframeLoaded =
+ await controller.runJavaScriptReturningResult('iframeLoaded') as bool;
+ expect(iframeLoaded, true);
- final String elementText = await controller.runJavascriptReturningResult(
+ final String elementText = await controller.runJavaScriptReturningResult(
'document.querySelector("p") && document.querySelector("p").textContent',
- );
+ ) as String;
expect(elementText, 'null');
},
);
-
- testWidgets(
- 'clearCache should clear local storage',
- (WidgetTester tester) async {
- final Completer<WebViewController> controllerCompleter =
- Completer<WebViewController>();
-
- Completer<void> pageLoadCompleter = Completer<void>();
-
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: WebView(
- key: GlobalKey(),
- initialUrl: primaryUrl,
- javascriptMode: JavascriptMode.unrestricted,
- onPageFinished: (_) => pageLoadCompleter.complete(),
- onWebViewCreated: (WebViewController controller) {
- controllerCompleter.complete(controller);
- },
- ),
- ),
- );
-
- await pageLoadCompleter.future;
- pageLoadCompleter = Completer<void>();
-
- final WebViewController controller = await controllerCompleter.future;
- await controller.runJavascript('localStorage.setItem("myCat", "Tom");');
- final String myCatItem = await controller.runJavascriptReturningResult(
- 'localStorage.getItem("myCat");',
- );
- expect(myCatItem, '"Tom"');
-
- await controller.clearCache();
- await pageLoadCompleter.future;
-
- final String nullItem = await controller.runJavascriptReturningResult(
- 'localStorage.getItem("myCat");',
- );
- expect(nullItem, 'null');
- },
- );
-}
-
-// JavaScript booleans evaluate to different string values on Android and iOS.
-// This utility method returns the string boolean value of the current platform.
-String _webviewBool(bool value) {
- if (defaultTargetPlatform == TargetPlatform.iOS) {
- return value ? '1' : '0';
- }
- return value ? 'true' : 'false';
}
/// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests.
-Future<String> _getUserAgent(WebViewController controller) async {
+Future<String> _getUserAgent(PlatformWebViewController controller) async {
return _runJavaScriptReturningResult(controller, 'navigator.userAgent;');
}
Future<String> _runJavaScriptReturningResult(
- WebViewController controller,
+ PlatformWebViewController controller,
String js,
) async {
- return jsonDecode(await controller.runJavascriptReturningResult(js))
+ return jsonDecode(await controller.runJavaScriptReturningResult(js) as String)
as String;
}
@@ -1445,7 +1038,7 @@
required this.onPageFinished,
}) : super(key: key);
- final JavascriptMessageHandler onResize;
+ final VoidCallback onResize;
final VoidCallback onPageFinished;
@override
@@ -1453,6 +1046,31 @@
}
class ResizableWebViewState extends State<ResizableWebView> {
+ late final PlatformWebViewController controller = PlatformWebViewController(
+ const PlatformWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )..setOnPageFinished((_) => widget.onPageFinished()),
+ )
+ ..addJavaScriptChannel(
+ JavaScriptChannelParams(
+ name: 'Resize',
+ onMessageReceived: (_) {
+ widget.onResize();
+ },
+ ),
+ )
+ ..loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse(
+ 'data:text/html;charset=utf-8;base64,${base64Encode(const Utf8Encoder().convert(resizePage))}',
+ ),
+ ),
+ );
+
double webViewWidth = 200;
double webViewHeight = 200;
@@ -1475,8 +1093,6 @@
@override
Widget build(BuildContext context) {
- final String resizeTestBase64 =
- base64Encode(const Utf8Encoder().convert(resizePage));
return Directionality(
textDirection: TextDirection.ltr,
child: Column(
@@ -1484,18 +1100,9 @@
SizedBox(
width: webViewWidth,
height: webViewHeight,
- child: WebView(
- initialUrl:
- 'data:text/html;charset=utf-8;base64,$resizeTestBase64',
- javascriptChannels: <JavascriptChannel>{
- JavascriptChannel(
- name: 'Resize',
- onMessageReceived: widget.onResize,
- ),
- },
- onPageFinished: (_) => widget.onPageFinished(),
- javascriptMode: JavascriptMode.unrestricted,
- ),
+ child: PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: controller),
+ ).build(context),
),
TextButton(
key: const Key('resizeButton'),
@@ -1512,3 +1119,33 @@
);
}
}
+
+class CopyableObjectWithCallback with Copyable {
+ CopyableObjectWithCallback(this.callback);
+
+ final VoidCallback callback;
+
+ @override
+ CopyableObjectWithCallback copy() {
+ return CopyableObjectWithCallback(callback);
+ }
+}
+
+class ClassWithCallbackClass {
+ ClassWithCallbackClass() {
+ callbackClass = CopyableObjectWithCallback(
+ withWeakRefenceTo(
+ this,
+ (WeakReference<ClassWithCallbackClass> weakReference) {
+ return () {
+ // Weak reference to `this` in callback.
+ // ignore: unnecessary_statements
+ weakReference;
+ };
+ },
+ ),
+ );
+ }
+
+ late final CopyableObjectWithCallback callbackClass;
+}
diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/navigation_decision.dart b/packages/webview_flutter/webview_flutter_android/example/lib/legacy/navigation_decision.dart
similarity index 100%
rename from packages/webview_flutter/webview_flutter_android/example/lib/navigation_decision.dart
rename to packages/webview_flutter/webview_flutter_android/example/lib/legacy/navigation_decision.dart
diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/navigation_request.dart b/packages/webview_flutter/webview_flutter_android/example/lib/legacy/navigation_request.dart
similarity index 100%
rename from packages/webview_flutter/webview_flutter_android/example/lib/navigation_request.dart
rename to packages/webview_flutter/webview_flutter_android/example/lib/legacy/navigation_request.dart
diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_android/example/lib/legacy/web_view.dart
similarity index 98%
rename from packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart
rename to packages/webview_flutter/webview_flutter_android/example/lib/legacy/web_view.dart
index b7d98f2..b77a503 100644
--- a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart
+++ b/packages/webview_flutter/webview_flutter_android/example/lib/legacy/web_view.dart
@@ -8,9 +8,10 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
-import 'package:webview_flutter_android/webview_android.dart';
-import 'package:webview_flutter_android/webview_android_cookie_manager.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_android/src/webview_flutter_android_legacy.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
import 'navigation_decision.dart';
import 'navigation_request.dart';
@@ -319,8 +320,10 @@
required bool isForMainFrame,
}) async {
if (url.startsWith('https://www.youtube.com/')) {
+ debugPrint('blocking navigation to $url');
return false;
}
+ debugPrint('allowing navigation to $url');
return true;
}
diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart
index bd958ed..fe6d723 100644
--- a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart
@@ -2,33 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// ignore_for_file: public_member_api_docs, avoid_print
+// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
+
import 'package:flutter/material.dart';
-import 'package:flutter_driver/driver_extension.dart';
import 'package:path_provider/path_provider.dart';
-import 'package:webview_flutter_android/webview_surface_android.dart';
+import 'package:webview_flutter_android/webview_flutter_android.dart';
import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
-import 'navigation_decision.dart';
-import 'navigation_request.dart';
-import 'web_view.dart';
-
-void appMain() {
- enableFlutterDriverExtension();
- main();
-}
-
void main() {
- // Configure the [WebView] to use the [SurfaceAndroidWebView]
- // implementation instead of the default [AndroidWebView].
- WebView.platform = SurfaceAndroidWebView();
-
- runApp(const MaterialApp(home: _WebViewExample()));
+ runApp(const MaterialApp(home: WebViewExample()));
}
const String kNavigationExamplePage = '''
@@ -46,7 +33,7 @@
</html>
''';
-const String kExamplePage = '''
+const String kLocalExamplePage = '''
<!DOCTYPE html>
<html lang="en">
<head>
@@ -86,16 +73,70 @@
</html>
''';
-class _WebViewExample extends StatefulWidget {
- const _WebViewExample({Key? key}) : super(key: key);
+class WebViewExample extends StatefulWidget {
+ const WebViewExample({Key? key, this.cookieManager}) : super(key: key);
+
+ final PlatformWebViewCookieManager? cookieManager;
@override
- _WebViewExampleState createState() => _WebViewExampleState();
+ State<WebViewExample> createState() => _WebViewExampleState();
}
-class _WebViewExampleState extends State<_WebViewExample> {
- final Completer<WebViewController> _controller =
- Completer<WebViewController>();
+class _WebViewExampleState extends State<WebViewExample> {
+ late final PlatformWebViewController _controller;
+
+ @override
+ void initState() {
+ super.initState();
+
+ _controller = PlatformWebViewController(
+ AndroidWebViewControllerCreationParams(),
+ )
+ ..setJavaScriptMode(JavaScriptMode.unrestricted)
+ ..setBackgroundColor(const Color(0x80000000))
+ ..setPlatformNavigationDelegate(
+ PlatformNavigationDelegate(
+ const PlatformNavigationDelegateCreationParams(),
+ )
+ ..setOnProgress((int progress) {
+ debugPrint('WebView is loading (progress : $progress%)');
+ })
+ ..setOnPageStarted((String url) {
+ debugPrint('Page started loading: $url');
+ })
+ ..setOnPageFinished((String url) {
+ debugPrint('Page finished loading: $url');
+ })
+ ..setOnWebResourceError((WebResourceError error) {
+ debugPrint('''
+Page resource error:
+ code: ${error.errorCode}
+ description: ${error.description}
+ errorType: ${error.errorType}
+ isForMainFrame: ${error.isForMainFrame}
+ ''');
+ })
+ ..setOnNavigationRequest((NavigationRequest request) {
+ if (request.url.startsWith('https://www.youtube.com/')) {
+ debugPrint('blocking navigation to ${request.url}');
+ return NavigationDecision.prevent;
+ }
+ debugPrint('allowing navigation to ${request.url}');
+ return NavigationDecision.navigate;
+ }),
+ )
+ ..addJavaScriptChannel(JavaScriptChannelParams(
+ name: 'Toaster',
+ onMessageReceived: (JavaScriptMessage message) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(content: Text(message.message)),
+ );
+ },
+ ))
+ ..loadRequest(LoadRequestParams(
+ uri: Uri.parse('https://flutter.dev'),
+ ));
+ }
@override
Widget build(BuildContext context) {
@@ -105,74 +146,34 @@
title: const Text('Flutter WebView example'),
// This drop down menu demonstrates that Flutter widgets can be shown over the web view.
actions: <Widget>[
- _NavigationControls(_controller.future),
- _SampleMenu(_controller.future),
+ NavigationControls(webViewController: _controller),
+ SampleMenu(
+ webViewController: _controller,
+ cookieManager: widget.cookieManager,
+ ),
],
),
- body: WebView(
- initialUrl: 'https://flutter.dev',
- onWebViewCreated: (WebViewController controller) {
- _controller.complete(controller);
- },
- onProgress: (int progress) {
- print('WebView is loading (progress : $progress%)');
- },
- navigationDelegate: (NavigationRequest request) {
- if (request.url.startsWith('https://www.youtube.com/')) {
- print('blocking navigation to $request}');
- return NavigationDecision.prevent;
- }
- print('allowing navigation to $request');
- return NavigationDecision.navigate;
- },
- onPageStarted: (String url) {
- print('Page started loading: $url');
- },
- onPageFinished: (String url) {
- print('Page finished loading: $url');
- },
- javascriptChannels: _createJavascriptChannels(context),
- javascriptMode: JavascriptMode.unrestricted,
- userAgent: 'Custom_User_Agent',
- backgroundColor: const Color(0x80000000),
- ),
+ body: PlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams(controller: _controller),
+ ).build(context),
floatingActionButton: favoriteButton(),
);
}
Widget favoriteButton() {
- return FutureBuilder<WebViewController>(
- future: _controller.future,
- builder: (BuildContext context,
- AsyncSnapshot<WebViewController> controller) {
- if (controller.hasData) {
- return FloatingActionButton(
- onPressed: () async {
- final String url = (await controller.data!.currentUrl())!;
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(content: Text('Favorited $url')),
- );
- },
- child: const Icon(Icons.favorite),
- );
- }
- return Container();
- });
+ return FloatingActionButton(
+ onPressed: () async {
+ final String? url = await _controller.currentUrl();
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(content: Text('Favorited $url')),
+ );
+ },
+ child: const Icon(Icons.favorite),
+ );
}
}
-Set<JavascriptChannel> _createJavascriptChannels(BuildContext context) {
- return <JavascriptChannel>{
- JavascriptChannel(
- name: 'Snackbar',
- onMessageReceived: (JavascriptMessage message) {
- ScaffoldMessenger.of(context)
- .showSnackBar(SnackBar(content: Text(message.message)));
- }),
- };
-}
-
-enum _MenuOptions {
+enum MenuOptions {
showUserAgent,
listCookies,
clearCookies,
@@ -180,143 +181,144 @@
listCache,
clearCache,
navigationDelegate,
- loadFlutterAsset,
+ doPostRequest,
loadLocalFile,
+ loadFlutterAsset,
loadHtmlString,
transparentBackground,
- doPostRequest,
setCookie,
}
-class _SampleMenu extends StatelessWidget {
- const _SampleMenu(this.controller);
+class SampleMenu extends StatelessWidget {
+ SampleMenu({
+ Key? key,
+ required this.webViewController,
+ PlatformWebViewCookieManager? cookieManager,
+ }) : cookieManager = cookieManager ??
+ PlatformWebViewCookieManager(
+ const PlatformWebViewCookieManagerCreationParams(),
+ ),
+ super(key: key);
- final Future<WebViewController> controller;
+ final PlatformWebViewController webViewController;
+ late final PlatformWebViewCookieManager cookieManager;
@override
Widget build(BuildContext context) {
- return FutureBuilder<WebViewController>(
- future: controller,
- builder:
- (BuildContext context, AsyncSnapshot<WebViewController> controller) {
- return PopupMenuButton<_MenuOptions>(
- key: const ValueKey<String>('ShowPopupMenu'),
- onSelected: (_MenuOptions value) {
- switch (value) {
- case _MenuOptions.showUserAgent:
- _onShowUserAgent(controller.data!, context);
- break;
- case _MenuOptions.listCookies:
- _onListCookies(controller.data!, context);
- break;
- case _MenuOptions.clearCookies:
- _onClearCookies(controller.data!, context);
- break;
- case _MenuOptions.addToCache:
- _onAddToCache(controller.data!, context);
- break;
- case _MenuOptions.listCache:
- _onListCache(controller.data!, context);
- break;
- case _MenuOptions.clearCache:
- _onClearCache(controller.data!, context);
- break;
- case _MenuOptions.navigationDelegate:
- _onNavigationDelegateExample(controller.data!, context);
- break;
- case _MenuOptions.loadFlutterAsset:
- _onLoadFlutterAssetExample(controller.data!, context);
- break;
- case _MenuOptions.loadLocalFile:
- _onLoadLocalFileExample(controller.data!, context);
- break;
- case _MenuOptions.loadHtmlString:
- _onLoadHtmlStringExample(controller.data!, context);
- break;
- case _MenuOptions.transparentBackground:
- _onTransparentBackground(controller.data!, context);
- break;
- case _MenuOptions.doPostRequest:
- _onDoPostRequest(controller.data!, context);
- break;
- case _MenuOptions.setCookie:
- _onSetCookie(controller.data!, context);
- break;
- }
- },
- itemBuilder: (BuildContext context) => <PopupMenuItem<_MenuOptions>>[
- PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.showUserAgent,
- enabled: controller.hasData,
- child: const Text('Show user agent'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.listCookies,
- child: Text('List cookies'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.clearCookies,
- child: Text('Clear cookies'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.addToCache,
- child: Text('Add to cache'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.listCache,
- child: Text('List cache'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.clearCache,
- child: Text('Clear cache'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.navigationDelegate,
- child: Text('Navigation Delegate example'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.loadFlutterAsset,
- child: Text('Load Flutter Asset'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.loadHtmlString,
- child: Text('Load HTML string'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.loadLocalFile,
- child: Text('Load local file'),
- ),
- const PopupMenuItem<_MenuOptions>(
- key: ValueKey<String>('ShowTransparentBackgroundExample'),
- value: _MenuOptions.transparentBackground,
- child: Text('Transparent background example'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.doPostRequest,
- child: Text('Post Request'),
- ),
- const PopupMenuItem<_MenuOptions>(
- value: _MenuOptions.setCookie,
- child: Text('Set Cookie'),
- ),
- ],
- );
+ return PopupMenuButton<MenuOptions>(
+ key: const ValueKey<String>('ShowPopupMenu'),
+ onSelected: (MenuOptions value) {
+ switch (value) {
+ case MenuOptions.showUserAgent:
+ _onShowUserAgent();
+ break;
+ case MenuOptions.listCookies:
+ _onListCookies(context);
+ break;
+ case MenuOptions.clearCookies:
+ _onClearCookies(context);
+ break;
+ case MenuOptions.addToCache:
+ _onAddToCache(context);
+ break;
+ case MenuOptions.listCache:
+ _onListCache();
+ break;
+ case MenuOptions.clearCache:
+ _onClearCache(context);
+ break;
+ case MenuOptions.navigationDelegate:
+ _onNavigationDelegateExample();
+ break;
+ case MenuOptions.doPostRequest:
+ _onDoPostRequest();
+ break;
+ case MenuOptions.loadLocalFile:
+ _onLoadLocalFileExample();
+ break;
+ case MenuOptions.loadFlutterAsset:
+ _onLoadFlutterAssetExample();
+ break;
+ case MenuOptions.loadHtmlString:
+ _onLoadHtmlStringExample();
+ break;
+ case MenuOptions.transparentBackground:
+ _onTransparentBackground();
+ break;
+ case MenuOptions.setCookie:
+ _onSetCookie();
+ break;
+ }
},
+ itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.showUserAgent,
+ child: Text('Show user agent'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.listCookies,
+ child: Text('List cookies'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.clearCookies,
+ child: Text('Clear cookies'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.addToCache,
+ child: Text('Add to cache'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.listCache,
+ child: Text('List cache'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.clearCache,
+ child: Text('Clear cache'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.navigationDelegate,
+ child: Text('Navigation Delegate example'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.doPostRequest,
+ child: Text('Post Request'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.loadHtmlString,
+ child: Text('Load HTML string'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.loadLocalFile,
+ child: Text('Load local file'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.loadFlutterAsset,
+ child: Text('Load Flutter Asset'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ value: MenuOptions.setCookie,
+ child: Text('Set cookie'),
+ ),
+ const PopupMenuItem<MenuOptions>(
+ key: ValueKey<String>('ShowTransparentBackgroundExample'),
+ value: MenuOptions.transparentBackground,
+ child: Text('Transparent background example'),
+ ),
+ ],
);
}
- Future<void> _onShowUserAgent(
- WebViewController controller, BuildContext context) async {
- // Send a message with the user agent string to the Snackbar JavaScript channel we registered
+ Future<void> _onShowUserAgent() {
+ // Send a message with the user agent string to the Toaster JavaScript channel we registered
// with the WebView.
- await controller.runJavascript(
- 'Snackbar.postMessage("User Agent: " + navigator.userAgent);');
+ return webViewController.runJavaScript(
+ 'Toaster.postMessage("User Agent: " + navigator.userAgent);',
+ );
}
- Future<void> _onListCookies(
- WebViewController controller, BuildContext context) async {
- final String cookies =
- await controller.runJavascriptReturningResult('document.cookie');
+ Future<void> _onListCookies(BuildContext context) async {
+ final String cookies = await webViewController
+ .runJavaScriptReturningResult('document.cookie') as String;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Column(
mainAxisAlignment: MainAxisAlignment.end,
@@ -329,34 +331,32 @@
));
}
- Future<void> _onAddToCache(
- WebViewController controller, BuildContext context) async {
- await controller.runJavascript(
- 'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";');
+ Future<void> _onAddToCache(BuildContext context) async {
+ await webViewController.runJavaScript(
+ 'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";',
+ );
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Added a test entry to cache.'),
));
}
- Future<void> _onListCache(
- WebViewController controller, BuildContext context) async {
- await controller.runJavascript('caches.keys()'
+ Future<void> _onListCache() {
+ return webViewController.runJavaScript('caches.keys()'
// ignore: missing_whitespace_between_adjacent_strings
'.then((cacheKeys) => JSON.stringify({"cacheKeys" : cacheKeys, "localStorage" : localStorage}))'
- '.then((caches) => Snackbar.postMessage(caches))');
+ '.then((caches) => Toaster.postMessage(caches))');
}
- Future<void> _onClearCache(
- WebViewController controller, BuildContext context) async {
- await controller.clearCache();
+ Future<void> _onClearCache(BuildContext context) async {
+ await webViewController.clearCache();
+ await webViewController.clearLocalStorage();
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Cache cleared.'),
));
}
- Future<void> _onClearCookies(
- WebViewController controller, BuildContext context) async {
- final bool hadCookies = await WebViewCookieManager.instance.clearCookies();
+ Future<void> _onClearCookies(BuildContext context) async {
+ final bool hadCookies = await cookieManager.clearCookies();
String message = 'There were cookies. Now, they are gone!';
if (!hadCookies) {
message = 'There are no cookies.';
@@ -366,47 +366,58 @@
));
}
- Future<void> _onSetCookie(
- WebViewController controller, BuildContext context) async {
- await WebViewCookieManager.instance.setCookie(
+ Future<void> _onNavigationDelegateExample() {
+ final String contentBase64 = base64Encode(
+ const Utf8Encoder().convert(kNavigationExamplePage),
+ );
+ return webViewController.loadRequest(
+ LoadRequestParams(
+ uri: Uri.parse('data:text/html;base64,$contentBase64'),
+ ),
+ );
+ }
+
+ Future<void> _onSetCookie() async {
+ await cookieManager.setCookie(
const WebViewCookie(
- name: 'foo', value: 'bar', domain: 'httpbin.org', path: '/anything'),
+ name: 'foo',
+ value: 'bar',
+ domain: 'httpbin.org',
+ path: '/anything',
+ ),
);
- await controller.loadUrl('https://httpbin.org/anything');
+ await webViewController.loadRequest(LoadRequestParams(
+ uri: Uri.parse('https://httpbin.org/anything'),
+ ));
}
- Future<void> _onNavigationDelegateExample(
- WebViewController controller, BuildContext context) async {
- final String contentBase64 =
- base64Encode(const Utf8Encoder().convert(kNavigationExamplePage));
- await controller.loadUrl('data:text/html;base64,$contentBase64');
- }
-
- Future<void> _onLoadFlutterAssetExample(
- WebViewController controller, BuildContext context) async {
- await controller.loadFlutterAsset('assets/www/index.html');
- }
-
- Future<void> _onLoadLocalFileExample(
- WebViewController controller, BuildContext context) async {
- final String pathToIndex = await _prepareLocalFile();
-
- await controller.loadFile(pathToIndex);
- }
-
- Future<void> _onLoadHtmlStringExample(
- WebViewController controller, BuildContext context) async {
- await controller.loadHtmlString(kExamplePage);
- }
-
- Future<void> _onDoPostRequest(
- WebViewController controller, BuildContext context) async {
- final WebViewRequest request = WebViewRequest(
+ Future<void> _onDoPostRequest() {
+ return webViewController.loadRequest(LoadRequestParams(
uri: Uri.parse('https://httpbin.org/post'),
- method: WebViewRequestMethod.post,
+ method: LoadRequestMethod.post,
+ headers: const <String, String>{
+ 'foo': 'bar',
+ 'Content-Type': 'text/plain',
+ },
body: Uint8List.fromList('Test Body'.codeUnits),
- );
- await controller.loadRequest(request);
+ ));
+ }
+
+ Future<void> _onLoadLocalFileExample() async {
+ final String pathToIndex = await _prepareLocalFile();
+ await webViewController.loadFile(pathToIndex);
+ }
+
+ Future<void> _onLoadFlutterAssetExample() {
+ return webViewController.loadFlutterAsset('assets/www/index.html');
+ }
+
+ Future<void> _onLoadHtmlStringExample() {
+ return webViewController.loadHtmlString(kLocalExamplePage);
+ }
+
+ Future<void> _onTransparentBackground() {
+ return webViewController.loadHtmlString(kTransparentBackgroundPage);
}
Widget _getCookieList(String cookies) {
@@ -425,83 +436,57 @@
static Future<String> _prepareLocalFile() async {
final String tmpDir = (await getTemporaryDirectory()).path;
- final File indexFile = File('$tmpDir/www/index.html');
+ final File indexFile = File(
+ <String>{tmpDir, 'www', 'index.html'}.join(Platform.pathSeparator));
- await Directory('$tmpDir/www').create(recursive: true);
- await indexFile.writeAsString(kExamplePage);
+ await indexFile.create(recursive: true);
+ await indexFile.writeAsString(kLocalExamplePage);
return indexFile.path;
}
-
- Future<void> _onTransparentBackground(
- WebViewController controller, BuildContext context) async {
- await controller.loadHtmlString(kTransparentBackgroundPage);
- }
}
-class _NavigationControls extends StatelessWidget {
- const _NavigationControls(this._webViewControllerFuture)
- : assert(_webViewControllerFuture != null);
+class NavigationControls extends StatelessWidget {
+ const NavigationControls({Key? key, required this.webViewController})
+ : super(key: key);
- final Future<WebViewController> _webViewControllerFuture;
+ final PlatformWebViewController webViewController;
@override
Widget build(BuildContext context) {
- return FutureBuilder<WebViewController>(
- future: _webViewControllerFuture,
- builder:
- (BuildContext context, AsyncSnapshot<WebViewController> snapshot) {
- final bool webViewReady =
- snapshot.connectionState == ConnectionState.done;
- final WebViewController? controller = snapshot.data;
-
- return Row(
- children: <Widget>[
- IconButton(
- icon: const Icon(Icons.arrow_back_ios),
- onPressed: !webViewReady
- ? null
- : () async {
- if (await controller!.canGoBack()) {
- await controller.goBack();
- } else {
- ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(content: Text('No back history item')),
- );
- return;
- }
- },
- ),
- IconButton(
- icon: const Icon(Icons.arrow_forward_ios),
- onPressed: !webViewReady
- ? null
- : () async {
- if (await controller!.canGoForward()) {
- await controller.goForward();
- } else {
- ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(
- content: Text('No forward history item')),
- );
- return;
- }
- },
- ),
- IconButton(
- icon: const Icon(Icons.replay),
- onPressed: !webViewReady
- ? null
- : () {
- controller!.reload();
- },
- ),
- ],
- );
- },
+ return Row(
+ children: <Widget>[
+ IconButton(
+ icon: const Icon(Icons.arrow_back_ios),
+ onPressed: () async {
+ if (await webViewController.canGoBack()) {
+ await webViewController.goBack();
+ } else {
+ ScaffoldMessenger.of(context).showSnackBar(
+ const SnackBar(content: Text('No back history item')),
+ );
+ return;
+ }
+ },
+ ),
+ IconButton(
+ icon: const Icon(Icons.arrow_forward_ios),
+ onPressed: () async {
+ if (await webViewController.canGoForward()) {
+ await webViewController.goForward();
+ } else {
+ ScaffoldMessenger.of(context).showSnackBar(
+ const SnackBar(content: Text('No forward history item')),
+ );
+ return;
+ }
+ },
+ ),
+ IconButton(
+ icon: const Icon(Icons.replay),
+ onPressed: () => webViewController.reload(),
+ ),
+ ],
);
}
}
-
-/// Callback type for handling messages sent from JavaScript running in a web view.
-typedef JavascriptMessageHandler = void Function(JavascriptMessage message);
diff --git a/packages/webview_flutter/webview_flutter_android/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/example/pubspec.yaml
index de6980a..0daacb0 100644
--- a/packages/webview_flutter/webview_flutter_android/example/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_android/example/pubspec.yaml
@@ -18,7 +18,7 @@
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
- webview_flutter_platform_interface: ^1.8.0
+ webview_flutter_platform_interface: ^2.0.0
dev_dependencies:
espresso: ^0.2.0
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_navigation_delegate.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_navigation_delegate.dart
new file mode 100644
index 0000000..51c6276
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_navigation_delegate.dart
@@ -0,0 +1,318 @@
+// 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.
+
+import 'dart:async';
+
+import 'package:flutter/foundation.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+
+import 'android_proxy.dart';
+import 'android_webview.dart' as android_webview;
+
+/// Signature for the `loadRequest` callback responsible for loading the [url]
+/// after a navigation request has been approved.
+typedef LoadRequestCallback = Future<void> Function(LoadRequestParams params);
+
+/// Error returned in `WebView.onWebResourceError` when a web resource loading error has occurred.
+@immutable
+class AndroidWebResourceError extends WebResourceError {
+ /// Creates a new [AndroidWebResourceError].
+ AndroidWebResourceError._({
+ required super.errorCode,
+ required super.description,
+ super.isForMainFrame,
+ this.failingUrl,
+ }) : super(
+ errorType: _errorCodeToErrorType(errorCode),
+ );
+
+ /// Gets the URL for which the failing resource request was made.
+ final String? failingUrl;
+
+ static WebResourceErrorType? _errorCodeToErrorType(int errorCode) {
+ switch (errorCode) {
+ case android_webview.WebViewClient.errorAuthentication:
+ return WebResourceErrorType.authentication;
+ case android_webview.WebViewClient.errorBadUrl:
+ return WebResourceErrorType.badUrl;
+ case android_webview.WebViewClient.errorConnect:
+ return WebResourceErrorType.connect;
+ case android_webview.WebViewClient.errorFailedSslHandshake:
+ return WebResourceErrorType.failedSslHandshake;
+ case android_webview.WebViewClient.errorFile:
+ return WebResourceErrorType.file;
+ case android_webview.WebViewClient.errorFileNotFound:
+ return WebResourceErrorType.fileNotFound;
+ case android_webview.WebViewClient.errorHostLookup:
+ return WebResourceErrorType.hostLookup;
+ case android_webview.WebViewClient.errorIO:
+ return WebResourceErrorType.io;
+ case android_webview.WebViewClient.errorProxyAuthentication:
+ return WebResourceErrorType.proxyAuthentication;
+ case android_webview.WebViewClient.errorRedirectLoop:
+ return WebResourceErrorType.redirectLoop;
+ case android_webview.WebViewClient.errorTimeout:
+ return WebResourceErrorType.timeout;
+ case android_webview.WebViewClient.errorTooManyRequests:
+ return WebResourceErrorType.tooManyRequests;
+ case android_webview.WebViewClient.errorUnknown:
+ return WebResourceErrorType.unknown;
+ case android_webview.WebViewClient.errorUnsafeResource:
+ return WebResourceErrorType.unsafeResource;
+ case android_webview.WebViewClient.errorUnsupportedAuthScheme:
+ return WebResourceErrorType.unsupportedAuthScheme;
+ case android_webview.WebViewClient.errorUnsupportedScheme:
+ return WebResourceErrorType.unsupportedScheme;
+ }
+
+ throw ArgumentError(
+ 'Could not find a WebResourceErrorType for errorCode: $errorCode',
+ );
+ }
+}
+
+/// Object specifying creation parameters for creating a [AndroidNavigationDelegate].
+///
+/// When adding additional fields make sure they can be null or have a default
+/// value to avoid breaking changes. See [PlatformNavigationDelegateCreationParams] for
+/// more information.
+@immutable
+class AndroidNavigationDelegateCreationParams
+ extends PlatformNavigationDelegateCreationParams {
+ /// Creates a new [AndroidNavigationDelegateCreationParams] instance.
+ const AndroidNavigationDelegateCreationParams._({
+ @visibleForTesting this.androidWebViewProxy = const AndroidWebViewProxy(),
+ }) : super();
+
+ /// Creates a [AndroidNavigationDelegateCreationParams] instance based on [PlatformNavigationDelegateCreationParams].
+ factory AndroidNavigationDelegateCreationParams.fromPlatformNavigationDelegateCreationParams(
+ // Recommended placeholder to prevent being broken by platform interface.
+ // ignore: avoid_unused_constructor_parameters
+ PlatformNavigationDelegateCreationParams params, {
+ @visibleForTesting
+ AndroidWebViewProxy androidWebViewProxy = const AndroidWebViewProxy(),
+ }) {
+ return AndroidNavigationDelegateCreationParams._(
+ androidWebViewProxy: androidWebViewProxy,
+ );
+ }
+
+ /// Handles constructing objects and calling static methods for the Android WebView
+ /// native library.
+ @visibleForTesting
+ final AndroidWebViewProxy androidWebViewProxy;
+}
+
+/// A place to register callback methods responsible to handle navigation events
+/// triggered by the [android_webview.WebView].
+class AndroidNavigationDelegate extends PlatformNavigationDelegate {
+ /// Creates a new [AndroidNavigationkDelegate].
+ AndroidNavigationDelegate(PlatformNavigationDelegateCreationParams params)
+ : super.implementation(params is AndroidNavigationDelegateCreationParams
+ ? params
+ : AndroidNavigationDelegateCreationParams
+ .fromPlatformNavigationDelegateCreationParams(params)) {
+ final WeakReference<AndroidNavigationDelegate> weakThis =
+ WeakReference<AndroidNavigationDelegate>(this);
+
+ _webChromeClient = (this.params as AndroidNavigationDelegateCreationParams)
+ .androidWebViewProxy
+ .createAndroidWebChromeClient(
+ onProgressChanged: (android_webview.WebView webView, int progress) {
+ if (weakThis.target?._onProgress != null) {
+ weakThis.target!._onProgress!(progress);
+ }
+ });
+
+ _webViewClient = (this.params as AndroidNavigationDelegateCreationParams)
+ .androidWebViewProxy
+ .createAndroidWebViewClient(
+ onPageFinished: (android_webview.WebView webView, String url) {
+ if (weakThis.target?._onPageFinished != null) {
+ weakThis.target!._onPageFinished!(url);
+ }
+ },
+ onPageStarted: (android_webview.WebView webView, String url) {
+ if (weakThis.target?._onPageStarted != null) {
+ weakThis.target!._onPageStarted!(url);
+ }
+ },
+ onReceivedRequestError: (
+ android_webview.WebView webView,
+ android_webview.WebResourceRequest request,
+ android_webview.WebResourceError error,
+ ) {
+ if (weakThis.target?._onWebResourceError != null) {
+ weakThis.target!._onWebResourceError!(AndroidWebResourceError._(
+ errorCode: error.errorCode,
+ description: error.description,
+ failingUrl: request.url,
+ isForMainFrame: request.isForMainFrame,
+ ));
+ }
+ },
+ onReceivedError: (
+ android_webview.WebView webView,
+ int errorCode,
+ String description,
+ String failingUrl,
+ ) {
+ if (weakThis.target?._onWebResourceError != null) {
+ weakThis.target!._onWebResourceError!(AndroidWebResourceError._(
+ errorCode: errorCode,
+ description: description,
+ failingUrl: failingUrl,
+ isForMainFrame: true,
+ ));
+ }
+ },
+ requestLoading: (
+ android_webview.WebView webView,
+ android_webview.WebResourceRequest request,
+ ) {
+ if (weakThis.target != null) {
+ weakThis.target!._handleNavigation(
+ request.url,
+ headers: request.requestHeaders,
+ isForMainFrame: request.isForMainFrame,
+ );
+ }
+ },
+ urlLoading: (
+ android_webview.WebView webView,
+ String url,
+ ) {
+ if (weakThis.target != null) {
+ weakThis.target!._handleNavigation(url, isForMainFrame: true);
+ }
+ },
+ );
+
+ _downloadListener = (this.params as AndroidNavigationDelegateCreationParams)
+ .androidWebViewProxy
+ .createDownloadListener(
+ onDownloadStart: (
+ String url,
+ String userAgent,
+ String contentDisposition,
+ String mimetype,
+ int contentLength,
+ ) {
+ if (weakThis.target != null) {
+ weakThis.target?._handleNavigation(url, isForMainFrame: true);
+ }
+ },
+ );
+ }
+
+ late final android_webview.WebChromeClient _webChromeClient;
+
+ /// Gets the native [android_webview.WebChromeClient] that is bridged by this [AndroidNavigationDelegate].
+ ///
+ /// Used by the [AndroidWebViewController] to set the `android_webview.WebView.setWebChromeClient`.
+ android_webview.WebChromeClient get androidWebChromeClient =>
+ _webChromeClient;
+
+ late final android_webview.WebViewClient _webViewClient;
+
+ /// Gets the native [android_webview.WebViewClient] that is bridged by this [AndroidNavigationDelegate].
+ ///
+ /// Used by the [AndroidWebViewController] to set the `android_webview.WebView.setWebViewClient`.
+ android_webview.WebViewClient get androidWebViewClient => _webViewClient;
+
+ late final android_webview.DownloadListener _downloadListener;
+
+ /// Gets the native [android_webview.DownloadListener] that is bridged by this [AndroidNavigationDelegate].
+ ///
+ /// Used by the [AndroidWebViewController] to set the `android_webview.WebView.setDownloadListener`.
+ android_webview.DownloadListener get androidDownloadListener =>
+ _downloadListener;
+
+ PageEventCallback? _onPageFinished;
+ PageEventCallback? _onPageStarted;
+ ProgressCallback? _onProgress;
+ WebResourceErrorCallback? _onWebResourceError;
+ NavigationRequestCallback? _onNavigationRequest;
+ LoadRequestCallback? _onLoadRequest;
+
+ void _handleNavigation(
+ String url, {
+ required bool isForMainFrame,
+ Map<String, String> headers = const <String, String>{},
+ }) {
+ final LoadRequestCallback? onLoadRequest = _onLoadRequest;
+ final NavigationRequestCallback? onNavigationRequest = _onNavigationRequest;
+
+ if (onNavigationRequest == null || onLoadRequest == null) {
+ return;
+ }
+
+ final FutureOr<NavigationDecision> returnValue = onNavigationRequest(
+ NavigationRequest(
+ url: url,
+ isMainFrame: isForMainFrame,
+ ),
+ );
+
+ if (returnValue is NavigationDecision &&
+ returnValue == NavigationDecision.navigate) {
+ onLoadRequest(LoadRequestParams(
+ uri: Uri.parse(url),
+ headers: headers,
+ ));
+ } else if (returnValue is Future<NavigationDecision>) {
+ returnValue.then((NavigationDecision shouldLoadUrl) {
+ if (shouldLoadUrl == NavigationDecision.navigate) {
+ onLoadRequest(LoadRequestParams(
+ uri: Uri.parse(url),
+ headers: headers,
+ ));
+ }
+ });
+ }
+ }
+
+ /// Invoked when loading the url after a navigation request is approved.
+ Future<void> setOnLoadRequest(
+ LoadRequestCallback onLoadRequest,
+ ) async {
+ _onLoadRequest = onLoadRequest;
+ }
+
+ @override
+ Future<void> setOnNavigationRequest(
+ NavigationRequestCallback onNavigationRequest,
+ ) async {
+ _onNavigationRequest = onNavigationRequest;
+ _webViewClient.setSynchronousReturnValueForShouldOverrideUrlLoading(true);
+ }
+
+ @override
+ Future<void> setOnPageStarted(
+ PageEventCallback onPageStarted,
+ ) async {
+ _onPageStarted = onPageStarted;
+ }
+
+ @override
+ Future<void> setOnPageFinished(
+ PageEventCallback onPageFinished,
+ ) async {
+ _onPageFinished = onPageFinished;
+ }
+
+ @override
+ Future<void> setOnProgress(
+ ProgressCallback onProgress,
+ ) async {
+ _onProgress = onProgress;
+ }
+
+ @override
+ Future<void> setOnWebResourceError(
+ WebResourceErrorCallback onWebResourceError,
+ ) async {
+ _onWebResourceError = onWebResourceError;
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_proxy.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_proxy.dart
new file mode 100644
index 0000000..db247ee
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_proxy.dart
@@ -0,0 +1,101 @@
+// 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.
+
+import 'android_webview.dart' as android_webview;
+
+/// Handles constructing objects and calling static methods for the Android
+/// WebView native library.
+///
+/// This class provides dependency injection for the implementations of the
+/// platform interface classes. Improving the ease of unit testing and/or
+/// overriding the underlying Android WebView classes.
+///
+/// By default each function calls the default constructor of the WebView class
+/// it intends to return.
+class AndroidWebViewProxy {
+ /// Constructs a [AndroidWebViewProxy].
+ const AndroidWebViewProxy({
+ this.createAndroidWebView = android_webview.WebView.new,
+ this.createAndroidWebChromeClient = android_webview.WebChromeClient.new,
+ this.createAndroidWebViewClient = android_webview.WebViewClient.new,
+ this.createFlutterAssetManager = android_webview.FlutterAssetManager.new,
+ this.createJavaScriptChannel = android_webview.JavaScriptChannel.new,
+ this.createDownloadListener = android_webview.DownloadListener.new,
+ });
+
+ /// Constructs a [android_webview.WebView].
+ ///
+ /// Due to changes in Flutter 3.0 the [useHybridComposition] doesn't have
+ /// any effect and should not be exposed publicly. More info here:
+ /// https://github.com/flutter/flutter/issues/108106
+ final android_webview.WebView Function({
+ required bool useHybridComposition,
+ }) createAndroidWebView;
+
+ /// Constructs a [android_webview.WebChromeClient].
+ final android_webview.WebChromeClient Function({
+ void Function(android_webview.WebView webView, int progress)?
+ onProgressChanged,
+ }) createAndroidWebChromeClient;
+
+ /// Constructs a [android_webview.WebViewClient].
+ final android_webview.WebViewClient Function({
+ void Function(android_webview.WebView webView, String url)? onPageStarted,
+ void Function(android_webview.WebView webView, String url)? onPageFinished,
+ void Function(
+ android_webview.WebView webView,
+ android_webview.WebResourceRequest request,
+ android_webview.WebResourceError error,
+ )?
+ onReceivedRequestError,
+ @Deprecated('Only called on Android version < 23.')
+ void Function(
+ android_webview.WebView webView,
+ int errorCode,
+ String description,
+ String failingUrl,
+ )?
+ onReceivedError,
+ void Function(
+ android_webview.WebView webView,
+ android_webview.WebResourceRequest request,
+ )?
+ requestLoading,
+ void Function(android_webview.WebView webView, String url)? urlLoading,
+ }) createAndroidWebViewClient;
+
+ /// Constructs a [android_webview.FlutterAssetManager].
+ final android_webview.FlutterAssetManager Function()
+ createFlutterAssetManager;
+
+ /// Constructs a [android_webview.JavaScriptChannel].
+ final android_webview.JavaScriptChannel Function(
+ String channelName, {
+ required void Function(String) postMessage,
+ }) createJavaScriptChannel;
+
+ /// Constructs a [android_webview.DownloadListener].
+ final android_webview.DownloadListener Function({
+ required void Function(
+ String url,
+ String userAgent,
+ String contentDisposition,
+ String mimetype,
+ int contentLength,
+ )
+ onDownloadStart,
+ }) createDownloadListener;
+
+ /// Enables debugging of web contents (HTML / CSS / JavaScript) loaded into any WebViews of this application.
+ ///
+ /// This flag can be enabled in order to facilitate debugging of web layouts
+ /// and JavaScript code running inside WebViews. Please refer to
+ /// [android_webview.WebView] documentation for the debugging guide. The
+ /// default is false.
+ ///
+ /// See [android_webview.WebView].setWebContentsDebuggingEnabled.
+ Future<void> setWebContentsDebuggingEnabled(bool enabled) {
+ return android_webview.WebView.setWebContentsDebuggingEnabled(enabled);
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart
index e087031..66f93dd 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.dart
@@ -38,7 +38,9 @@
/// Global instance of [InstanceManager].
static final InstanceManager globalInstanceManager = InstanceManager(
- onWeakReferenceRemoved: (_) {},
+ onWeakReferenceRemoved: (int identifier) {
+ JavaObjectHostApiImpl().dispose(identifier);
+ },
);
/// Pigeon Host Api implementation for [JavaObject].
@@ -76,6 +78,10 @@
/// When a [WebView] is no longer needed [release] must be called.
class WebView extends JavaObject {
/// Constructs a new WebView.
+ ///
+ /// Due to changes in Flutter 3.0 the [useHybridComposition] doesn't have
+ /// any effect and should not be exposed publicly. More info here:
+ /// https://github.com/flutter/flutter/issues/108106
WebView({this.useHybridComposition = false}) : super.detached() {
api.createFromInstance(this);
}
@@ -90,8 +96,6 @@
@visibleForTesting
static WebViewHostApiImpl api = WebViewHostApiImpl();
- WebViewClient? _currentWebViewClient;
-
/// Whether the [WebView] will be rendered with an [AndroidViewSurface].
///
/// This implementation uses hybrid composition to render the WebView Widget.
@@ -330,8 +334,6 @@
///
/// This will replace the current handler.
Future<void> setWebViewClient(WebViewClient webViewClient) {
- _currentWebViewClient = webViewClient;
- WebViewClient.api.createFromInstance(webViewClient);
return api.setWebViewClientFromInstance(this, webViewClient);
}
@@ -375,11 +377,8 @@
/// Registers the interface to be used when content can not be handled by the rendering engine, and should be downloaded instead.
///
/// This will replace the current handler.
- Future<void> setDownloadListener(DownloadListener? listener) async {
- await Future.wait(<Future<void>>[
- if (listener != null) DownloadListener.api.createFromInstance(listener),
- api.setDownloadListenerFromInstance(this, listener)
- ]);
+ Future<void> setDownloadListener(DownloadListener? listener) {
+ return api.setDownloadListenerFromInstance(this, listener);
}
/// Sets the chrome handler.
@@ -387,20 +386,8 @@
/// This is an implementation of [WebChromeClient] for use in handling
/// JavaScript dialogs, favicons, titles, and the progress. This will replace
/// the current handler.
- Future<void> setWebChromeClient(WebChromeClient? client) async {
- // WebView requires a WebViewClient because of a bug fix that makes
- // calls to WebViewClient.requestLoading/WebViewClient.urlLoading when a new
- // window is opened. This is to make sure a url opened by `Window.open` has
- // a secure url.
- assert(
- _currentWebViewClient != null,
- "Can't set a WebChromeClient without setting a WebViewClient first.",
- );
- await Future.wait(<Future<void>>[
- if (client != null)
- WebChromeClient.api.createFromInstance(client, _currentWebViewClient!),
- api.setWebChromeClientFromInstance(this, client),
- ]);
+ Future<void> setWebChromeClient(WebChromeClient? client) {
+ return api.setWebChromeClientFromInstance(this, client);
}
/// Sets the background color of this WebView.
@@ -408,15 +395,6 @@
return api.setBackgroundColorFromInstance(this, color.value);
}
- /// Releases all resources used by the [WebView].
- ///
- /// Any methods called after [release] will throw an exception.
- Future<void> release() {
- _currentWebViewClient = null;
- WebSettings.api.disposeFromInstance(settings);
- return api.disposeFromInstance(this);
- }
-
@override
WebView copy() {
return WebView.detached(useHybridComposition: useHybridComposition);
@@ -624,9 +602,10 @@
/// Constructs a [JavaScriptChannel].
JavaScriptChannel(
this.channelName, {
- void Function(String message)? postMessage,
+ required this.postMessage,
}) : super.detached() {
AndroidWebViewFlutterApis.instance.ensureSetUp();
+ api.createFromInstance(this);
}
/// Constructs a [JavaScriptChannel] without creating the associated Java
@@ -636,7 +615,7 @@
/// create copies.
JavaScriptChannel.detached(
this.channelName, {
- void Function(String message)? postMessage,
+ required this.postMessage,
}) : super.detached();
/// Pigeon Host Api implementation for [JavaScriptChannel].
@@ -647,7 +626,7 @@
final String channelName;
/// Callback method when javaScript calls `postMessage` on the object instance passed.
- void postMessage(String message) {}
+ final void Function(String message) postMessage;
@override
JavaScriptChannel copy() {
@@ -659,26 +638,15 @@
class WebViewClient extends JavaObject {
/// Constructs a [WebViewClient].
WebViewClient({
- this.shouldOverrideUrlLoading = true,
- void Function(WebView webView, String url)? onPageStarted,
- void Function(WebView webView, String url)? onPageFinished,
- void Function(
- WebView webView,
- WebResourceRequest request,
- WebResourceError error,
- )?
- onReceivedRequestError,
- void Function(
- WebView webView,
- int errorCode,
- String description,
- String failingUrl,
- )?
- onReceivedError,
- void Function(WebView webView, WebResourceRequest request)? requestLoading,
- void Function(WebView webView, String url)? urlLoading,
+ this.onPageStarted,
+ this.onPageFinished,
+ this.onReceivedRequestError,
+ @Deprecated('Only called on Android version < 23.') this.onReceivedError,
+ this.requestLoading,
+ this.urlLoading,
}) : super.detached() {
AndroidWebViewFlutterApis.instance.ensureSetUp();
+ api.createFromInstance(this);
}
/// Constructs a [WebViewClient] without creating the associated Java object.
@@ -686,24 +654,12 @@
/// This should only be used by subclasses created by this library or to
/// create copies.
WebViewClient.detached({
- this.shouldOverrideUrlLoading = true,
- void Function(WebView webView, String url)? onPageStarted,
- void Function(WebView webView, String url)? onPageFinished,
- void Function(
- WebView webView,
- WebResourceRequest request,
- WebResourceError error,
- )?
- onReceivedRequestError,
- void Function(
- WebView webView,
- int errorCode,
- String description,
- String failingUrl,
- )?
- onReceivedError,
- void Function(WebView webView, WebResourceRequest request)? requestLoading,
- void Function(WebView webView, String url)? urlLoading,
+ this.onPageStarted,
+ this.onPageFinished,
+ this.onReceivedRequestError,
+ @Deprecated('Only called on Android version < 23.') this.onReceivedError,
+ this.requestLoading,
+ this.urlLoading,
}) : super.detached();
/// User authentication failed on server.
@@ -790,20 +746,6 @@
@visibleForTesting
static WebViewClientHostApiImpl api = WebViewClientHostApiImpl();
- /// Whether loading a url should be overridden.
- ///
- /// In Java, `shouldOverrideUrlLoading()` and `shouldOverrideRequestLoading()`
- /// callbacks must synchronously return a boolean. This sets the default
- /// return value.
- ///
- /// Setting [shouldOverrideUrlLoading] to true causes the current [WebView] to
- /// abort loading the URL, while returning false causes the [WebView] to
- /// continue loading the URL as usual. [requestLoading] or [urlLoading] will
- /// still be called either way.
- ///
- /// Defaults to true.
- final bool shouldOverrideUrlLoading;
-
/// Notify the host application that a page has started loading.
///
/// This method is called once for each main frame load so a page with iframes
@@ -812,7 +754,7 @@
/// embedded frame changes, i.e. clicking a link whose target is an iframe, it
/// will also not be called for fragment navigations (navigations to
/// #fragment_id).
- void onPageStarted(WebView webView, String url) {}
+ final void Function(WebView webView, String url)? onPageStarted;
// TODO(bparrishMines): Update documentation when WebView.postVisualStateCallback is added.
/// Notify the host application that a page has finished loading.
@@ -820,7 +762,7 @@
/// This method is called only for main frame. Receiving an [onPageFinished]
/// callback does not guarantee that the next frame drawn by WebView will
/// reflect the state of the DOM at this point.
- void onPageFinished(WebView webView, String url) {}
+ final void Function(WebView webView, String url)? onPageFinished;
/// Report web resource loading error to the host application.
///
@@ -829,48 +771,58 @@
/// be called for any resource (iframe, image, etc.), not just for the main
/// page. Thus, it is recommended to perform minimum required work in this
/// callback.
- void onReceivedRequestError(
+ final void Function(
WebView webView,
WebResourceRequest request,
WebResourceError error,
- ) {}
+ )? onReceivedRequestError;
/// Report an error to the host application.
///
/// These errors are unrecoverable (i.e. the main resource is unavailable).
/// The errorCode parameter corresponds to one of the error* constants.
@Deprecated('Only called on Android version < 23.')
- void onReceivedError(
+ final void Function(
WebView webView,
int errorCode,
String description,
String failingUrl,
- ) {}
+ )? onReceivedError;
- // TODO(bparrishMines): Update documentation once synchronous url handling is supported.
- /// When a URL is about to be loaded in the current [WebView].
+ /// When the current [WebView] wants to load a URL.
///
- /// If a [WebViewClient] is not provided, by default [WebView] will ask
- /// Activity Manager to choose the proper handler for the URL. If a
- /// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true
- /// causes the current [WebView] to abort loading the URL, while returning
- /// false causes the [WebView] to continue loading the URL as usual.
- void requestLoading(WebView webView, WebResourceRequest request) {}
+ /// The value set by [setSynchronousReturnValueForShouldOverrideUrlLoading]
+ /// indicates whether the [WebView] loaded the request.
+ final void Function(WebView webView, WebResourceRequest request)?
+ requestLoading;
- // TODO(bparrishMines): Update documentation once synchronous url handling is supported.
- /// When a URL is about to be loaded in the current [WebView].
+ /// When the current [WebView] wants to load a URL.
///
- /// If a [WebViewClient] is not provided, by default [WebView] will ask
- /// Activity Manager to choose the proper handler for the URL. If a
- /// [WebViewClient] is provided, setting [shouldOverrideUrlLoading] to true
- /// causes the current [WebView] to abort loading the URL, while returning
- /// false causes the [WebView] to continue loading the URL as usual.
- void urlLoading(WebView webView, String url) {}
+ /// The value set by [setSynchronousReturnValueForShouldOverrideUrlLoading]
+ /// indicates whether the [WebView] loaded the URL.
+ final void Function(WebView webView, String url)? urlLoading;
+
+ /// Sets the required synchronous return value for the Java method,
+ /// `WebViewClient.shouldOverrideUrlLoading(...)`.
+ ///
+ /// The Java method, `WebViewClient.shouldOverrideUrlLoading(...)`, requires
+ /// a boolean to be returned and this method sets the returned value for all
+ /// calls to the Java method.
+ ///
+ /// Setting this to true causes the current [WebView] to abort loading any URL
+ /// received by [requestLoading] or [urlLoading], while setting this to false
+ /// causes the [WebView] to continue loading a URL as usual.
+ ///
+ /// Defaults to false.
+ Future<void> setSynchronousReturnValueForShouldOverrideUrlLoading(
+ bool value,
+ ) {
+ return api.setShouldOverrideUrlLoadingReturnValueFromInstance(this, value);
+ }
@override
WebViewClient copy() {
return WebViewClient.detached(
- shouldOverrideUrlLoading: shouldOverrideUrlLoading,
onPageStarted: onPageStarted,
onPageFinished: onPageFinished,
onReceivedRequestError: onReceivedRequestError,
@@ -885,17 +837,9 @@
/// engine for [WebView], and should be downloaded instead.
class DownloadListener extends JavaObject {
/// Constructs a [DownloadListener].
- DownloadListener({
- void Function(
- String url,
- String userAgent,
- String contentDisposition,
- String mimetype,
- int contentLength,
- )?
- onDownloadStart,
- }) : super.detached() {
+ DownloadListener({required this.onDownloadStart}) : super.detached() {
AndroidWebViewFlutterApis.instance.ensureSetUp();
+ api.createFromInstance(this);
}
/// Constructs a [DownloadListener] without creating the associated Java
@@ -903,43 +847,33 @@
///
/// This should only be used by subclasses created by this library or to
/// create copies.
- DownloadListener.detached({
- void Function(
- String url,
- String userAgent,
- String contentDisposition,
- String mimetype,
- int contentLength,
- )?
- onDownloadStart,
- }) : super.detached();
+ DownloadListener.detached({required this.onDownloadStart}) : super.detached();
/// Pigeon Host Api implementation for [DownloadListener].
@visibleForTesting
static DownloadListenerHostApiImpl api = DownloadListenerHostApiImpl();
/// Notify the host application that a file should be downloaded.
- void onDownloadStart(
+ final void Function(
String url,
String userAgent,
String contentDisposition,
String mimetype,
int contentLength,
- ) {}
+ ) onDownloadStart;
@override
DownloadListener copy() {
- return DownloadListener(onDownloadStart: onDownloadStart);
+ return DownloadListener.detached(onDownloadStart: onDownloadStart);
}
}
/// Handles JavaScript dialogs, favicons, titles, and the progress for [WebView].
class WebChromeClient extends JavaObject {
/// Constructs a [WebChromeClient].
- WebChromeClient({
- void Function(WebView webView, int progress)? onProgressChanged,
- }) : super.detached() {
+ WebChromeClient({this.onProgressChanged}) : super.detached() {
AndroidWebViewFlutterApis.instance.ensureSetUp();
+ api.createFromInstance(this);
}
/// Constructs a [WebChromeClient] without creating the associated Java
@@ -947,16 +881,14 @@
///
/// This should only be used by subclasses created by this library or to
/// create copies.
- WebChromeClient.detached({
- void Function(WebView webView, int progress)? onProgressChanged,
- }) : super.detached();
+ WebChromeClient.detached({this.onProgressChanged}) : super.detached();
/// Pigeon Host Api implementation for [WebChromeClient].
@visibleForTesting
static WebChromeClientHostApiImpl api = WebChromeClientHostApiImpl();
/// Notify the host application that a file should be downloaded.
- void onProgressChanged(WebView webView, int progress) {}
+ final void Function(WebView webView, int progress)? onProgressChanged;
@override
WebChromeClient copy() {
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart
index e793dbb..5bdab16 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview.pigeon.dart
@@ -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 (v4.0.2), do not edit directly.
+// Autogenerated from Pigeon (v4.2.3), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
import 'dart:async';
@@ -102,20 +102,20 @@
}
}
-class _JavaObjectHostApiCodec extends StandardMessageCodec {
- const _JavaObjectHostApiCodec();
-}
-
+/// Handles methods calls to the native Java Object class.
+///
+/// Also handles calls to remove the reference to an instance with `dispose`.
+///
+/// See https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html.
class JavaObjectHostApi {
/// Constructor for [JavaObjectHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
JavaObjectHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
- static const MessageCodec<Object?> codec = _JavaObjectHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<void> dispose(int arg_identifier) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
@@ -142,12 +142,11 @@
}
}
-class _JavaObjectFlutterApiCodec extends StandardMessageCodec {
- const _JavaObjectFlutterApiCodec();
-}
-
+/// Handles callbacks methods for the native Java Object class.
+///
+/// See https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html.
abstract class JavaObjectFlutterApi {
- static const MessageCodec<Object?> codec = _JavaObjectFlutterApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
void dispose(int identifier);
static void setup(JavaObjectFlutterApi? api,
@@ -174,20 +173,15 @@
}
}
-class _CookieManagerHostApiCodec extends StandardMessageCodec {
- const _CookieManagerHostApiCodec();
-}
-
class CookieManagerHostApi {
/// Constructor for [CookieManagerHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
CookieManagerHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
- static const MessageCodec<Object?> codec = _CookieManagerHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<bool> clearCookies() async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
@@ -273,7 +267,6 @@
/// BinaryMessenger will be used which routes to the host platform.
WebViewHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
static const MessageCodec<Object?> codec = _WebViewHostApiCodec();
@@ -303,30 +296,6 @@
}
}
- Future<void> dispose(int arg_instanceId) async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.WebViewHostApi.dispose', codec,
- binaryMessenger: _binaryMessenger);
- final Map<Object?, Object?>? replyMap =
- await channel.send(<Object?>[arg_instanceId]) as Map<Object?, Object?>?;
- if (replyMap == null) {
- throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
- );
- } else if (replyMap['error'] != null) {
- final Map<Object?, Object?> error =
- (replyMap['error'] as Map<Object?, Object?>?)!;
- throw PlatformException(
- code: (error['code'] as String?)!,
- message: error['message'] as String?,
- details: error['details'],
- );
- } else {
- return;
- }
- }
-
Future<void> loadData(int arg_instanceId, String arg_data,
String? arg_mimeType, String? arg_encoding) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
@@ -987,20 +956,15 @@
}
}
-class _WebSettingsHostApiCodec extends StandardMessageCodec {
- const _WebSettingsHostApiCodec();
-}
-
class WebSettingsHostApi {
/// Constructor for [WebSettingsHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
WebSettingsHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
- static const MessageCodec<Object?> codec = _WebSettingsHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<void> create(int arg_instanceId, int arg_webViewInstanceId) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
@@ -1027,30 +991,6 @@
}
}
- Future<void> dispose(int arg_instanceId) async {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.WebSettingsHostApi.dispose', codec,
- binaryMessenger: _binaryMessenger);
- final Map<Object?, Object?>? replyMap =
- await channel.send(<Object?>[arg_instanceId]) as Map<Object?, Object?>?;
- if (replyMap == null) {
- throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
- );
- } else if (replyMap['error'] != null) {
- final Map<Object?, Object?> error =
- (replyMap['error'] as Map<Object?, Object?>?)!;
- throw PlatformException(
- code: (error['code'] as String?)!,
- message: error['message'] as String?,
- details: error['details'],
- );
- } else {
- return;
- }
- }
-
Future<void> setDomStorageEnabled(int arg_instanceId, bool arg_flag) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled', codec,
@@ -1352,20 +1292,15 @@
}
}
-class _JavaScriptChannelHostApiCodec extends StandardMessageCodec {
- const _JavaScriptChannelHostApiCodec();
-}
-
class JavaScriptChannelHostApi {
/// Constructor for [JavaScriptChannelHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
JavaScriptChannelHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
- static const MessageCodec<Object?> codec = _JavaScriptChannelHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<void> create(int arg_instanceId, String arg_channelName) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
@@ -1393,39 +1328,14 @@
}
}
-class _JavaScriptChannelFlutterApiCodec extends StandardMessageCodec {
- const _JavaScriptChannelFlutterApiCodec();
-}
-
abstract class JavaScriptChannelFlutterApi {
- static const MessageCodec<Object?> codec =
- _JavaScriptChannelFlutterApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
- void dispose(int instanceId);
void postMessage(int instanceId, String message);
static void setup(JavaScriptChannelFlutterApi? api,
{BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.JavaScriptChannelFlutterApi.dispose', codec,
- binaryMessenger: binaryMessenger);
- if (api == null) {
- channel.setMessageHandler(null);
- } else {
- channel.setMessageHandler((Object? message) async {
- assert(message != null,
- 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.dispose was null.');
- final List<Object?> args = (message as List<Object?>?)!;
- final int? arg_instanceId = (args[0] as int?);
- assert(arg_instanceId != null,
- 'Argument for dev.flutter.pigeon.JavaScriptChannelFlutterApi.dispose was null, expected non-null int.');
- api.dispose(arg_instanceId!);
- return;
- });
- }
- }
- {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.JavaScriptChannelFlutterApi.postMessage', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
@@ -1449,29 +1359,48 @@
}
}
-class _WebViewClientHostApiCodec extends StandardMessageCodec {
- const _WebViewClientHostApiCodec();
-}
-
class WebViewClientHostApi {
/// Constructor for [WebViewClientHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
WebViewClientHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
- static const MessageCodec<Object?> codec = _WebViewClientHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
- Future<void> create(
- int arg_instanceId, bool arg_shouldOverrideUrlLoading) async {
+ Future<void> create(int arg_instanceId) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebViewClientHostApi.create', codec,
binaryMessenger: _binaryMessenger);
+ final Map<Object?, Object?>? replyMap =
+ await channel.send(<Object?>[arg_instanceId]) as Map<Object?, Object?>?;
+ if (replyMap == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyMap['error'] != null) {
+ final Map<Object?, Object?> error =
+ (replyMap['error'] as Map<Object?, Object?>?)!;
+ throw PlatformException(
+ code: (error['code'] as String?)!,
+ message: error['message'] as String?,
+ details: error['details'],
+ );
+ } else {
+ return;
+ }
+ }
+
+ Future<void> setSynchronousReturnValueForShouldOverrideUrlLoading(
+ int arg_instanceId, bool arg_value) async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.WebViewClientHostApi.setSynchronousReturnValueForShouldOverrideUrlLoading',
+ codec,
+ binaryMessenger: _binaryMessenger);
final Map<Object?, Object?>? replyMap = await channel
- .send(<Object?>[arg_instanceId, arg_shouldOverrideUrlLoading])
- as Map<Object?, Object?>?;
+ .send(<Object?>[arg_instanceId, arg_value]) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
@@ -1524,7 +1453,6 @@
abstract class WebViewClientFlutterApi {
static const MessageCodec<Object?> codec = _WebViewClientFlutterApiCodec();
- void dispose(int instanceId);
void onPageStarted(int instanceId, int webViewInstanceId, String url);
void onPageFinished(int instanceId, int webViewInstanceId, String url);
void onReceivedRequestError(int instanceId, int webViewInstanceId,
@@ -1538,25 +1466,6 @@
{BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.WebViewClientFlutterApi.dispose', codec,
- binaryMessenger: binaryMessenger);
- if (api == null) {
- channel.setMessageHandler(null);
- } else {
- channel.setMessageHandler((Object? message) async {
- assert(message != null,
- 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.dispose was null.');
- final List<Object?> args = (message as List<Object?>?)!;
- final int? arg_instanceId = (args[0] as int?);
- assert(arg_instanceId != null,
- 'Argument for dev.flutter.pigeon.WebViewClientFlutterApi.dispose was null, expected non-null int.');
- api.dispose(arg_instanceId!);
- return;
- });
- }
- }
- {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebViewClientFlutterApi.onPageStarted', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
@@ -1724,20 +1633,15 @@
}
}
-class _DownloadListenerHostApiCodec extends StandardMessageCodec {
- const _DownloadListenerHostApiCodec();
-}
-
class DownloadListenerHostApi {
/// Constructor for [DownloadListenerHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
DownloadListenerHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
- static const MessageCodec<Object?> codec = _DownloadListenerHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<void> create(int arg_instanceId) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
@@ -1764,39 +1668,15 @@
}
}
-class _DownloadListenerFlutterApiCodec extends StandardMessageCodec {
- const _DownloadListenerFlutterApiCodec();
-}
-
abstract class DownloadListenerFlutterApi {
- static const MessageCodec<Object?> codec = _DownloadListenerFlutterApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
- void dispose(int instanceId);
void onDownloadStart(int instanceId, String url, String userAgent,
String contentDisposition, String mimetype, int contentLength);
static void setup(DownloadListenerFlutterApi? api,
{BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.DownloadListenerFlutterApi.dispose', codec,
- binaryMessenger: binaryMessenger);
- if (api == null) {
- channel.setMessageHandler(null);
- } else {
- channel.setMessageHandler((Object? message) async {
- assert(message != null,
- 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.dispose was null.');
- final List<Object?> args = (message as List<Object?>?)!;
- final int? arg_instanceId = (args[0] as int?);
- assert(arg_instanceId != null,
- 'Argument for dev.flutter.pigeon.DownloadListenerFlutterApi.dispose was null, expected non-null int.');
- api.dispose(arg_instanceId!);
- return;
- });
- }
- }
- {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.DownloadListenerFlutterApi.onDownloadStart',
codec,
binaryMessenger: binaryMessenger);
@@ -1834,29 +1714,22 @@
}
}
-class _WebChromeClientHostApiCodec extends StandardMessageCodec {
- const _WebChromeClientHostApiCodec();
-}
-
class WebChromeClientHostApi {
/// Constructor for [WebChromeClientHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
WebChromeClientHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
- static const MessageCodec<Object?> codec = _WebChromeClientHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
- Future<void> create(
- int arg_instanceId, int arg_webViewClientInstanceId) async {
+ Future<void> create(int arg_instanceId) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebChromeClientHostApi.create', codec,
binaryMessenger: _binaryMessenger);
- final Map<Object?, Object?>? replyMap = await channel
- .send(<Object?>[arg_instanceId, arg_webViewClientInstanceId])
- as Map<Object?, Object?>?;
+ final Map<Object?, Object?>? replyMap =
+ await channel.send(<Object?>[arg_instanceId]) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
@@ -1876,20 +1749,15 @@
}
}
-class _FlutterAssetManagerHostApiCodec extends StandardMessageCodec {
- const _FlutterAssetManagerHostApiCodec();
-}
-
class FlutterAssetManagerHostApi {
/// Constructor for [FlutterAssetManagerHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
FlutterAssetManagerHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
- static const MessageCodec<Object?> codec = _FlutterAssetManagerHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<List<String?>> list(String arg_path) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
@@ -1951,38 +1819,14 @@
}
}
-class _WebChromeClientFlutterApiCodec extends StandardMessageCodec {
- const _WebChromeClientFlutterApiCodec();
-}
-
abstract class WebChromeClientFlutterApi {
- static const MessageCodec<Object?> codec = _WebChromeClientFlutterApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
- void dispose(int instanceId);
void onProgressChanged(int instanceId, int webViewInstanceId, int progress);
static void setup(WebChromeClientFlutterApi? api,
{BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.WebChromeClientFlutterApi.dispose', codec,
- binaryMessenger: binaryMessenger);
- if (api == null) {
- channel.setMessageHandler(null);
- } else {
- channel.setMessageHandler((Object? message) async {
- assert(message != null,
- 'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.dispose was null.');
- final List<Object?> args = (message as List<Object?>?)!;
- final int? arg_instanceId = (args[0] as int?);
- assert(arg_instanceId != null,
- 'Argument for dev.flutter.pigeon.WebChromeClientFlutterApi.dispose was null, expected non-null int.');
- api.dispose(arg_instanceId!);
- return;
- });
- }
- }
- {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebChromeClientFlutterApi.onProgressChanged',
codec,
binaryMessenger: binaryMessenger);
@@ -2011,20 +1855,15 @@
}
}
-class _WebStorageHostApiCodec extends StandardMessageCodec {
- const _WebStorageHostApiCodec();
-}
-
class WebStorageHostApi {
/// Constructor for [WebStorageHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
WebStorageHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
-
final BinaryMessenger? _binaryMessenger;
- static const MessageCodec<Object?> codec = _WebStorageHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<void> create(int arg_instanceId) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart
index 4f2c51c..8aa5f7d 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_api_impls.dart
@@ -128,10 +128,9 @@
class WebViewHostApiImpl extends WebViewHostApi {
/// Constructs a [WebViewHostApiImpl].
WebViewHostApiImpl({
- BinaryMessenger? binaryMessenger,
+ super.binaryMessenger,
InstanceManager? instanceManager,
- }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
- super(binaryMessenger: binaryMessenger);
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
/// Maintains instances stored to communicate with java objects.
final InstanceManager instanceManager;
@@ -144,15 +143,6 @@
);
}
- /// Helper method to convert instances ids to objects.
- Future<void> disposeFromInstance(WebView instance) async {
- final int? instanceId = instanceManager.getIdentifier(instance);
- if (instanceId != null) {
- instanceManager.remove(instanceId);
- await dispose(instanceId);
- }
- }
-
/// Helper method to convert the instances ids to objects.
Future<void> loadDataFromInstance(
WebView instance,
@@ -351,10 +341,9 @@
class WebSettingsHostApiImpl extends WebSettingsHostApi {
/// Constructs a [WebSettingsHostApiImpl].
WebSettingsHostApiImpl({
- BinaryMessenger? binaryMessenger,
+ super.binaryMessenger,
InstanceManager? instanceManager,
- }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
- super(binaryMessenger: binaryMessenger);
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
/// Maintains instances stored to communicate with java objects.
final InstanceManager instanceManager;
@@ -368,15 +357,6 @@
}
/// Helper method to convert instances ids to objects.
- Future<void> disposeFromInstance(WebSettings instance) async {
- final int? instanceId = instanceManager.getIdentifier(instance);
- if (instanceId != null) {
- instanceManager.remove(instanceId);
- return dispose(instanceId);
- }
- }
-
- /// Helper method to convert instances ids to objects.
Future<void> setDomStorageEnabledFromInstance(
WebSettings instance,
bool flag,
@@ -502,10 +482,9 @@
class JavaScriptChannelHostApiImpl extends JavaScriptChannelHostApi {
/// Constructs a [JavaScriptChannelHostApiImpl].
JavaScriptChannelHostApiImpl({
- BinaryMessenger? binaryMessenger,
+ super.binaryMessenger,
InstanceManager? instanceManager,
- }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
- super(binaryMessenger: binaryMessenger);
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
/// Maintains instances stored to communicate with java objects.
final InstanceManager instanceManager;
@@ -532,11 +511,6 @@
final InstanceManager instanceManager;
@override
- void dispose(int instanceId) {
- instanceManager.remove(instanceId);
- }
-
- @override
void postMessage(int instanceId, String message) {
final JavaScriptChannel? instance = instanceManager
.getInstanceWithWeakReference(instanceId) as JavaScriptChannel?;
@@ -552,10 +526,9 @@
class WebViewClientHostApiImpl extends WebViewClientHostApi {
/// Constructs a [WebViewClientHostApiImpl].
WebViewClientHostApiImpl({
- BinaryMessenger? binaryMessenger,
+ super.binaryMessenger,
InstanceManager? instanceManager,
- }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
- super(binaryMessenger: binaryMessenger);
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
/// Maintains instances stored to communicate with java objects.
final InstanceManager instanceManager;
@@ -564,9 +537,20 @@
Future<void> createFromInstance(WebViewClient instance) async {
if (instanceManager.getIdentifier(instance) == null) {
final int identifier = instanceManager.addDartCreatedInstance(instance);
- return create(identifier, instance.shouldOverrideUrlLoading);
+ return create(identifier);
}
}
+
+ /// Helper method to convert instances ids to objects.
+ Future<void> setShouldOverrideUrlLoadingReturnValueFromInstance(
+ WebViewClient instance,
+ bool value,
+ ) {
+ return setSynchronousReturnValueForShouldOverrideUrlLoading(
+ instanceManager.getIdentifier(instance)!,
+ value,
+ );
+ }
}
/// Flutter api implementation for [WebViewClient].
@@ -579,11 +563,6 @@
final InstanceManager instanceManager;
@override
- void dispose(int instanceId) {
- instanceManager.remove(instanceId);
- }
-
- @override
void onPageFinished(int instanceId, int webViewInstanceId, String url) {
final WebViewClient? instance = instanceManager
.getInstanceWithWeakReference(instanceId) as WebViewClient?;
@@ -597,7 +576,9 @@
webViewInstance != null,
'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
);
- instance!.onPageFinished(webViewInstance!, url);
+ if (instance!.onPageFinished != null) {
+ instance.onPageFinished!(webViewInstance!, url);
+ }
}
@override
@@ -614,7 +595,9 @@
webViewInstance != null,
'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
);
- instance!.onPageStarted(webViewInstance!, url);
+ if (instance!.onPageStarted != null) {
+ instance.onPageStarted!(webViewInstance!, url);
+ }
}
@override
@@ -638,12 +621,14 @@
'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
);
// ignore: deprecated_member_use_from_same_package
- instance!.onReceivedError(
- webViewInstance!,
- errorCode,
- description,
- failingUrl,
- );
+ if (instance!.onReceivedError != null) {
+ instance.onReceivedError!(
+ webViewInstance!,
+ errorCode,
+ description,
+ failingUrl,
+ );
+ }
}
@override
@@ -665,11 +650,13 @@
webViewInstance != null,
'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
);
- instance!.onReceivedRequestError(
- webViewInstance!,
- _toWebResourceRequest(request),
- _toWebResourceError(error),
- );
+ if (instance!.onReceivedRequestError != null) {
+ instance.onReceivedRequestError!(
+ webViewInstance!,
+ _toWebResourceRequest(request),
+ _toWebResourceError(error),
+ );
+ }
}
@override
@@ -690,7 +677,12 @@
webViewInstance != null,
'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
);
- instance!.requestLoading(webViewInstance!, _toWebResourceRequest(request));
+ if (instance!.requestLoading != null) {
+ instance.requestLoading!(
+ webViewInstance!,
+ _toWebResourceRequest(request),
+ );
+ }
}
@override
@@ -711,7 +703,9 @@
webViewInstance != null,
'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
);
- instance!.urlLoading(webViewInstance!, url);
+ if (instance!.urlLoading != null) {
+ instance.urlLoading!(webViewInstance!, url);
+ }
}
}
@@ -719,10 +713,9 @@
class DownloadListenerHostApiImpl extends DownloadListenerHostApi {
/// Constructs a [DownloadListenerHostApiImpl].
DownloadListenerHostApiImpl({
- BinaryMessenger? binaryMessenger,
+ super.binaryMessenger,
InstanceManager? instanceManager,
- }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
- super(binaryMessenger: binaryMessenger);
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
/// Maintains instances stored to communicate with java objects.
final InstanceManager instanceManager;
@@ -746,11 +739,6 @@
final InstanceManager instanceManager;
@override
- void dispose(int instanceId) {
- instanceManager.remove(instanceId);
- }
-
- @override
void onDownloadStart(
int instanceId,
String url,
@@ -779,25 +767,18 @@
class WebChromeClientHostApiImpl extends WebChromeClientHostApi {
/// Constructs a [WebChromeClientHostApiImpl].
WebChromeClientHostApiImpl({
- BinaryMessenger? binaryMessenger,
+ super.binaryMessenger,
InstanceManager? instanceManager,
- }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
- super(binaryMessenger: binaryMessenger);
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
/// Maintains instances stored to communicate with java objects.
final InstanceManager instanceManager;
/// Helper method to convert instances ids to objects.
- Future<void> createFromInstance(
- WebChromeClient instance,
- WebViewClient webViewClient,
- ) async {
+ Future<void> createFromInstance(WebChromeClient instance) async {
if (instanceManager.getIdentifier(instance) == null) {
final int identifier = instanceManager.addDartCreatedInstance(instance);
- return create(
- identifier,
- instanceManager.getIdentifier(webViewClient)!,
- );
+ return create(identifier);
}
}
}
@@ -812,11 +793,6 @@
final InstanceManager instanceManager;
@override
- void dispose(int instanceId) {
- instanceManager.remove(instanceId);
- }
-
- @override
void onProgressChanged(int instanceId, int webViewInstanceId, int progress) {
final WebChromeClient? instance = instanceManager
.getInstanceWithWeakReference(instanceId) as WebChromeClient?;
@@ -830,7 +806,9 @@
webViewInstance != null,
'InstanceManager does not contain an WebView with instanceId: $webViewInstanceId',
);
- instance!.onProgressChanged(webViewInstance!, progress);
+ if (instance!.onProgressChanged != null) {
+ instance.onProgressChanged!(webViewInstance!, progress);
+ }
}
}
@@ -838,10 +816,9 @@
class WebStorageHostApiImpl extends WebStorageHostApi {
/// Constructs a [WebStorageHostApiImpl].
WebStorageHostApiImpl({
- BinaryMessenger? binaryMessenger,
+ super.binaryMessenger,
InstanceManager? instanceManager,
- }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
- super(binaryMessenger: binaryMessenger);
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
/// Maintains instances stored to communicate with java objects.
final InstanceManager instanceManager;
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart
new file mode 100644
index 0000000..2cb01d4
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_controller.dart
@@ -0,0 +1,440 @@
+// 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.
+
+// TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231)
+// ignore: unnecessary_import
+import 'dart:typed_data';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/rendering.dart';
+import 'package:flutter/services.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+
+import 'android_navigation_delegate.dart';
+import 'android_proxy.dart';
+import 'android_webview.dart' as android_webview;
+import 'android_webview.dart';
+import 'instance_manager.dart';
+import 'weak_reference_utils.dart';
+
+/// Object specifying creation parameters for creating a [AndroidWebViewController].
+///
+/// When adding additional fields make sure they can be null or have a default
+/// value to avoid breaking changes. See [PlatformWebViewControllerCreationParams] for
+/// more information.
+@immutable
+class AndroidWebViewControllerCreationParams
+ extends PlatformWebViewControllerCreationParams {
+ /// Creates a new [AndroidWebViewControllerCreationParams] instance.
+ AndroidWebViewControllerCreationParams({
+ @visibleForTesting this.androidWebViewProxy = const AndroidWebViewProxy(),
+ @visibleForTesting android_webview.WebStorage? androidWebStorage,
+ }) : androidWebStorage =
+ androidWebStorage ?? android_webview.WebStorage.instance,
+ super();
+
+ /// Creates a [AndroidWebViewControllerCreationParams] instance based on [PlatformWebViewControllerCreationParams].
+ factory AndroidWebViewControllerCreationParams.fromPlatformWebViewControllerCreationParams(
+ // Recommended placeholder to prevent being broken by platform interface.
+ // ignore: avoid_unused_constructor_parameters
+ PlatformWebViewControllerCreationParams params, {
+ @visibleForTesting
+ AndroidWebViewProxy androidWebViewProxy = const AndroidWebViewProxy(),
+ @visibleForTesting android_webview.WebStorage? androidWebStorage,
+ }) {
+ return AndroidWebViewControllerCreationParams(
+ androidWebViewProxy: androidWebViewProxy,
+ androidWebStorage:
+ androidWebStorage ?? android_webview.WebStorage.instance,
+ );
+ }
+
+ /// Handles constructing objects and calling static methods for the Android WebView
+ /// native library.
+ @visibleForTesting
+ final AndroidWebViewProxy androidWebViewProxy;
+
+ /// Manages the JavaScript storage APIs provided by the [android_webview.WebView].
+ @visibleForTesting
+ final android_webview.WebStorage androidWebStorage;
+}
+
+/// Implementation of the [PlatformWebViewController] with the Android WebView API.
+class AndroidWebViewController extends PlatformWebViewController {
+ /// Creates a new [AndroidWebViewCookieManager].
+ AndroidWebViewController(PlatformWebViewControllerCreationParams params)
+ : super.implementation(params is AndroidWebViewControllerCreationParams
+ ? params
+ : AndroidWebViewControllerCreationParams
+ .fromPlatformWebViewControllerCreationParams(params)) {
+ _webView.settings.setDomStorageEnabled(true);
+ _webView.settings.setJavaScriptCanOpenWindowsAutomatically(true);
+ _webView.settings.setSupportMultipleWindows(true);
+ _webView.settings.setLoadWithOverviewMode(true);
+ _webView.settings.setUseWideViewPort(true);
+ _webView.settings.setDisplayZoomControls(false);
+ _webView.settings.setBuiltInZoomControls(true);
+ }
+
+ AndroidWebViewControllerCreationParams get _androidWebViewParams =>
+ params as AndroidWebViewControllerCreationParams;
+
+ /// The native [android_webview.WebView] being controlled.
+ late final android_webview.WebView _webView =
+ _androidWebViewParams.androidWebViewProxy.createAndroidWebView(
+ // Due to changes in Flutter 3.0 the `useHybridComposition` doesn't have
+ // any effect and is purposefully not exposed publicly by the
+ // [AndroidWebViewController]. More info here:
+ // https://github.com/flutter/flutter/issues/108106
+ useHybridComposition: true,
+ );
+
+ /// The native [android_webview.FlutterAssetManager] allows managing assets.
+ late final android_webview.FlutterAssetManager _flutterAssetManager =
+ _androidWebViewParams.androidWebViewProxy.createFlutterAssetManager();
+
+ final Map<String, AndroidJavaScriptChannelParams> _javaScriptChannelParams =
+ <String, AndroidJavaScriptChannelParams>{};
+
+ // The keeps a reference to the current NavigationDelegate so that the
+ // callback methods remain reachable.
+ // ignore: unused_field
+ late AndroidNavigationDelegate _currentNavigationDelegate;
+
+ /// Whether to enable the platform's webview content debugging tools.
+ ///
+ /// Defaults to false.
+ static Future<void> enableDebugging(
+ bool enabled, {
+ @visibleForTesting
+ AndroidWebViewProxy webViewProxy = const AndroidWebViewProxy(),
+ }) {
+ return webViewProxy.setWebContentsDebuggingEnabled(enabled);
+ }
+
+ @override
+ Future<void> loadFile(
+ String absoluteFilePath,
+ ) {
+ final String url = absoluteFilePath.startsWith('file://')
+ ? absoluteFilePath
+ : Uri.file(absoluteFilePath).toString();
+
+ _webView.settings.setAllowFileAccess(true);
+ return _webView.loadUrl(url, <String, String>{});
+ }
+
+ @override
+ Future<void> loadFlutterAsset(
+ String key,
+ ) async {
+ final String assetFilePath =
+ await _flutterAssetManager.getAssetFilePathByName(key);
+ final List<String> pathElements = assetFilePath.split('/');
+ final String fileName = pathElements.removeLast();
+ final List<String?> paths =
+ await _flutterAssetManager.list(pathElements.join('/'));
+
+ if (!paths.contains(fileName)) {
+ throw ArgumentError(
+ 'Asset for key "$key" not found.',
+ 'key',
+ );
+ }
+
+ return _webView.loadUrl(
+ Uri.file('/android_asset/$assetFilePath').toString(),
+ <String, String>{},
+ );
+ }
+
+ @override
+ Future<void> loadHtmlString(
+ String html, {
+ String? baseUrl,
+ }) {
+ return _webView.loadDataWithBaseUrl(
+ baseUrl: baseUrl,
+ data: html,
+ mimeType: 'text/html',
+ );
+ }
+
+ @override
+ Future<void> loadRequest(
+ LoadRequestParams params,
+ ) {
+ if (!params.uri.hasScheme) {
+ throw ArgumentError('WebViewRequest#uri is required to have a scheme.');
+ }
+ switch (params.method) {
+ case LoadRequestMethod.get:
+ return _webView.loadUrl(params.uri.toString(), params.headers);
+ case LoadRequestMethod.post:
+ return _webView.postUrl(
+ params.uri.toString(), params.body ?? Uint8List(0));
+ default:
+ throw UnimplementedError(
+ 'This version of `AndroidWebViewController` currently has no implementation for HTTP method ${params.method.serialize()} in loadRequest.',
+ );
+ }
+ }
+
+ @override
+ Future<String?> currentUrl() => _webView.getUrl();
+
+ @override
+ Future<bool> canGoBack() => _webView.canGoBack();
+
+ @override
+ Future<bool> canGoForward() => _webView.canGoForward();
+
+ @override
+ Future<void> goBack() => _webView.goBack();
+
+ @override
+ Future<void> goForward() => _webView.goForward();
+
+ @override
+ Future<void> reload() => _webView.reload();
+
+ @override
+ Future<void> clearCache() => _webView.clearCache(true);
+
+ @override
+ Future<void> clearLocalStorage() =>
+ _androidWebViewParams.androidWebStorage.deleteAllData();
+
+ @override
+ Future<void> setPlatformNavigationDelegate(
+ covariant AndroidNavigationDelegate handler) async {
+ _currentNavigationDelegate = handler;
+ handler.setOnLoadRequest(loadRequest);
+ _webView.setWebViewClient(handler.androidWebViewClient);
+ _webView.setWebChromeClient(handler.androidWebChromeClient);
+ _webView.setDownloadListener(handler.androidDownloadListener);
+ }
+
+ @override
+ Future<void> runJavaScript(String javaScript) {
+ return _webView.evaluateJavascript(javaScript);
+ }
+
+ @override
+ Future<Object> runJavaScriptReturningResult(String javaScript) async {
+ final String? result = await _webView.evaluateJavascript(javaScript);
+
+ if (result == null) {
+ return '';
+ } else if (result == 'true') {
+ return true;
+ } else if (result == 'false') {
+ return false;
+ }
+
+ return num.tryParse(result) ?? result;
+ }
+
+ @override
+ Future<void> addJavaScriptChannel(
+ JavaScriptChannelParams javaScriptChannelParams,
+ ) {
+ final AndroidJavaScriptChannelParams androidJavaScriptParams =
+ javaScriptChannelParams is AndroidJavaScriptChannelParams
+ ? javaScriptChannelParams
+ : AndroidJavaScriptChannelParams.fromJavaScriptChannelParams(
+ javaScriptChannelParams);
+
+ // When JavaScript channel with the same name exists make sure to remove it
+ // before registering the new channel.
+ if (_javaScriptChannelParams.containsKey(androidJavaScriptParams.name)) {
+ _webView
+ .removeJavaScriptChannel(androidJavaScriptParams._javaScriptChannel);
+ }
+
+ _javaScriptChannelParams[androidJavaScriptParams.name] =
+ androidJavaScriptParams;
+
+ return _webView
+ .addJavaScriptChannel(androidJavaScriptParams._javaScriptChannel);
+ }
+
+ @override
+ Future<void> removeJavaScriptChannel(String javaScriptChannelName) async {
+ final AndroidJavaScriptChannelParams? javaScriptChannelParams =
+ _javaScriptChannelParams[javaScriptChannelName];
+ if (javaScriptChannelParams == null) {
+ return;
+ }
+
+ _javaScriptChannelParams.remove(javaScriptChannelName);
+ return _webView
+ .removeJavaScriptChannel(javaScriptChannelParams._javaScriptChannel);
+ }
+
+ @override
+ Future<String?> getTitle() => _webView.getTitle();
+
+ @override
+ Future<void> scrollTo(int x, int y) => _webView.scrollTo(x, y);
+
+ @override
+ Future<void> scrollBy(int x, int y) => _webView.scrollBy(x, y);
+
+ @override
+ Future<Offset> getScrollPosition() {
+ return _webView.getScrollPosition();
+ }
+
+ @override
+ Future<void> enableZoom(bool enabled) =>
+ _webView.settings.setSupportZoom(enabled);
+
+ @override
+ Future<void> setBackgroundColor(Color color) =>
+ _webView.setBackgroundColor(color);
+
+ @override
+ Future<void> setJavaScriptMode(JavaScriptMode javaScriptMode) =>
+ _webView.settings
+ .setJavaScriptEnabled(javaScriptMode == JavaScriptMode.unrestricted);
+
+ @override
+ Future<void> setUserAgent(String? userAgent) =>
+ _webView.settings.setUserAgentString(userAgent);
+
+ /// Sets the restrictions that apply on automatic media playback.
+ Future<void> setMediaPlaybackRequiresUserGesture(bool require) {
+ return _webView.settings.setMediaPlaybackRequiresUserGesture(require);
+ }
+}
+
+/// An implementation of [JavaScriptChannelParams] with the Android WebView API.
+///
+/// See [AndroidWebViewController.addJavaScriptChannel].
+@immutable
+class AndroidJavaScriptChannelParams extends JavaScriptChannelParams {
+ /// Constructs a [AndroidJavaScriptChannelParams].
+ AndroidJavaScriptChannelParams({
+ required super.name,
+ required super.onMessageReceived,
+ @visibleForTesting
+ AndroidWebViewProxy webViewProxy = const AndroidWebViewProxy(),
+ }) : assert(name.isNotEmpty),
+ _javaScriptChannel = webViewProxy.createJavaScriptChannel(
+ name,
+ postMessage: withWeakRefenceTo(
+ onMessageReceived,
+ (WeakReference<void Function(JavaScriptMessage)> weakReference) {
+ return (
+ String message,
+ ) {
+ if (weakReference.target != null) {
+ weakReference.target!(
+ JavaScriptMessage(message: message),
+ );
+ }
+ };
+ },
+ ),
+ );
+
+ /// Constructs a [AndroidJavaScriptChannelParams] using a
+ /// [JavaScriptChannelParams].
+ AndroidJavaScriptChannelParams.fromJavaScriptChannelParams(
+ JavaScriptChannelParams params, {
+ @visibleForTesting
+ AndroidWebViewProxy webViewProxy = const AndroidWebViewProxy(),
+ }) : this(
+ name: params.name,
+ onMessageReceived: params.onMessageReceived,
+ webViewProxy: webViewProxy,
+ );
+
+ final android_webview.JavaScriptChannel _javaScriptChannel;
+}
+
+/// Object specifying creation parameters for creating a [AndroidWebViewWidget].
+///
+/// When adding additional fields make sure they can be null or have a default
+/// value to avoid breaking changes. See [PlatformWebViewWidgetCreationParams] for
+/// more information.
+@immutable
+class AndroidWebViewWidgetCreationParams
+ extends PlatformWebViewWidgetCreationParams {
+ /// Creates [AndroidWebWidgetCreationParams].
+ AndroidWebViewWidgetCreationParams({
+ super.key,
+ required super.controller,
+ super.layoutDirection,
+ super.gestureRecognizers,
+ @visibleForTesting InstanceManager? instanceManager,
+ }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
+
+ /// Constructs a [WebKitWebViewWidgetCreationParams] using a
+ /// [PlatformWebViewWidgetCreationParams].
+ AndroidWebViewWidgetCreationParams.fromPlatformWebViewWidgetCreationParams(
+ PlatformWebViewWidgetCreationParams params, {
+ InstanceManager? instanceManager,
+ }) : this(
+ key: params.key,
+ controller: params.controller,
+ layoutDirection: params.layoutDirection,
+ gestureRecognizers: params.gestureRecognizers,
+ instanceManager: instanceManager,
+ );
+
+ /// Maintains instances used to communicate with the native objects they
+ /// represent.
+ ///
+ /// This field is exposed for testing purposes only and should not be used
+ /// outside of tests.
+ @visibleForTesting
+ final InstanceManager instanceManager;
+}
+
+/// An implementation of [PlatformWebViewWidget] with the Android WebView API.
+class AndroidWebViewWidget extends PlatformWebViewWidget {
+ /// Constructs a [WebKitWebViewWidget].
+ AndroidWebViewWidget(PlatformWebViewWidgetCreationParams params)
+ : super.implementation(
+ params is AndroidWebViewWidgetCreationParams
+ ? params
+ : AndroidWebViewWidgetCreationParams
+ .fromPlatformWebViewWidgetCreationParams(params),
+ );
+
+ AndroidWebViewWidgetCreationParams get _androidParams =>
+ params as AndroidWebViewWidgetCreationParams;
+
+ @override
+ Widget build(BuildContext context) {
+ return PlatformViewLink(
+ key: _androidParams.key,
+ viewType: 'plugins.flutter.io/webview',
+ surfaceFactory: (
+ BuildContext context,
+ PlatformViewController controller,
+ ) {
+ return AndroidViewSurface(
+ controller: controller as AndroidViewController,
+ gestureRecognizers: _androidParams.gestureRecognizers,
+ hitTestBehavior: PlatformViewHitTestBehavior.opaque,
+ );
+ },
+ onCreatePlatformView: (PlatformViewCreationParams params) {
+ return PlatformViewsService.initSurfaceAndroidView(
+ id: params.id,
+ viewType: 'plugins.flutter.io/webview',
+ layoutDirection: _androidParams.layoutDirection,
+ creationParams: _androidParams.instanceManager.getIdentifier(
+ (_androidParams.controller as AndroidWebViewController)
+ ._webView),
+ creationParamsCodec: const StandardMessageCodec(),
+ )
+ ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
+ ..create();
+ });
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_cookie_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_cookie_manager.dart
new file mode 100644
index 0000000..5174ca5
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_cookie_manager.dart
@@ -0,0 +1,74 @@
+// 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.
+
+import 'package:flutter/foundation.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+
+import 'android_webview.dart';
+
+/// Object specifying creation parameters for creating a [AndroidWebViewCookieManager].
+///
+/// When adding additional fields make sure they can be null or have a default
+/// value to avoid breaking changes. See [PlatformWebViewCookieManagerCreationParams] for
+/// more information.
+@immutable
+class AndroidWebViewCookieManagerCreationParams
+ extends PlatformWebViewCookieManagerCreationParams {
+ /// Creates a new [AndroidWebViewCookieManagerCreationParams] instance.
+ const AndroidWebViewCookieManagerCreationParams._(
+ // This parameter prevents breaking changes later.
+ // ignore: avoid_unused_constructor_parameters
+ PlatformWebViewCookieManagerCreationParams params,
+ ) : super();
+
+ /// Creates a [AndroidWebViewCookieManagerCreationParams] instance based on [PlatformWebViewCookieManagerCreationParams].
+ factory AndroidWebViewCookieManagerCreationParams.fromPlatformWebViewCookieManagerCreationParams(
+ PlatformWebViewCookieManagerCreationParams params) {
+ return AndroidWebViewCookieManagerCreationParams._(params);
+ }
+}
+
+/// Handles all cookie operations for the Android platform.
+class AndroidWebViewCookieManager extends PlatformWebViewCookieManager {
+ /// Creates a new [AndroidWebViewCookieManager].
+ AndroidWebViewCookieManager(
+ PlatformWebViewCookieManagerCreationParams params, {
+ CookieManager? cookieManager,
+ }) : _cookieManager = cookieManager ?? CookieManager.instance,
+ super.implementation(
+ params is AndroidWebViewCookieManagerCreationParams
+ ? params
+ : AndroidWebViewCookieManagerCreationParams
+ .fromPlatformWebViewCookieManagerCreationParams(params),
+ );
+
+ final CookieManager _cookieManager;
+
+ @override
+ Future<bool> clearCookies() {
+ return _cookieManager.clearCookies();
+ }
+
+ @override
+ Future<void> setCookie(WebViewCookie cookie) {
+ if (!_isValidPath(cookie.path)) {
+ throw ArgumentError(
+ 'The path property for the provided cookie was not given a legal value.');
+ }
+ return _cookieManager.setCookie(
+ cookie.domain,
+ '${Uri.encodeComponent(cookie.name)}=${Uri.encodeComponent(cookie.value)}; path=${cookie.path}',
+ );
+ }
+
+ bool _isValidPath(String path) {
+ // Permitted ranges based on RFC6265bis: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1
+ for (final int char in path.codeUnits) {
+ if ((char < 0x20 || char > 0x3A) && (char < 0x3C || char > 0x7E)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_platform.dart b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_platform.dart
new file mode 100644
index 0000000..24581eb
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/android_webview_platform.dart
@@ -0,0 +1,45 @@
+// 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.
+
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+
+import 'android_navigation_delegate.dart';
+import 'android_webview_controller.dart';
+import 'android_webview_cookie_manager.dart';
+
+/// Implementation of [WebViewPlatform] using the WebKit API.
+class AndroidWebViewPlatform extends WebViewPlatform {
+ /// Registers this class as the default instance of [WebViewPlatform].
+ static void registerWith() {
+ WebViewPlatform.instance = AndroidWebViewPlatform();
+ }
+
+ @override
+ AndroidWebViewController createPlatformWebViewController(
+ PlatformWebViewControllerCreationParams params,
+ ) {
+ return AndroidWebViewController(params);
+ }
+
+ @override
+ AndroidNavigationDelegate createPlatformNavigationDelegate(
+ PlatformNavigationDelegateCreationParams params,
+ ) {
+ return AndroidNavigationDelegate(params);
+ }
+
+ @override
+ AndroidWebViewWidget createPlatformWebViewWidget(
+ PlatformWebViewWidgetCreationParams params,
+ ) {
+ return AndroidWebViewWidget(params);
+ }
+
+ @override
+ AndroidWebViewCookieManager createPlatformCookieManager(
+ PlatformWebViewCookieManagerCreationParams params,
+ ) {
+ return AndroidWebViewCookieManager(params);
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_android.dart
similarity index 94%
rename from packages/webview_flutter/webview_flutter_android/lib/webview_android.dart
rename to packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_android.dart
index 4774024..cfda749 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_android.dart
@@ -8,9 +8,10 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
-import 'src/android_webview.dart';
+import '../android_webview.dart';
import 'webview_android_widget.dart';
/// Builds an Android webview.
diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_android_cookie_manager.dart
similarity index 85%
rename from packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart
rename to packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_android_cookie_manager.dart
index 6e3f6f2..663a207 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_android_cookie_manager.dart
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
-import 'src/android_webview.dart' as android_webview;
+import '../android_webview.dart' as android_webview;
/// Handles all cookie operations for the current platform.
class WebViewAndroidCookieManager extends WebViewCookieManagerPlatform {
diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart b/packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_android_widget.dart
similarity index 68%
rename from packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart
rename to packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_android_widget.dart
index 140d0da..fc1028e 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_android_widget.dart
@@ -6,16 +6,18 @@
import 'dart:typed_data';
import 'package:flutter/widgets.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
-import 'src/android_webview.dart' as android_webview;
+import '../android_webview.dart' as android_webview;
+import '../weak_reference_utils.dart';
import 'webview_android_cookie_manager.dart';
/// Creates a [Widget] with a [android_webview.WebView].
class WebViewAndroidWidget extends StatefulWidget {
/// Constructs a [WebViewAndroidWidget].
const WebViewAndroidWidget({
- Key? key,
+ super.key,
required this.creationParams,
required this.useHybridComposition,
required this.callbacksHandler,
@@ -25,7 +27,7 @@
@visibleForTesting
this.flutterAssetManager = const android_webview.FlutterAssetManager(),
@visibleForTesting this.webStorage,
- }) : super(key: key);
+ });
/// Initial parameters used to setup the WebView.
final CreationParams creationParams;
@@ -86,12 +88,6 @@
}
@override
- void dispose() {
- super.dispose();
- controller._dispose();
- }
-
- @override
Widget build(BuildContext context) {
return widget.onBuildWidget(controller);
}
@@ -127,6 +123,7 @@
_setCreationParams(creationParams);
webView.setDownloadListener(downloadListener);
webView.setWebChromeClient(webChromeClient);
+ webView.setWebViewClient(webViewClient);
final String? initialUrl = creationParams.initialUrl;
if (initialUrl != null) {
@@ -137,7 +134,61 @@
final Map<String, WebViewAndroidJavaScriptChannel> _javaScriptChannels =
<String, WebViewAndroidJavaScriptChannel>{};
- late WebViewAndroidWebViewClient _webViewClient;
+ late final android_webview.WebViewClient _webViewClient = withWeakRefenceTo(
+ this, (WeakReference<WebViewAndroidPlatformController> weakReference) {
+ return webViewProxy.createWebViewClient(
+ onPageStarted: (_, String url) {
+ weakReference.target?.callbacksHandler.onPageStarted(url);
+ },
+ onPageFinished: (_, String url) {
+ weakReference.target?.callbacksHandler.onPageFinished(url);
+ },
+ onReceivedError: (
+ _,
+ int errorCode,
+ String description,
+ String failingUrl,
+ ) {
+ weakReference.target?.callbacksHandler
+ .onWebResourceError(WebResourceError(
+ errorCode: errorCode,
+ description: description,
+ failingUrl: failingUrl,
+ errorType: _errorCodeToErrorType(errorCode),
+ ));
+ },
+ onReceivedRequestError: (
+ _,
+ android_webview.WebResourceRequest request,
+ android_webview.WebResourceError error,
+ ) {
+ if (request.isForMainFrame) {
+ weakReference.target?.callbacksHandler
+ .onWebResourceError(WebResourceError(
+ errorCode: error.errorCode,
+ description: error.description,
+ failingUrl: request.url,
+ errorType: _errorCodeToErrorType(error.errorCode),
+ ));
+ }
+ },
+ urlLoading: (_, String url) {
+ weakReference.target?._handleNavigationRequest(
+ url: url,
+ isForMainFrame: true,
+ );
+ },
+ requestLoading: (_, android_webview.WebResourceRequest request) {
+ weakReference.target?._handleNavigationRequest(
+ url: request.url,
+ isForMainFrame: request.isForMainFrame,
+ );
+ },
+ );
+ });
+
+ bool _hasNavigationDelegate = false;
+ bool _hasProgressTracking = false;
/// Represents the WebView maintained by platform code.
late final android_webview.WebView webView;
@@ -160,20 +211,50 @@
/// Receives callbacks when content should be downloaded instead.
@visibleForTesting
- late final WebViewAndroidDownloadListener downloadListener =
- WebViewAndroidDownloadListener(loadUrl: loadUrl);
+ late final android_webview.DownloadListener downloadListener =
+ android_webview.DownloadListener(
+ onDownloadStart: withWeakRefenceTo(
+ this,
+ (WeakReference<WebViewAndroidPlatformController> weakReference) {
+ return (
+ String url,
+ String userAgent,
+ String contentDisposition,
+ String mimetype,
+ int contentLength,
+ ) {
+ weakReference.target?._handleNavigationRequest(
+ url: url,
+ isForMainFrame: true,
+ );
+ };
+ },
+ ),
+ );
/// Handles JavaScript dialogs, favicons, titles, new windows, and the progress for [android_webview.WebView].
@visibleForTesting
- late final WebViewAndroidWebChromeClient webChromeClient =
- WebViewAndroidWebChromeClient();
+ late final android_webview.WebChromeClient webChromeClient =
+ android_webview.WebChromeClient(
+ onProgressChanged: withWeakRefenceTo(
+ this,
+ (WeakReference<WebViewAndroidPlatformController> weakReference) {
+ return (_, int progress) {
+ final WebViewAndroidPlatformController? controller =
+ weakReference.target;
+ if (controller != null && controller._hasProgressTracking) {
+ controller.callbacksHandler.onProgress(progress);
+ }
+ };
+ },
+ ));
/// Manages the JavaScript storage APIs.
final android_webview.WebStorage webStorage;
/// Receive various notifications and requests for [android_webview.WebView].
@visibleForTesting
- WebViewAndroidWebViewClient get webViewClient => _webViewClient;
+ android_webview.WebViewClient get webViewClient => _webViewClient;
@override
Future<void> loadHtmlString(String html, {String? baseUrl}) {
@@ -272,10 +353,9 @@
@override
Future<void> updateSettings(WebSettings setting) async {
+ _hasProgressTracking = setting.hasProgressTracking ?? _hasProgressTracking;
await Future.wait(<Future<void>>[
_setUserAgent(setting.userAgent),
- if (setting.hasProgressTracking != null)
- _setHasProgressTracking(setting.hasProgressTracking!),
if (setting.hasNavigationDelegate != null)
_setHasNavigationDelegate(setting.hasNavigationDelegate!),
if (setting.javascriptMode != null)
@@ -355,8 +435,6 @@
@override
Future<int> getScrollY() => webView.getScrollY();
- Future<void> _dispose() => webView.release();
-
void _setCreationParams(CreationParams creationParams) {
final WebSettings? webSettings = creationParams.webSettings;
if (webSettings != null) {
@@ -389,34 +467,11 @@
.forEach(WebViewCookieManagerPlatform.instance!.setCookie);
}
- Future<void> _setHasProgressTracking(bool hasProgressTracking) async {
- if (hasProgressTracking) {
- webChromeClient._onProgress = callbacksHandler.onProgress;
- } else {
- webChromeClient._onProgress = null;
- }
- }
-
Future<void> _setHasNavigationDelegate(bool hasNavigationDelegate) {
- if (hasNavigationDelegate) {
- downloadListener._onNavigationRequest =
- callbacksHandler.onNavigationRequest;
- _webViewClient = WebViewAndroidWebViewClient.handlesNavigation(
- onPageStartedCallback: callbacksHandler.onPageStarted,
- onPageFinishedCallback: callbacksHandler.onPageFinished,
- onWebResourceErrorCallback: callbacksHandler.onWebResourceError,
- loadUrl: loadUrl,
- onNavigationRequestCallback: callbacksHandler.onNavigationRequest,
- );
- } else {
- downloadListener._onNavigationRequest = null;
- _webViewClient = WebViewAndroidWebViewClient(
- onPageStartedCallback: callbacksHandler.onPageStarted,
- onPageFinishedCallback: callbacksHandler.onPageFinished,
- onWebResourceErrorCallback: callbacksHandler.onWebResourceError,
- );
- }
- return webView.setWebViewClient(_webViewClient);
+ _hasNavigationDelegate = hasNavigationDelegate;
+ return _webViewClient.setSynchronousReturnValueForShouldOverrideUrlLoading(
+ hasNavigationDelegate,
+ );
}
Future<void> _setJavaScriptMode(JavascriptMode mode) {
@@ -444,114 +499,6 @@
Future<void> _setZoomEnabled(bool zoomEnabled) {
return webView.settings.setSupportZoom(zoomEnabled);
}
-}
-
-/// Exposes a channel to receive calls from javaScript.
-class WebViewAndroidJavaScriptChannel
- extends android_webview.JavaScriptChannel {
- /// Creates a [WebViewAndroidJavaScriptChannel].
- WebViewAndroidJavaScriptChannel(
- String channelName, this.javascriptChannelRegistry)
- : super(channelName);
-
- /// Manages named JavaScript channels and forwarding incoming messages on the correct channel.
- final JavascriptChannelRegistry javascriptChannelRegistry;
-
- @override
- void postMessage(String message) {
- javascriptChannelRegistry.onJavascriptChannelMessage(channelName, message);
- }
-}
-
-/// Receives callbacks when content can not be handled by the rendering engine for [WebViewAndroidPlatformController], and should be downloaded instead.
-///
-/// When handling navigation requests, this calls [onNavigationRequestCallback]
-/// when a [android_webview.WebView] attempts to navigate to a new page. If
-/// this callback return true, this calls [loadUrl].
-class WebViewAndroidDownloadListener extends android_webview.DownloadListener {
- /// Creates a [WebViewAndroidDownloadListener].
- WebViewAndroidDownloadListener({required this.loadUrl});
-
- // Changed by WebViewAndroidPlatformController.
- FutureOr<bool> Function({
- required String url,
- required bool isForMainFrame,
- })? _onNavigationRequest;
-
- /// Callback to load a URL when a navigation request is approved.
- final Future<void> Function(String url, Map<String, String>? headers) loadUrl;
-
- @override
- void onDownloadStart(
- String url,
- String userAgent,
- String contentDisposition,
- String mimetype,
- int contentLength,
- ) {
- if (_onNavigationRequest == null) {
- return;
- }
-
- final FutureOr<bool> returnValue = _onNavigationRequest!(
- url: url,
- isForMainFrame: true,
- );
-
- if (returnValue is bool && returnValue) {
- loadUrl(url, <String, String>{});
- } else {
- (returnValue as Future<bool>).then((bool shouldLoadUrl) {
- if (shouldLoadUrl) {
- loadUrl(url, <String, String>{});
- }
- });
- }
- }
-}
-
-/// Receives various navigation requests and errors for [WebViewAndroidPlatformController].
-///
-/// When handling navigation requests, this calls [onNavigationRequestCallback]
-/// when a [android_webview.WebView] attempts to navigate to a new page. If
-/// this callback return true, this calls [loadUrl].
-class WebViewAndroidWebViewClient extends android_webview.WebViewClient {
- /// Creates a [WebViewAndroidWebViewClient] that doesn't handle navigation requests.
- WebViewAndroidWebViewClient({
- required this.onPageStartedCallback,
- required this.onPageFinishedCallback,
- required this.onWebResourceErrorCallback,
- }) : loadUrl = null,
- onNavigationRequestCallback = null,
- super(shouldOverrideUrlLoading: false);
-
- /// Creates a [WebViewAndroidWebViewClient] that handles navigation requests.
- WebViewAndroidWebViewClient.handlesNavigation({
- required this.onPageStartedCallback,
- required this.onPageFinishedCallback,
- required this.onWebResourceErrorCallback,
- required this.onNavigationRequestCallback,
- required this.loadUrl,
- }) : super(shouldOverrideUrlLoading: true);
-
- /// Callback when [android_webview.WebViewClient] receives a callback from [android_webview.WebViewClient].onPageStarted.
- final void Function(String url) onPageStartedCallback;
-
- /// Callback when [android_webview.WebViewClient] receives a callback from [android_webview.WebViewClient].onPageFinished.
- final void Function(String url) onPageFinishedCallback;
-
- /// Callback when [android_webview.WebViewClient] receives an error callback.
- void Function(WebResourceError error) onWebResourceErrorCallback;
-
- /// Checks whether a navigation request should be approved or disaproved.
- final FutureOr<bool> Function({
- required String url,
- required bool isForMainFrame,
- })? onNavigationRequestCallback;
-
- /// Callback when a navigation request is approved.
- final Future<void> Function(String url, Map<String, String>? headers)?
- loadUrl;
static WebResourceErrorType _errorCodeToErrorType(int errorCode) {
switch (errorCode) {
@@ -594,110 +541,54 @@
);
}
- /// Whether this [android_webview.WebViewClient] handles navigation requests.
- bool get handlesNavigation =>
- loadUrl != null && onNavigationRequestCallback != null;
-
- @override
- void onPageStarted(android_webview.WebView webView, String url) {
- onPageStartedCallback(url);
- }
-
- @override
- void onPageFinished(android_webview.WebView webView, String url) {
- onPageFinishedCallback(url);
- }
-
- @override
- void onReceivedError(
- android_webview.WebView webView,
- int errorCode,
- String description,
- String failingUrl,
- ) {
- onWebResourceErrorCallback(WebResourceError(
- errorCode: errorCode,
- description: description,
- failingUrl: failingUrl,
- errorType: _errorCodeToErrorType(errorCode),
- ));
- }
-
- @override
- void onReceivedRequestError(
- android_webview.WebView webView,
- android_webview.WebResourceRequest request,
- android_webview.WebResourceError error,
- ) {
- if (request.isForMainFrame) {
- onWebResourceErrorCallback(WebResourceError(
- errorCode: error.errorCode,
- description: error.description,
- failingUrl: request.url,
- errorType: _errorCodeToErrorType(error.errorCode),
- ));
- }
- }
-
- @override
- void urlLoading(android_webview.WebView webView, String url) {
- if (!handlesNavigation) {
+ void _handleNavigationRequest({
+ required String url,
+ required bool isForMainFrame,
+ }) {
+ if (!_hasNavigationDelegate) {
return;
}
- final FutureOr<bool> returnValue = onNavigationRequestCallback!(
+ final FutureOr<bool> returnValue = callbacksHandler.onNavigationRequest(
url: url,
- isForMainFrame: true,
+ isForMainFrame: isForMainFrame,
);
if (returnValue is bool && returnValue) {
- loadUrl!(url, <String, String>{});
+ loadUrl(url, <String, String>{});
} else if (returnValue is Future<bool>) {
returnValue.then((bool shouldLoadUrl) {
if (shouldLoadUrl) {
- loadUrl!(url, <String, String>{});
- }
- });
- }
- }
-
- @override
- void requestLoading(
- android_webview.WebView webView,
- android_webview.WebResourceRequest request,
- ) {
- if (!handlesNavigation) {
- return;
- }
-
- final FutureOr<bool> returnValue = onNavigationRequestCallback!(
- url: request.url,
- isForMainFrame: request.isForMainFrame,
- );
-
- if (returnValue is bool && returnValue) {
- loadUrl!(request.url, <String, String>{});
- } else if (returnValue is Future<bool>) {
- returnValue.then((bool shouldLoadUrl) {
- if (shouldLoadUrl) {
- loadUrl!(request.url, <String, String>{});
+ loadUrl(url, <String, String>{});
}
});
}
}
}
-/// Handles JavaScript dialogs, favicons, titles, and the progress for [WebViewAndroidPlatformController].
-class WebViewAndroidWebChromeClient extends android_webview.WebChromeClient {
- // Changed by WebViewAndroidPlatformController.
- void Function(int progress)? _onProgress;
+/// Exposes a channel to receive calls from javaScript.
+class WebViewAndroidJavaScriptChannel
+ extends android_webview.JavaScriptChannel {
+ /// Creates a [WebViewAndroidJavaScriptChannel].
+ WebViewAndroidJavaScriptChannel(
+ super.channelName,
+ this.javascriptChannelRegistry,
+ ) : super(
+ postMessage: withWeakRefenceTo(
+ javascriptChannelRegistry,
+ (WeakReference<JavascriptChannelRegistry> weakReference) {
+ return (String message) {
+ weakReference.target?.onJavascriptChannelMessage(
+ channelName,
+ message,
+ );
+ };
+ },
+ ),
+ );
- @override
- void onProgressChanged(android_webview.WebView webView, int progress) {
- if (_onProgress != null) {
- _onProgress!(progress);
- }
- }
+ /// Manages named JavaScript channels and forwarding incoming messages on the correct channel.
+ final JavascriptChannelRegistry javascriptChannelRegistry;
}
/// Handles constructing [android_webview.WebView]s and calling static methods.
@@ -713,6 +604,38 @@
return android_webview.WebView(useHybridComposition: useHybridComposition);
}
+ /// Constructs a [android_webview.WebViewClient].
+ android_webview.WebViewClient createWebViewClient({
+ void Function(android_webview.WebView webView, String url)? onPageStarted,
+ void Function(android_webview.WebView webView, String url)? onPageFinished,
+ void Function(
+ android_webview.WebView webView,
+ android_webview.WebResourceRequest request,
+ android_webview.WebResourceError error,
+ )?
+ onReceivedRequestError,
+ void Function(
+ android_webview.WebView webView,
+ int errorCode,
+ String description,
+ String failingUrl,
+ )?
+ onReceivedError,
+ void Function(android_webview.WebView webView,
+ android_webview.WebResourceRequest request)?
+ requestLoading,
+ void Function(android_webview.WebView webView, String url)? urlLoading,
+ }) {
+ return android_webview.WebViewClient(
+ onPageStarted: onPageStarted,
+ onPageFinished: onPageFinished,
+ onReceivedRequestError: onReceivedRequestError,
+ onReceivedError: onReceivedError,
+ requestLoading: requestLoading,
+ urlLoading: urlLoading,
+ );
+ }
+
/// Enables debugging of web contents (HTML / CSS / JavaScript) loaded into any WebViews of this application.
///
/// This flag can be enabled in order to facilitate debugging of web layouts
diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart b/packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_surface_android.dart
similarity index 96%
rename from packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart
rename to packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_surface_android.dart
index e89fb7d..8db2fe0 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/webview_surface_android.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/legacy/webview_surface_android.dart
@@ -7,9 +7,10 @@
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+// ignore: implementation_imports
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
-import 'src/android_webview.dart';
+import '../android_webview.dart';
import 'webview_android.dart';
import 'webview_android_widget.dart';
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/weak_reference_utils.dart b/packages/webview_flutter/webview_flutter_android/lib/src/weak_reference_utils.dart
new file mode 100644
index 0000000..ad0c9eb
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/weak_reference_utils.dart
@@ -0,0 +1,34 @@
+// 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.
+
+/// Helper method for creating callbacks methods with a weak reference.
+///
+/// Example:
+/// ```
+/// final JavascriptChannelRegistry javascriptChannelRegistry = ...
+///
+/// final WKScriptMessageHandler handler = WKScriptMessageHandler(
+/// didReceiveScriptMessage: withWeakRefenceTo(
+/// javascriptChannelRegistry,
+/// (WeakReference<JavascriptChannelRegistry> weakReference) {
+/// return (
+/// WKUserContentController userContentController,
+/// WKScriptMessage message,
+/// ) {
+/// weakReference.target?.onJavascriptChannelMessage(
+/// message.name,
+/// message.body!.toString(),
+/// );
+/// };
+/// },
+/// ),
+/// );
+/// ```
+S withWeakRefenceTo<T extends Object, S extends Object>(
+ T reference,
+ S Function(WeakReference<T> weakReference) onCreate,
+) {
+ final WeakReference<T> weakReference = WeakReference<T>(reference);
+ return onCreate(weakReference);
+}
diff --git a/packages/webview_flutter/webview_flutter_android/lib/src/webview_flutter_android_legacy.dart b/packages/webview_flutter/webview_flutter_android/lib/src/webview_flutter_android_legacy.dart
new file mode 100644
index 0000000..a4f9166
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/lib/src/webview_flutter_android_legacy.dart
@@ -0,0 +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.
+
+export 'legacy/webview_android.dart';
+export 'legacy/webview_android_cookie_manager.dart';
+export 'legacy/webview_surface_android.dart';
diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_flutter_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_flutter_android.dart
new file mode 100644
index 0000000..faab715
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/lib/webview_flutter_android.dart
@@ -0,0 +1,10 @@
+// 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.
+
+library webview_flutter_android;
+
+export 'src/android_navigation_delegate.dart';
+export 'src/android_webview_controller.dart';
+export 'src/android_webview_cookie_manager.dart';
+export 'src/android_webview_platform.dart';
diff --git a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
index f3946ed..d3adac8 100644
--- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
+++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
@@ -88,8 +88,6 @@
abstract class WebViewHostApi {
void create(int instanceId, bool useHybridComposition);
- void dispose(int instanceId);
-
void loadData(
int instanceId,
String data,
@@ -169,8 +167,6 @@
abstract class WebSettingsHostApi {
void create(int instanceId, int webViewInstanceId);
- void dispose(int instanceId);
-
void setDomStorageEnabled(int instanceId, bool flag);
void setJavaScriptCanOpenWindowsAutomatically(int instanceId, bool flag);
@@ -203,20 +199,21 @@
@FlutterApi()
abstract class JavaScriptChannelFlutterApi {
- void dispose(int instanceId);
-
void postMessage(int instanceId, String message);
}
@HostApi(dartHostTestHandler: 'TestWebViewClientHostApi')
abstract class WebViewClientHostApi {
- void create(int instanceId, bool shouldOverrideUrlLoading);
+ void create(int instanceId);
+
+ void setSynchronousReturnValueForShouldOverrideUrlLoading(
+ int instanceId,
+ bool value,
+ );
}
@FlutterApi()
abstract class WebViewClientFlutterApi {
- void dispose(int instanceId);
-
void onPageStarted(int instanceId, int webViewInstanceId, String url);
void onPageFinished(int instanceId, int webViewInstanceId, String url);
@@ -252,8 +249,6 @@
@FlutterApi()
abstract class DownloadListenerFlutterApi {
- void dispose(int instanceId);
-
void onDownloadStart(
int instanceId,
String url,
@@ -266,7 +261,7 @@
@HostApi(dartHostTestHandler: 'TestWebChromeClientHostApi')
abstract class WebChromeClientHostApi {
- void create(int instanceId, int webViewClientInstanceId);
+ void create(int instanceId);
}
@HostApi(dartHostTestHandler: 'TestAssetManagerHostApi')
@@ -278,8 +273,6 @@
@FlutterApi()
abstract class WebChromeClientFlutterApi {
- void dispose(int instanceId);
-
void onProgressChanged(int instanceId, int webViewInstanceId, int progress);
}
diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
index e411b4e..4b22a1f 100644
--- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
@@ -2,10 +2,10 @@
description: A Flutter plugin that provides a WebView widget on Android.
repository: https://github.com/flutter/plugins/tree/main/packages/webview_flutter/webview_flutter_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 2.10.4
+version: 3.0.0
environment:
- sdk: ">=2.14.0 <3.0.0"
+ sdk: ">=2.17.0 <3.0.0"
flutter: ">=3.0.0"
flutter:
@@ -15,11 +15,12 @@
android:
package: io.flutter.plugins.webviewflutter
pluginClass: WebViewFlutterPlugin
+ dartPluginClass: AndroidWebViewPlatform
dependencies:
flutter:
sdk: flutter
- webview_flutter_platform_interface: ^1.8.0
+ webview_flutter_platform_interface: ^2.0.0
dev_dependencies:
build_runner: ^2.1.4
@@ -27,5 +28,5 @@
sdk: flutter
flutter_test:
sdk: flutter
- mockito: ^5.2.0
- pigeon: ^4.0.2
+ mockito: ^5.3.2
+ pigeon: ^4.2.3
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart
new file mode 100644
index 0000000..26d4e68
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/test/android_navigation_delegate_test.dart
@@ -0,0 +1,514 @@
+// 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.
+
+import 'dart:async';
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:webview_flutter_android/src/android_proxy.dart';
+import 'package:webview_flutter_android/src/android_webview.dart'
+ as android_webview;
+import 'package:webview_flutter_android/webview_flutter_android.dart';
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+
+void main() {
+ group('AndroidNavigationDelegate', () {
+ test('onPageFinished', () {
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ late final String callbackUrl;
+ androidNavigationDelegate
+ .setOnPageFinished((String url) => callbackUrl = url);
+
+ CapturingWebViewClient.lastCreatedDelegate.onPageFinished!(
+ android_webview.WebView.detached(),
+ 'https://www.google.com',
+ );
+
+ expect(callbackUrl, 'https://www.google.com');
+ });
+
+ test('onPageStarted', () {
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ late final String callbackUrl;
+ androidNavigationDelegate
+ .setOnPageStarted((String url) => callbackUrl = url);
+
+ CapturingWebViewClient.lastCreatedDelegate.onPageStarted!(
+ android_webview.WebView.detached(),
+ 'https://www.google.com',
+ );
+
+ expect(callbackUrl, 'https://www.google.com');
+ });
+
+ test('onWebResourceError from onReceivedRequestError', () {
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ late final WebResourceError callbackError;
+ androidNavigationDelegate.setOnWebResourceError(
+ (WebResourceError error) => callbackError = error);
+
+ CapturingWebViewClient.lastCreatedDelegate.onReceivedRequestError!(
+ android_webview.WebView.detached(),
+ android_webview.WebResourceRequest(
+ url: 'https://www.google.com',
+ isForMainFrame: false,
+ isRedirect: true,
+ hasGesture: true,
+ method: 'GET',
+ requestHeaders: <String, String>{'X-Mock': 'mocking'},
+ ),
+ android_webview.WebResourceError(
+ errorCode: android_webview.WebViewClient.errorFileNotFound,
+ description: 'Page not found.',
+ ),
+ );
+
+ expect(callbackError.errorCode,
+ android_webview.WebViewClient.errorFileNotFound);
+ expect(callbackError.description, 'Page not found.');
+ expect(callbackError.errorType, WebResourceErrorType.fileNotFound);
+ expect(callbackError.isForMainFrame, false);
+ });
+
+ test('onWebResourceError from onRequestError', () {
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ late final WebResourceError callbackError;
+ androidNavigationDelegate.setOnWebResourceError(
+ (WebResourceError error) => callbackError = error);
+
+ CapturingWebViewClient.lastCreatedDelegate.onReceivedError!(
+ android_webview.WebView.detached(),
+ android_webview.WebViewClient.errorFileNotFound,
+ 'Page not found.',
+ 'https://www.google.com',
+ );
+
+ expect(callbackError.errorCode,
+ android_webview.WebViewClient.errorFileNotFound);
+ expect(callbackError.description, 'Page not found.');
+ expect(callbackError.errorType, WebResourceErrorType.fileNotFound);
+ expect(callbackError.isForMainFrame, true);
+ });
+
+ test(
+ 'onNavigationRequest from requestLoading should not be called when loadUrlCallback is not specified',
+ () {
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ NavigationRequest? callbackNavigationRequest;
+ androidNavigationDelegate
+ .setOnNavigationRequest((NavigationRequest navigationRequest) {
+ callbackNavigationRequest = navigationRequest;
+ return NavigationDecision.prevent;
+ });
+
+ CapturingWebViewClient.lastCreatedDelegate.requestLoading!(
+ android_webview.WebView.detached(),
+ android_webview.WebResourceRequest(
+ url: 'https://www.google.com',
+ isForMainFrame: true,
+ isRedirect: true,
+ hasGesture: true,
+ method: 'GET',
+ requestHeaders: <String, String>{'X-Mock': 'mocking'},
+ ),
+ );
+
+ expect(callbackNavigationRequest, isNull);
+ });
+
+ test(
+ 'onLoadRequest from requestLoading should not be called when navigationRequestCallback is not specified',
+ () {
+ final Completer<void> completer = Completer<void>();
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnLoadRequest((_) {
+ completer.complete();
+ return completer.future;
+ });
+
+ CapturingWebViewClient.lastCreatedDelegate.requestLoading!(
+ android_webview.WebView.detached(),
+ android_webview.WebResourceRequest(
+ url: 'https://www.google.com',
+ isForMainFrame: true,
+ isRedirect: true,
+ hasGesture: true,
+ method: 'GET',
+ requestHeaders: <String, String>{'X-Mock': 'mocking'},
+ ),
+ );
+
+ expect(completer.isCompleted, false);
+ });
+
+ test(
+ 'onLoadRequest from requestLoading should not be called when onNavigationRequestCallback returns NavigationDecision.prevent',
+ () {
+ final Completer<void> completer = Completer<void>();
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnLoadRequest((_) {
+ completer.complete();
+ return completer.future;
+ });
+
+ late final NavigationRequest callbackNavigationRequest;
+ androidNavigationDelegate
+ .setOnNavigationRequest((NavigationRequest navigationRequest) {
+ callbackNavigationRequest = navigationRequest;
+ return NavigationDecision.prevent;
+ });
+
+ CapturingWebViewClient.lastCreatedDelegate.requestLoading!(
+ android_webview.WebView.detached(),
+ android_webview.WebResourceRequest(
+ url: 'https://www.google.com',
+ isForMainFrame: true,
+ isRedirect: true,
+ hasGesture: true,
+ method: 'GET',
+ requestHeaders: <String, String>{'X-Mock': 'mocking'},
+ ),
+ );
+
+ expect(callbackNavigationRequest.isMainFrame, true);
+ expect(callbackNavigationRequest.url, 'https://www.google.com');
+ expect(completer.isCompleted, false);
+ });
+
+ test(
+ 'onLoadRequest from requestLoading should complete when onNavigationRequestCallback returns NavigationDecision.navigate',
+ () {
+ final Completer<void> completer = Completer<void>();
+ late final LoadRequestParams loadRequestParams;
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnLoadRequest((LoadRequestParams params) {
+ loadRequestParams = params;
+ completer.complete();
+ return completer.future;
+ });
+
+ late final NavigationRequest callbackNavigationRequest;
+ androidNavigationDelegate
+ .setOnNavigationRequest((NavigationRequest navigationRequest) {
+ callbackNavigationRequest = navigationRequest;
+ return NavigationDecision.navigate;
+ });
+
+ CapturingWebViewClient.lastCreatedDelegate.requestLoading!(
+ android_webview.WebView.detached(),
+ android_webview.WebResourceRequest(
+ url: 'https://www.google.com',
+ isForMainFrame: true,
+ isRedirect: true,
+ hasGesture: true,
+ method: 'GET',
+ requestHeaders: <String, String>{'X-Mock': 'mocking'},
+ ),
+ );
+
+ expect(loadRequestParams.uri.toString(), 'https://www.google.com');
+ expect(loadRequestParams.headers, <String, String>{'X-Mock': 'mocking'});
+ expect(callbackNavigationRequest.isMainFrame, true);
+ expect(callbackNavigationRequest.url, 'https://www.google.com');
+ expect(completer.isCompleted, true);
+ });
+
+ test(
+ 'onNavigationRequest from urlLoading should not be called when loadUrlCallback is not specified',
+ () {
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ NavigationRequest? callbackNavigationRequest;
+ androidNavigationDelegate
+ .setOnNavigationRequest((NavigationRequest navigationRequest) {
+ callbackNavigationRequest = navigationRequest;
+ return NavigationDecision.prevent;
+ });
+
+ CapturingWebViewClient.lastCreatedDelegate.urlLoading!(
+ android_webview.WebView.detached(),
+ 'https://www.google.com',
+ );
+
+ expect(callbackNavigationRequest, isNull);
+ });
+
+ test(
+ 'onLoadRequest from urlLoading should not be called when navigationRequestCallback is not specified',
+ () {
+ final Completer<void> completer = Completer<void>();
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnLoadRequest((_) {
+ completer.complete();
+ return completer.future;
+ });
+
+ CapturingWebViewClient.lastCreatedDelegate.urlLoading!(
+ android_webview.WebView.detached(),
+ 'https://www.google.com',
+ );
+
+ expect(completer.isCompleted, false);
+ });
+
+ test(
+ 'onLoadRequest from urlLoading should not be called when onNavigationRequestCallback returns NavigationDecision.prevent',
+ () {
+ final Completer<void> completer = Completer<void>();
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnLoadRequest((_) {
+ completer.complete();
+ return completer.future;
+ });
+
+ late final NavigationRequest callbackNavigationRequest;
+ androidNavigationDelegate
+ .setOnNavigationRequest((NavigationRequest navigationRequest) {
+ callbackNavigationRequest = navigationRequest;
+ return NavigationDecision.prevent;
+ });
+
+ CapturingWebViewClient.lastCreatedDelegate.urlLoading!(
+ android_webview.WebView.detached(),
+ 'https://www.google.com',
+ );
+
+ expect(callbackNavigationRequest.isMainFrame, true);
+ expect(callbackNavigationRequest.url, 'https://www.google.com');
+ expect(completer.isCompleted, false);
+ });
+
+ test(
+ 'onLoadRequest from urlLoading should complete when onNavigationRequestCallback returns NavigationDecision.navigate',
+ () {
+ final Completer<void> completer = Completer<void>();
+ late final LoadRequestParams loadRequestParams;
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnLoadRequest((LoadRequestParams params) {
+ loadRequestParams = params;
+ completer.complete();
+ return completer.future;
+ });
+
+ late final NavigationRequest callbackNavigationRequest;
+ androidNavigationDelegate
+ .setOnNavigationRequest((NavigationRequest navigationRequest) {
+ callbackNavigationRequest = navigationRequest;
+ return NavigationDecision.navigate;
+ });
+
+ CapturingWebViewClient.lastCreatedDelegate.urlLoading!(
+ android_webview.WebView.detached(),
+ 'https://www.google.com',
+ );
+
+ expect(loadRequestParams.uri.toString(), 'https://www.google.com');
+ expect(loadRequestParams.headers, <String, String>{});
+ expect(callbackNavigationRequest.isMainFrame, true);
+ expect(callbackNavigationRequest.url, 'https://www.google.com');
+ expect(completer.isCompleted, true);
+ });
+
+ test('setOnNavigationRequest should override URL loading', () {
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnNavigationRequest(
+ (NavigationRequest request) => NavigationDecision.navigate,
+ );
+
+ expect(
+ CapturingWebViewClient.lastCreatedDelegate
+ .synchronousReturnValueForShouldOverrideUrlLoading,
+ isTrue);
+ });
+
+ test('onProgress', () {
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ late final int callbackProgress;
+ androidNavigationDelegate
+ .setOnProgress((int progress) => callbackProgress = progress);
+
+ CapturingWebChromeClient.lastCreatedDelegate.onProgressChanged!(
+ android_webview.WebView.detached(),
+ 42,
+ );
+
+ expect(callbackProgress, 42);
+ });
+
+ test(
+ 'onLoadRequest from onDownloadStart should not be called when navigationRequestCallback is not specified',
+ () {
+ final Completer<void> completer = Completer<void>();
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnLoadRequest((_) {
+ completer.complete();
+ return completer.future;
+ });
+
+ CapturingDownloadListener.lastCreatedListener.onDownloadStart(
+ '',
+ '',
+ '',
+ '',
+ 0,
+ );
+
+ expect(completer.isCompleted, false);
+ });
+
+ test(
+ 'onLoadRequest from onDownloadStart should not be called when onNavigationRequestCallback returns NavigationDecision.prevent',
+ () {
+ final Completer<void> completer = Completer<void>();
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnLoadRequest((_) {
+ completer.complete();
+ return completer.future;
+ });
+
+ late final NavigationRequest callbackNavigationRequest;
+ androidNavigationDelegate
+ .setOnNavigationRequest((NavigationRequest navigationRequest) {
+ callbackNavigationRequest = navigationRequest;
+ return NavigationDecision.prevent;
+ });
+
+ CapturingDownloadListener.lastCreatedListener.onDownloadStart(
+ 'https://www.google.com',
+ '',
+ '',
+ '',
+ 0,
+ );
+
+ expect(callbackNavigationRequest.isMainFrame, true);
+ expect(callbackNavigationRequest.url, 'https://www.google.com');
+ expect(completer.isCompleted, false);
+ });
+
+ test(
+ 'onLoadRequest from onDownloadStart should complete when onNavigationRequestCallback returns NavigationDecision.navigate',
+ () {
+ final Completer<void> completer = Completer<void>();
+ late final LoadRequestParams loadRequestParams;
+ final AndroidNavigationDelegate androidNavigationDelegate =
+ AndroidNavigationDelegate(_buildCreationParams());
+
+ androidNavigationDelegate.setOnLoadRequest((LoadRequestParams params) {
+ loadRequestParams = params;
+ completer.complete();
+ return completer.future;
+ });
+
+ late final NavigationRequest callbackNavigationRequest;
+ androidNavigationDelegate
+ .setOnNavigationRequest((NavigationRequest navigationRequest) {
+ callbackNavigationRequest = navigationRequest;
+ return NavigationDecision.navigate;
+ });
+
+ CapturingDownloadListener.lastCreatedListener.onDownloadStart(
+ 'https://www.google.com',
+ '',
+ '',
+ '',
+ 0,
+ );
+
+ expect(loadRequestParams.uri.toString(), 'https://www.google.com');
+ expect(loadRequestParams.headers, <String, String>{});
+ expect(callbackNavigationRequest.isMainFrame, true);
+ expect(callbackNavigationRequest.url, 'https://www.google.com');
+ expect(completer.isCompleted, true);
+ });
+ });
+}
+
+AndroidNavigationDelegateCreationParams _buildCreationParams() {
+ return AndroidNavigationDelegateCreationParams
+ .fromPlatformNavigationDelegateCreationParams(
+ const PlatformNavigationDelegateCreationParams(),
+ androidWebViewProxy: const AndroidWebViewProxy(
+ createAndroidWebChromeClient: CapturingWebChromeClient.new,
+ createAndroidWebViewClient: CapturingWebViewClient.new,
+ createDownloadListener: CapturingDownloadListener.new,
+ ),
+ );
+}
+
+// Records the last created instance of itself.
+class CapturingWebViewClient extends android_webview.WebViewClient {
+ CapturingWebViewClient({
+ super.onPageFinished,
+ super.onPageStarted,
+ super.onReceivedError,
+ super.onReceivedRequestError,
+ super.requestLoading,
+ super.urlLoading,
+ }) : super.detached() {
+ lastCreatedDelegate = this;
+ }
+
+ static CapturingWebViewClient lastCreatedDelegate = CapturingWebViewClient();
+
+ bool synchronousReturnValueForShouldOverrideUrlLoading = false;
+
+ @override
+ Future<void> setSynchronousReturnValueForShouldOverrideUrlLoading(
+ bool value) async {
+ synchronousReturnValueForShouldOverrideUrlLoading = value;
+ }
+}
+
+// Records the last created instance of itself.
+class CapturingWebChromeClient extends android_webview.WebChromeClient {
+ CapturingWebChromeClient({
+ super.onProgressChanged,
+ }) : super.detached() {
+ lastCreatedDelegate = this;
+ }
+ static CapturingWebChromeClient lastCreatedDelegate =
+ CapturingWebChromeClient();
+}
+
+// Records the last created instance of itself.
+class CapturingDownloadListener extends android_webview.DownloadListener {
+ CapturingDownloadListener({
+ required super.onDownloadStart,
+ }) : super.detached() {
+ lastCreatedListener = this;
+ }
+ static CapturingDownloadListener lastCreatedListener =
+ CapturingDownloadListener(onDownloadStart: (_, __, ___, ____, _____) {});
+}
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart
new file mode 100644
index 0000000..4b74f3a
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.dart
@@ -0,0 +1,798 @@
+// 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.
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'package:webview_flutter_android/src/android_proxy.dart';
+import 'package:webview_flutter_android/src/android_webview.dart'
+ as android_webview;
+import 'package:webview_flutter_android/src/instance_manager.dart';
+import 'package:webview_flutter_android/webview_flutter_android.dart';
+import 'package:webview_flutter_platform_interface/src/webview_platform.dart';
+
+import 'android_webview_controller_test.mocks.dart';
+
+@GenerateNiceMocks(<MockSpec<Object>>[
+ MockSpec<AndroidNavigationDelegate>(),
+ MockSpec<AndroidWebViewController>(),
+ MockSpec<AndroidWebViewProxy>(),
+ MockSpec<AndroidWebViewWidgetCreationParams>(),
+ MockSpec<android_webview.FlutterAssetManager>(),
+ MockSpec<android_webview.JavaScriptChannel>(),
+ MockSpec<android_webview.WebChromeClient>(),
+ MockSpec<android_webview.WebSettings>(),
+ MockSpec<android_webview.WebView>(),
+ MockSpec<android_webview.WebViewClient>(),
+ MockSpec<android_webview.WebStorage>(),
+ MockSpec<InstanceManager>(),
+])
+void main() {
+ TestWidgetsFlutterBinding.ensureInitialized();
+
+ AndroidWebViewController createControllerWithMocks({
+ android_webview.FlutterAssetManager? mockFlutterAssetManager,
+ android_webview.JavaScriptChannel? mockJavaScriptChannel,
+ android_webview.WebChromeClient? mockWebChromeClient,
+ android_webview.WebView? mockWebView,
+ android_webview.WebViewClient? mockWebViewClient,
+ android_webview.WebStorage? mockWebStorage,
+ android_webview.WebSettings? mockSettings,
+ }) {
+ final android_webview.WebView nonNullMockWebView =
+ mockWebView ?? MockWebView();
+
+ final AndroidWebViewControllerCreationParams creationParams =
+ AndroidWebViewControllerCreationParams(
+ androidWebStorage: mockWebStorage ?? MockWebStorage(),
+ androidWebViewProxy: AndroidWebViewProxy(
+ createAndroidWebChromeClient: (
+ {void Function(android_webview.WebView, int)?
+ onProgressChanged}) =>
+ mockWebChromeClient ?? MockWebChromeClient(),
+ createAndroidWebView: ({required bool useHybridComposition}) =>
+ nonNullMockWebView,
+ createAndroidWebViewClient: ({
+ void Function(android_webview.WebView webView, String url)?
+ onPageFinished,
+ void Function(android_webview.WebView webView, String url)?
+ onPageStarted,
+ @Deprecated('Only called on Android version < 23.')
+ void Function(
+ android_webview.WebView webView,
+ int errorCode,
+ String description,
+ String failingUrl,
+ )?
+ onReceivedError,
+ void Function(
+ android_webview.WebView webView,
+ android_webview.WebResourceRequest request,
+ android_webview.WebResourceError error,
+ )?
+ onReceivedRequestError,
+ void Function(
+ android_webview.WebView webView,
+ android_webview.WebResourceRequest request,
+ )?
+ requestLoading,
+ void Function(android_webview.WebView webView, String url)?
+ urlLoading,
+ }) =>
+ mockWebViewClient ?? MockWebViewClient(),
+ createFlutterAssetManager: () =>
+ mockFlutterAssetManager ?? MockFlutterAssetManager(),
+ createJavaScriptChannel: (
+ String channelName, {
+ required void Function(String) postMessage,
+ }) =>
+ mockJavaScriptChannel ?? MockJavaScriptChannel(),
+ ));
+
+ when(nonNullMockWebView.settings)
+ .thenReturn(mockSettings ?? MockWebSettings());
+
+ return AndroidWebViewController(creationParams);
+ }
+
+ group('AndroidWebViewController', () {
+ AndroidJavaScriptChannelParams
+ createAndroidJavaScriptChannelParamsWithMocks({
+ String? name,
+ MockJavaScriptChannel? mockJavaScriptChannel,
+ }) {
+ return AndroidJavaScriptChannelParams(
+ name: name ?? 'test',
+ onMessageReceived: (JavaScriptMessage message) {},
+ webViewProxy: AndroidWebViewProxy(
+ createJavaScriptChannel: (
+ String channelName, {
+ required void Function(String) postMessage,
+ }) =>
+ mockJavaScriptChannel ?? MockJavaScriptChannel(),
+ ));
+ }
+
+ test('loadFile without file prefix', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockWebSettings mockWebSettings = MockWebSettings();
+ createControllerWithMocks(
+ mockWebView: mockWebView,
+ mockSettings: mockWebSettings,
+ );
+
+ verify(mockWebSettings.setBuiltInZoomControls(true)).called(1);
+ verify(mockWebSettings.setDisplayZoomControls(false)).called(1);
+ verify(mockWebSettings.setDomStorageEnabled(true)).called(1);
+ verify(mockWebSettings.setJavaScriptCanOpenWindowsAutomatically(true))
+ .called(1);
+ verify(mockWebSettings.setLoadWithOverviewMode(true)).called(1);
+ verify(mockWebSettings.setSupportMultipleWindows(true)).called(1);
+ verify(mockWebSettings.setUseWideViewPort(true)).called(1);
+ });
+
+ test('loadFile without file prefix', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockWebSettings mockWebSettings = MockWebSettings();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ mockSettings: mockWebSettings,
+ );
+
+ await controller.loadFile('/path/to/file.html');
+
+ verify(mockWebSettings.setAllowFileAccess(true)).called(1);
+ verify(mockWebView.loadUrl(
+ 'file:///path/to/file.html',
+ <String, String>{},
+ )).called(1);
+ });
+
+ test('loadFile without file prefix and characters to be escaped', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockWebSettings mockWebSettings = MockWebSettings();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ mockSettings: mockWebSettings,
+ );
+
+ await controller.loadFile('/path/to/?_<_>_.html');
+
+ verify(mockWebSettings.setAllowFileAccess(true)).called(1);
+ verify(mockWebView.loadUrl(
+ 'file:///path/to/%3F_%3C_%3E_.html',
+ <String, String>{},
+ )).called(1);
+ });
+
+ test('loadFile with file prefix', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockWebSettings mockWebSettings = MockWebSettings();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ when(mockWebView.settings).thenReturn(mockWebSettings);
+
+ await controller.loadFile('file:///path/to/file.html');
+
+ verify(mockWebSettings.setAllowFileAccess(true)).called(1);
+ verify(mockWebView.loadUrl(
+ 'file:///path/to/file.html',
+ <String, String>{},
+ )).called(1);
+ });
+
+ test('loadFlutterAsset when asset does not exists', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockFlutterAssetManager mockAssetManager =
+ MockFlutterAssetManager();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockFlutterAssetManager: mockAssetManager,
+ mockWebView: mockWebView,
+ );
+
+ when(mockAssetManager.getAssetFilePathByName('mock_key'))
+ .thenAnswer((_) => Future<String>.value(''));
+ when(mockAssetManager.list(''))
+ .thenAnswer((_) => Future<List<String>>.value(<String>[]));
+
+ try {
+ await controller.loadFlutterAsset('mock_key');
+ fail('Expected an `ArgumentError`.');
+ } on ArgumentError catch (e) {
+ expect(e.message, 'Asset for key "mock_key" not found.');
+ expect(e.name, 'key');
+ } on Error {
+ fail('Expect an `ArgumentError`.');
+ }
+
+ verify(mockAssetManager.getAssetFilePathByName('mock_key')).called(1);
+ verify(mockAssetManager.list('')).called(1);
+ verifyNever(mockWebView.loadUrl(any, any));
+ });
+
+ test('loadFlutterAsset when asset does exists', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockFlutterAssetManager mockAssetManager =
+ MockFlutterAssetManager();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockFlutterAssetManager: mockAssetManager,
+ mockWebView: mockWebView,
+ );
+
+ when(mockAssetManager.getAssetFilePathByName('mock_key'))
+ .thenAnswer((_) => Future<String>.value('www/mock_file.html'));
+ when(mockAssetManager.list('www')).thenAnswer(
+ (_) => Future<List<String>>.value(<String>['mock_file.html']));
+
+ await controller.loadFlutterAsset('mock_key');
+
+ verify(mockAssetManager.getAssetFilePathByName('mock_key')).called(1);
+ verify(mockAssetManager.list('www')).called(1);
+ verify(mockWebView.loadUrl(
+ 'file:///android_asset/www/mock_file.html', <String, String>{}));
+ });
+
+ test(
+ 'loadFlutterAsset when asset name contains characters that should be escaped',
+ () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockFlutterAssetManager mockAssetManager =
+ MockFlutterAssetManager();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockFlutterAssetManager: mockAssetManager,
+ mockWebView: mockWebView,
+ );
+
+ when(mockAssetManager.getAssetFilePathByName('mock_key'))
+ .thenAnswer((_) => Future<String>.value('www/?_<_>_.html'));
+ when(mockAssetManager.list('www')).thenAnswer(
+ (_) => Future<List<String>>.value(<String>['?_<_>_.html']));
+
+ await controller.loadFlutterAsset('mock_key');
+
+ verify(mockAssetManager.getAssetFilePathByName('mock_key')).called(1);
+ verify(mockAssetManager.list('www')).called(1);
+ verify(mockWebView.loadUrl(
+ 'file:///android_asset/www/%3F_%3C_%3E_.html', <String, String>{}));
+ });
+
+ test('loadHtmlString without baseUrl', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.loadHtmlString('<p>Hello Test!</p>');
+
+ verify(mockWebView.loadDataWithBaseUrl(
+ data: '<p>Hello Test!</p>',
+ mimeType: 'text/html',
+ )).called(1);
+ });
+
+ test('loadHtmlString with baseUrl', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.loadHtmlString('<p>Hello Test!</p>',
+ baseUrl: 'https://flutter.dev');
+
+ verify(mockWebView.loadDataWithBaseUrl(
+ data: '<p>Hello Test!</p>',
+ baseUrl: 'https://flutter.dev',
+ mimeType: 'text/html',
+ )).called(1);
+ });
+
+ test('loadRequest without URI scheme', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+ final LoadRequestParams requestParams = LoadRequestParams(
+ uri: Uri.parse('flutter.dev'),
+ );
+
+ try {
+ await controller.loadRequest(requestParams);
+ fail('Expect an `ArgumentError`.');
+ } on ArgumentError catch (e) {
+ expect(e.message, 'WebViewRequest#uri is required to have a scheme.');
+ } on Error {
+ fail('Expect a `ArgumentError`.');
+ }
+
+ verifyNever(mockWebView.loadUrl(any, any));
+ verifyNever(mockWebView.postUrl(any, any));
+ });
+
+ test('loadRequest using the GET method', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+ final LoadRequestParams requestParams = LoadRequestParams(
+ uri: Uri.parse('https://flutter.dev'),
+ headers: const <String, String>{'X-Test': 'Testing'},
+ );
+
+ await controller.loadRequest(requestParams);
+
+ verify(mockWebView.loadUrl(
+ 'https://flutter.dev',
+ <String, String>{'X-Test': 'Testing'},
+ ));
+ verifyNever(mockWebView.postUrl(any, any));
+ });
+
+ test('loadRequest using the POST method without body', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+ final LoadRequestParams requestParams = LoadRequestParams(
+ uri: Uri.parse('https://flutter.dev'),
+ method: LoadRequestMethod.post,
+ headers: const <String, String>{'X-Test': 'Testing'},
+ );
+
+ await controller.loadRequest(requestParams);
+
+ verify(mockWebView.postUrl(
+ 'https://flutter.dev',
+ Uint8List(0),
+ ));
+ verifyNever(mockWebView.loadUrl(any, any));
+ });
+
+ test('loadRequest using the POST method with body', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+ final LoadRequestParams requestParams = LoadRequestParams(
+ uri: Uri.parse('https://flutter.dev'),
+ method: LoadRequestMethod.post,
+ headers: const <String, String>{'X-Test': 'Testing'},
+ body: Uint8List.fromList('{"message": "Hello World!"}'.codeUnits),
+ );
+
+ await controller.loadRequest(requestParams);
+
+ verify(mockWebView.postUrl(
+ 'https://flutter.dev',
+ Uint8List.fromList('{"message": "Hello World!"}'.codeUnits),
+ ));
+ verifyNever(mockWebView.loadUrl(any, any));
+ });
+
+ test('currentUrl', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.currentUrl();
+
+ verify(mockWebView.getUrl()).called(1);
+ });
+
+ test('canGoBack', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.canGoBack();
+
+ verify(mockWebView.canGoBack()).called(1);
+ });
+
+ test('canGoForward', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.canGoForward();
+
+ verify(mockWebView.canGoForward()).called(1);
+ });
+
+ test('goBack', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.goBack();
+
+ verify(mockWebView.goBack()).called(1);
+ });
+
+ test('goForward', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.goForward();
+
+ verify(mockWebView.goForward()).called(1);
+ });
+
+ test('reload', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.reload();
+
+ verify(mockWebView.reload()).called(1);
+ });
+
+ test('clearCache', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.clearCache();
+
+ verify(mockWebView.clearCache(true)).called(1);
+ });
+
+ test('clearLocalStorage', () async {
+ final MockWebStorage mockWebStorage = MockWebStorage();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebStorage: mockWebStorage,
+ );
+
+ await controller.clearLocalStorage();
+
+ verify(mockWebStorage.deleteAllData()).called(1);
+ });
+
+ test('setPlatformNavigationDelegate', () async {
+ final MockAndroidNavigationDelegate mockNavigationDelegate =
+ MockAndroidNavigationDelegate();
+ final MockWebView mockWebView = MockWebView();
+ final MockWebChromeClient mockWebChromeClient = MockWebChromeClient();
+ final MockWebViewClient mockWebViewClient = MockWebViewClient();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ when(mockNavigationDelegate.androidWebChromeClient)
+ .thenReturn(mockWebChromeClient);
+ when(mockNavigationDelegate.androidWebViewClient)
+ .thenReturn(mockWebViewClient);
+
+ await controller.setPlatformNavigationDelegate(mockNavigationDelegate);
+
+ verifyInOrder(<Object>[
+ mockWebView.setWebViewClient(mockWebViewClient),
+ mockWebView.setWebChromeClient(mockWebChromeClient),
+ ]);
+ });
+
+ test('runJavaScript', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.runJavaScript('alert("This is a test.");');
+
+ verify(mockWebView.evaluateJavascript('alert("This is a test.");'))
+ .called(1);
+ });
+
+ test('runJavaScriptReturningResult with return value', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ when(mockWebView.evaluateJavascript('return "Hello" + " World!";'))
+ .thenAnswer((_) => Future<String>.value('Hello World!'));
+
+ final String message = await controller.runJavaScriptReturningResult(
+ 'return "Hello" + " World!";') as String;
+
+ expect(message, 'Hello World!');
+ });
+
+ test('runJavaScriptReturningResult returning null', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ when(mockWebView.evaluateJavascript('alert("This is a test.");'))
+ .thenAnswer((_) => Future<String?>.value());
+
+ final String message = await controller
+ .runJavaScriptReturningResult('alert("This is a test.");') as String;
+
+ expect(message, '');
+ });
+
+ test('runJavaScriptReturningResult parses num', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ when(mockWebView.evaluateJavascript('alert("This is a test.");'))
+ .thenAnswer((_) => Future<String?>.value('3.14'));
+
+ final num message = await controller
+ .runJavaScriptReturningResult('alert("This is a test.");') as num;
+
+ expect(message, 3.14);
+ });
+
+ test('runJavaScriptReturningResult parses true', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ when(mockWebView.evaluateJavascript('alert("This is a test.");'))
+ .thenAnswer((_) => Future<String?>.value('true'));
+
+ final bool message = await controller
+ .runJavaScriptReturningResult('alert("This is a test.");') as bool;
+
+ expect(message, true);
+ });
+
+ test('runJavaScriptReturningResult parses false', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ when(mockWebView.evaluateJavascript('alert("This is a test.");'))
+ .thenAnswer((_) => Future<String?>.value('false'));
+
+ final bool message = await controller
+ .runJavaScriptReturningResult('alert("This is a test.");') as bool;
+
+ expect(message, false);
+ });
+
+ test('addJavaScriptChannel', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+ final AndroidJavaScriptChannelParams paramsWithMock =
+ createAndroidJavaScriptChannelParamsWithMocks(name: 'test');
+ await controller.addJavaScriptChannel(paramsWithMock);
+ verify(mockWebView.addJavaScriptChannel(
+ argThat(isA<android_webview.JavaScriptChannel>())))
+ .called(1);
+ });
+
+ test(
+ 'addJavaScriptChannel add channel with same name should remove existing channel',
+ () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+ final AndroidJavaScriptChannelParams paramsWithMock =
+ createAndroidJavaScriptChannelParamsWithMocks(name: 'test');
+ await controller.addJavaScriptChannel(paramsWithMock);
+ verify(mockWebView.addJavaScriptChannel(
+ argThat(isA<android_webview.JavaScriptChannel>())))
+ .called(1);
+
+ await controller.addJavaScriptChannel(paramsWithMock);
+ verifyInOrder(<Object>[
+ mockWebView.removeJavaScriptChannel(
+ argThat(isA<android_webview.JavaScriptChannel>())),
+ mockWebView.addJavaScriptChannel(
+ argThat(isA<android_webview.JavaScriptChannel>())),
+ ]);
+ });
+
+ test('removeJavaScriptChannel when channel is not registered', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.removeJavaScriptChannel('test');
+ verifyNever(mockWebView.removeJavaScriptChannel(any));
+ });
+
+ test('removeJavaScriptChannel when channel exists', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+ final AndroidJavaScriptChannelParams paramsWithMock =
+ createAndroidJavaScriptChannelParamsWithMocks(name: 'test');
+
+ // Make sure channel exists before removing it.
+ await controller.addJavaScriptChannel(paramsWithMock);
+ verify(mockWebView.addJavaScriptChannel(
+ argThat(isA<android_webview.JavaScriptChannel>())))
+ .called(1);
+
+ await controller.removeJavaScriptChannel('test');
+ verify(mockWebView.removeJavaScriptChannel(
+ argThat(isA<android_webview.JavaScriptChannel>())))
+ .called(1);
+ });
+
+ test('getTitle', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.getTitle();
+
+ verify(mockWebView.getTitle()).called(1);
+ });
+
+ test('scrollTo', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.scrollTo(4, 2);
+
+ verify(mockWebView.scrollTo(4, 2)).called(1);
+ });
+
+ test('scrollBy', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.scrollBy(4, 2);
+
+ verify(mockWebView.scrollBy(4, 2)).called(1);
+ });
+
+ test('getScrollPosition', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+ when(mockWebView.getScrollPosition())
+ .thenAnswer((_) => Future<Offset>.value(const Offset(4, 2)));
+
+ final Offset position = await controller.getScrollPosition();
+
+ verify(mockWebView.getScrollPosition()).called(1);
+ expect(position.dx, 4);
+ expect(position.dy, 2);
+ });
+
+ test('enableDebugging', () async {
+ final MockAndroidWebViewProxy mockProxy = MockAndroidWebViewProxy();
+
+ await AndroidWebViewController.enableDebugging(
+ true,
+ webViewProxy: mockProxy,
+ );
+ verify(mockProxy.setWebContentsDebuggingEnabled(true)).called(1);
+ });
+
+ test('enableZoom', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockWebSettings mockSettings = MockWebSettings();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ mockSettings: mockSettings,
+ );
+
+ clearInteractions(mockWebView);
+
+ await controller.enableZoom(true);
+
+ verify(mockWebView.settings).called(1);
+ verify(mockSettings.setSupportZoom(true)).called(1);
+ });
+
+ test('setBackgroundColor', () async {
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ );
+
+ await controller.setBackgroundColor(Colors.blue);
+
+ verify(mockWebView.setBackgroundColor(Colors.blue)).called(1);
+ });
+
+ test('setJavaScriptMode', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockWebSettings mockSettings = MockWebSettings();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ mockSettings: mockSettings,
+ );
+
+ clearInteractions(mockWebView);
+
+ await controller.setJavaScriptMode(JavaScriptMode.disabled);
+
+ verify(mockWebView.settings).called(1);
+ verify(mockSettings.setJavaScriptEnabled(false)).called(1);
+ });
+
+ test('setUserAgent', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockWebSettings mockSettings = MockWebSettings();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ mockSettings: mockSettings,
+ );
+
+ clearInteractions(mockWebView);
+
+ await controller.setUserAgent('Test Framework');
+
+ verify(mockWebView.settings).called(1);
+ verify(mockSettings.setUserAgentString('Test Framework')).called(1);
+ });
+ });
+
+ test('setMediaPlaybackRequiresUserGesture', () async {
+ final MockWebView mockWebView = MockWebView();
+ final MockWebSettings mockSettings = MockWebSettings();
+ final AndroidWebViewController controller = createControllerWithMocks(
+ mockWebView: mockWebView,
+ mockSettings: mockSettings,
+ );
+
+ await controller.setMediaPlaybackRequiresUserGesture(true);
+
+ verify(mockSettings.setMediaPlaybackRequiresUserGesture(true)).called(1);
+ });
+
+ group('AndroidWebViewWidget', () {
+ testWidgets('Builds AndroidView using supplied parameters',
+ (WidgetTester tester) async {
+ final MockAndroidWebViewWidgetCreationParams mockParams =
+ MockAndroidWebViewWidgetCreationParams();
+ final MockInstanceManager mockInstanceManager = MockInstanceManager();
+ final MockWebView mockWebView = MockWebView();
+ final AndroidWebViewController controller =
+ createControllerWithMocks(mockWebView: mockWebView);
+
+ when(mockParams.key).thenReturn(const Key('test_web_view'));
+ when(mockParams.instanceManager).thenReturn(mockInstanceManager);
+ when(mockParams.controller).thenReturn(controller);
+ when(mockInstanceManager.getIdentifier(mockWebView)).thenReturn(42);
+
+ final AndroidWebViewWidget webViewWidget =
+ AndroidWebViewWidget(mockParams);
+
+ await tester.pumpWidget(Builder(
+ builder: (BuildContext context) => webViewWidget.build(context),
+ ));
+
+ expect(find.byType(PlatformViewLink), findsOneWidget);
+ expect(find.byKey(const Key('test_web_view')), findsOneWidget);
+ });
+ });
+}
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart
new file mode 100644
index 0000000..d6147a5
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_controller_test.mocks.dart
@@ -0,0 +1,1679 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_android/test/android_webview_controller_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i7;
+import 'dart:typed_data' as _i12;
+import 'dart:ui' as _i4;
+
+import 'package:flutter/foundation.dart' as _i10;
+import 'package:flutter/gestures.dart' as _i11;
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_android/src/android_navigation_delegate.dart'
+ as _i6;
+import 'package:webview_flutter_android/src/android_proxy.dart' as _i9;
+import 'package:webview_flutter_android/src/android_webview.dart' as _i2;
+import 'package:webview_flutter_android/src/android_webview_controller.dart'
+ as _i8;
+import 'package:webview_flutter_android/src/instance_manager.dart' as _i5;
+import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'
+ as _i3;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeWebChromeClient_0 extends _i1.SmartFake
+ implements _i2.WebChromeClient {
+ _FakeWebChromeClient_0(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeWebViewClient_1 extends _i1.SmartFake implements _i2.WebViewClient {
+ _FakeWebViewClient_1(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeDownloadListener_2 extends _i1.SmartFake
+ implements _i2.DownloadListener {
+ _FakeDownloadListener_2(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakePlatformNavigationDelegateCreationParams_3 extends _i1.SmartFake
+ implements _i3.PlatformNavigationDelegateCreationParams {
+ _FakePlatformNavigationDelegateCreationParams_3(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakePlatformWebViewControllerCreationParams_4 extends _i1.SmartFake
+ implements _i3.PlatformWebViewControllerCreationParams {
+ _FakePlatformWebViewControllerCreationParams_4(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeObject_5 extends _i1.SmartFake implements Object {
+ _FakeObject_5(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeOffset_6 extends _i1.SmartFake implements _i4.Offset {
+ _FakeOffset_6(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeWebView_7 extends _i1.SmartFake implements _i2.WebView {
+ _FakeWebView_7(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeFlutterAssetManager_8 extends _i1.SmartFake
+ implements _i2.FlutterAssetManager {
+ _FakeFlutterAssetManager_8(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeJavaScriptChannel_9 extends _i1.SmartFake
+ implements _i2.JavaScriptChannel {
+ _FakeJavaScriptChannel_9(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeInstanceManager_10 extends _i1.SmartFake
+ implements _i5.InstanceManager {
+ _FakeInstanceManager_10(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakePlatformWebViewController_11 extends _i1.SmartFake
+ implements _i3.PlatformWebViewController {
+ _FakePlatformWebViewController_11(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeWebSettings_12 extends _i1.SmartFake implements _i2.WebSettings {
+ _FakeWebSettings_12(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeWebStorage_13 extends _i1.SmartFake implements _i2.WebStorage {
+ _FakeWebStorage_13(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+/// A class which mocks [AndroidNavigationDelegate].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockAndroidNavigationDelegate extends _i1.Mock
+ implements _i6.AndroidNavigationDelegate {
+ @override
+ _i2.WebChromeClient get androidWebChromeClient => (super.noSuchMethod(
+ Invocation.getter(#androidWebChromeClient),
+ returnValue: _FakeWebChromeClient_0(
+ this,
+ Invocation.getter(#androidWebChromeClient),
+ ),
+ returnValueForMissingStub: _FakeWebChromeClient_0(
+ this,
+ Invocation.getter(#androidWebChromeClient),
+ ),
+ ) as _i2.WebChromeClient);
+ @override
+ _i2.WebViewClient get androidWebViewClient => (super.noSuchMethod(
+ Invocation.getter(#androidWebViewClient),
+ returnValue: _FakeWebViewClient_1(
+ this,
+ Invocation.getter(#androidWebViewClient),
+ ),
+ returnValueForMissingStub: _FakeWebViewClient_1(
+ this,
+ Invocation.getter(#androidWebViewClient),
+ ),
+ ) as _i2.WebViewClient);
+ @override
+ _i2.DownloadListener get androidDownloadListener => (super.noSuchMethod(
+ Invocation.getter(#androidDownloadListener),
+ returnValue: _FakeDownloadListener_2(
+ this,
+ Invocation.getter(#androidDownloadListener),
+ ),
+ returnValueForMissingStub: _FakeDownloadListener_2(
+ this,
+ Invocation.getter(#androidDownloadListener),
+ ),
+ ) as _i2.DownloadListener);
+ @override
+ _i3.PlatformNavigationDelegateCreationParams get params =>
+ (super.noSuchMethod(
+ Invocation.getter(#params),
+ returnValue: _FakePlatformNavigationDelegateCreationParams_3(
+ this,
+ Invocation.getter(#params),
+ ),
+ returnValueForMissingStub:
+ _FakePlatformNavigationDelegateCreationParams_3(
+ this,
+ Invocation.getter(#params),
+ ),
+ ) as _i3.PlatformNavigationDelegateCreationParams);
+ @override
+ _i7.Future<void> setOnLoadRequest(_i6.LoadRequestCallback? onLoadRequest) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setOnLoadRequest,
+ [onLoadRequest],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setOnNavigationRequest(
+ _i3.NavigationRequestCallback? onNavigationRequest) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setOnNavigationRequest,
+ [onNavigationRequest],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setOnPageStarted(_i3.PageEventCallback? onPageStarted) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setOnPageStarted,
+ [onPageStarted],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setOnPageFinished(_i3.PageEventCallback? onPageFinished) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setOnPageFinished,
+ [onPageFinished],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setOnProgress(_i3.ProgressCallback? onProgress) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setOnProgress,
+ [onProgress],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setOnWebResourceError(
+ _i3.WebResourceErrorCallback? onWebResourceError) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setOnWebResourceError,
+ [onWebResourceError],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+}
+
+/// A class which mocks [AndroidWebViewController].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockAndroidWebViewController extends _i1.Mock
+ implements _i8.AndroidWebViewController {
+ @override
+ _i3.PlatformWebViewControllerCreationParams get params => (super.noSuchMethod(
+ Invocation.getter(#params),
+ returnValue: _FakePlatformWebViewControllerCreationParams_4(
+ this,
+ Invocation.getter(#params),
+ ),
+ returnValueForMissingStub:
+ _FakePlatformWebViewControllerCreationParams_4(
+ this,
+ Invocation.getter(#params),
+ ),
+ ) as _i3.PlatformWebViewControllerCreationParams);
+ @override
+ _i7.Future<void> loadFile(String? absoluteFilePath) => (super.noSuchMethod(
+ Invocation.method(
+ #loadFile,
+ [absoluteFilePath],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> loadFlutterAsset(String? key) => (super.noSuchMethod(
+ Invocation.method(
+ #loadFlutterAsset,
+ [key],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> loadHtmlString(
+ String? html, {
+ String? baseUrl,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #loadHtmlString,
+ [html],
+ {#baseUrl: baseUrl},
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> loadRequest(_i3.LoadRequestParams? params) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #loadRequest,
+ [params],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<String?> currentUrl() => (super.noSuchMethod(
+ Invocation.method(
+ #currentUrl,
+ [],
+ ),
+ returnValue: _i7.Future<String?>.value(),
+ returnValueForMissingStub: _i7.Future<String?>.value(),
+ ) as _i7.Future<String?>);
+ @override
+ _i7.Future<bool> canGoBack() => (super.noSuchMethod(
+ Invocation.method(
+ #canGoBack,
+ [],
+ ),
+ returnValue: _i7.Future<bool>.value(false),
+ returnValueForMissingStub: _i7.Future<bool>.value(false),
+ ) as _i7.Future<bool>);
+ @override
+ _i7.Future<bool> canGoForward() => (super.noSuchMethod(
+ Invocation.method(
+ #canGoForward,
+ [],
+ ),
+ returnValue: _i7.Future<bool>.value(false),
+ returnValueForMissingStub: _i7.Future<bool>.value(false),
+ ) as _i7.Future<bool>);
+ @override
+ _i7.Future<void> goBack() => (super.noSuchMethod(
+ Invocation.method(
+ #goBack,
+ [],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> goForward() => (super.noSuchMethod(
+ Invocation.method(
+ #goForward,
+ [],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> reload() => (super.noSuchMethod(
+ Invocation.method(
+ #reload,
+ [],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> clearCache() => (super.noSuchMethod(
+ Invocation.method(
+ #clearCache,
+ [],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> clearLocalStorage() => (super.noSuchMethod(
+ Invocation.method(
+ #clearLocalStorage,
+ [],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setPlatformNavigationDelegate(
+ _i3.PlatformNavigationDelegate? handler) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setPlatformNavigationDelegate,
+ [handler],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> runJavaScript(String? javaScript) => (super.noSuchMethod(
+ Invocation.method(
+ #runJavaScript,
+ [javaScript],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<Object> runJavaScriptReturningResult(String? javaScript) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #runJavaScriptReturningResult,
+ [javaScript],
+ ),
+ returnValue: _i7.Future<Object>.value(_FakeObject_5(
+ this,
+ Invocation.method(
+ #runJavaScriptReturningResult,
+ [javaScript],
+ ),
+ )),
+ returnValueForMissingStub: _i7.Future<Object>.value(_FakeObject_5(
+ this,
+ Invocation.method(
+ #runJavaScriptReturningResult,
+ [javaScript],
+ ),
+ )),
+ ) as _i7.Future<Object>);
+ @override
+ _i7.Future<void> addJavaScriptChannel(
+ _i3.JavaScriptChannelParams? javaScriptChannelParams) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #addJavaScriptChannel,
+ [javaScriptChannelParams],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> removeJavaScriptChannel(String? javaScriptChannelName) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #removeJavaScriptChannel,
+ [javaScriptChannelName],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<String?> getTitle() => (super.noSuchMethod(
+ Invocation.method(
+ #getTitle,
+ [],
+ ),
+ returnValue: _i7.Future<String?>.value(),
+ returnValueForMissingStub: _i7.Future<String?>.value(),
+ ) as _i7.Future<String?>);
+ @override
+ _i7.Future<void> scrollTo(
+ int? x,
+ int? y,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #scrollTo,
+ [
+ x,
+ y,
+ ],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> scrollBy(
+ int? x,
+ int? y,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #scrollBy,
+ [
+ x,
+ y,
+ ],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<_i4.Offset> getScrollPosition() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ returnValue: _i7.Future<_i4.Offset>.value(_FakeOffset_6(
+ this,
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ )),
+ returnValueForMissingStub: _i7.Future<_i4.Offset>.value(_FakeOffset_6(
+ this,
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ )),
+ ) as _i7.Future<_i4.Offset>);
+ @override
+ _i7.Future<void> enableZoom(bool? enabled) => (super.noSuchMethod(
+ Invocation.method(
+ #enableZoom,
+ [enabled],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setBackgroundColor(_i4.Color? color) => (super.noSuchMethod(
+ Invocation.method(
+ #setBackgroundColor,
+ [color],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setJavaScriptMode(_i3.JavaScriptMode? javaScriptMode) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setJavaScriptMode,
+ [javaScriptMode],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setUserAgent(String? userAgent) => (super.noSuchMethod(
+ Invocation.method(
+ #setUserAgent,
+ [userAgent],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setMediaPlaybackRequiresUserGesture(bool? require) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setMediaPlaybackRequiresUserGesture,
+ [require],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+}
+
+/// A class which mocks [AndroidWebViewProxy].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockAndroidWebViewProxy extends _i1.Mock
+ implements _i9.AndroidWebViewProxy {
+ @override
+ _i2.WebView Function({required bool useHybridComposition})
+ get createAndroidWebView => (super.noSuchMethod(
+ Invocation.getter(#createAndroidWebView),
+ returnValue: ({required bool useHybridComposition}) =>
+ _FakeWebView_7(
+ this,
+ Invocation.getter(#createAndroidWebView),
+ ),
+ returnValueForMissingStub: ({required bool useHybridComposition}) =>
+ _FakeWebView_7(
+ this,
+ Invocation.getter(#createAndroidWebView),
+ ),
+ ) as _i2.WebView Function({required bool useHybridComposition}));
+ @override
+ _i2.WebChromeClient Function(
+ {void Function(
+ _i2.WebView,
+ int,
+ )?
+ onProgressChanged}) get createAndroidWebChromeClient =>
+ (super.noSuchMethod(
+ Invocation.getter(#createAndroidWebChromeClient),
+ returnValue: (
+ {void Function(
+ _i2.WebView,
+ int,
+ )?
+ onProgressChanged}) =>
+ _FakeWebChromeClient_0(
+ this,
+ Invocation.getter(#createAndroidWebChromeClient),
+ ),
+ returnValueForMissingStub: (
+ {void Function(
+ _i2.WebView,
+ int,
+ )?
+ onProgressChanged}) =>
+ _FakeWebChromeClient_0(
+ this,
+ Invocation.getter(#createAndroidWebChromeClient),
+ ),
+ ) as _i2.WebChromeClient Function(
+ {void Function(
+ _i2.WebView,
+ int,
+ )?
+ onProgressChanged}));
+ @override
+ _i2.WebViewClient Function({
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageFinished,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageStarted,
+ void Function(
+ _i2.WebView,
+ int,
+ String,
+ String,
+ )?
+ onReceivedError,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ _i2.WebResourceError,
+ )?
+ onReceivedRequestError,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ )?
+ requestLoading,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ urlLoading,
+ }) get createAndroidWebViewClient => (super.noSuchMethod(
+ Invocation.getter(#createAndroidWebViewClient),
+ returnValue: ({
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageFinished,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageStarted,
+ void Function(
+ _i2.WebView,
+ int,
+ String,
+ String,
+ )?
+ onReceivedError,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ _i2.WebResourceError,
+ )?
+ onReceivedRequestError,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ )?
+ requestLoading,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ urlLoading,
+ }) =>
+ _FakeWebViewClient_1(
+ this,
+ Invocation.getter(#createAndroidWebViewClient),
+ ),
+ returnValueForMissingStub: ({
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageFinished,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageStarted,
+ void Function(
+ _i2.WebView,
+ int,
+ String,
+ String,
+ )?
+ onReceivedError,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ _i2.WebResourceError,
+ )?
+ onReceivedRequestError,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ )?
+ requestLoading,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ urlLoading,
+ }) =>
+ _FakeWebViewClient_1(
+ this,
+ Invocation.getter(#createAndroidWebViewClient),
+ ),
+ ) as _i2.WebViewClient Function({
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageFinished,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageStarted,
+ void Function(
+ _i2.WebView,
+ int,
+ String,
+ String,
+ )?
+ onReceivedError,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ _i2.WebResourceError,
+ )?
+ onReceivedRequestError,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ )?
+ requestLoading,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ urlLoading,
+ }));
+ @override
+ _i2.FlutterAssetManager Function() get createFlutterAssetManager =>
+ (super.noSuchMethod(
+ Invocation.getter(#createFlutterAssetManager),
+ returnValue: () => _FakeFlutterAssetManager_8(
+ this,
+ Invocation.getter(#createFlutterAssetManager),
+ ),
+ returnValueForMissingStub: () => _FakeFlutterAssetManager_8(
+ this,
+ Invocation.getter(#createFlutterAssetManager),
+ ),
+ ) as _i2.FlutterAssetManager Function());
+ @override
+ _i2.JavaScriptChannel Function(
+ String, {
+ required void Function(String) postMessage,
+ }) get createJavaScriptChannel => (super.noSuchMethod(
+ Invocation.getter(#createJavaScriptChannel),
+ returnValue: (
+ String channelName, {
+ required void Function(String) postMessage,
+ }) =>
+ _FakeJavaScriptChannel_9(
+ this,
+ Invocation.getter(#createJavaScriptChannel),
+ ),
+ returnValueForMissingStub: (
+ String channelName, {
+ required void Function(String) postMessage,
+ }) =>
+ _FakeJavaScriptChannel_9(
+ this,
+ Invocation.getter(#createJavaScriptChannel),
+ ),
+ ) as _i2.JavaScriptChannel Function(
+ String, {
+ required void Function(String) postMessage,
+ }));
+ @override
+ _i2.DownloadListener Function(
+ {required void Function(
+ String,
+ String,
+ String,
+ String,
+ int,
+ )
+ onDownloadStart}) get createDownloadListener => (super.noSuchMethod(
+ Invocation.getter(#createDownloadListener),
+ returnValue: (
+ {required void Function(
+ String,
+ String,
+ String,
+ String,
+ int,
+ )
+ onDownloadStart}) =>
+ _FakeDownloadListener_2(
+ this,
+ Invocation.getter(#createDownloadListener),
+ ),
+ returnValueForMissingStub: (
+ {required void Function(
+ String,
+ String,
+ String,
+ String,
+ int,
+ )
+ onDownloadStart}) =>
+ _FakeDownloadListener_2(
+ this,
+ Invocation.getter(#createDownloadListener),
+ ),
+ ) as _i2.DownloadListener Function(
+ {required void Function(
+ String,
+ String,
+ String,
+ String,
+ int,
+ )
+ onDownloadStart}));
+ @override
+ _i7.Future<void> setWebContentsDebuggingEnabled(bool? enabled) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setWebContentsDebuggingEnabled,
+ [enabled],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+}
+
+/// A class which mocks [AndroidWebViewWidgetCreationParams].
+///
+/// See the documentation for Mockito's code generation for more information.
+// ignore: must_be_immutable
+class MockAndroidWebViewWidgetCreationParams extends _i1.Mock
+ implements _i8.AndroidWebViewWidgetCreationParams {
+ @override
+ _i5.InstanceManager get instanceManager => (super.noSuchMethod(
+ Invocation.getter(#instanceManager),
+ returnValue: _FakeInstanceManager_10(
+ this,
+ Invocation.getter(#instanceManager),
+ ),
+ returnValueForMissingStub: _FakeInstanceManager_10(
+ this,
+ Invocation.getter(#instanceManager),
+ ),
+ ) as _i5.InstanceManager);
+ @override
+ _i3.PlatformWebViewController get controller => (super.noSuchMethod(
+ Invocation.getter(#controller),
+ returnValue: _FakePlatformWebViewController_11(
+ this,
+ Invocation.getter(#controller),
+ ),
+ returnValueForMissingStub: _FakePlatformWebViewController_11(
+ this,
+ Invocation.getter(#controller),
+ ),
+ ) as _i3.PlatformWebViewController);
+ @override
+ _i4.TextDirection get layoutDirection => (super.noSuchMethod(
+ Invocation.getter(#layoutDirection),
+ returnValue: _i4.TextDirection.rtl,
+ returnValueForMissingStub: _i4.TextDirection.rtl,
+ ) as _i4.TextDirection);
+ @override
+ Set<_i10.Factory<_i11.OneSequenceGestureRecognizer>> get gestureRecognizers =>
+ (super.noSuchMethod(
+ Invocation.getter(#gestureRecognizers),
+ returnValue: <_i10.Factory<_i11.OneSequenceGestureRecognizer>>{},
+ returnValueForMissingStub: <
+ _i10.Factory<_i11.OneSequenceGestureRecognizer>>{},
+ ) as Set<_i10.Factory<_i11.OneSequenceGestureRecognizer>>);
+}
+
+/// A class which mocks [FlutterAssetManager].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockFlutterAssetManager extends _i1.Mock
+ implements _i2.FlutterAssetManager {
+ @override
+ _i7.Future<List<String?>> list(String? path) => (super.noSuchMethod(
+ Invocation.method(
+ #list,
+ [path],
+ ),
+ returnValue: _i7.Future<List<String?>>.value(<String?>[]),
+ returnValueForMissingStub: _i7.Future<List<String?>>.value(<String?>[]),
+ ) as _i7.Future<List<String?>>);
+ @override
+ _i7.Future<String> getAssetFilePathByName(String? name) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getAssetFilePathByName,
+ [name],
+ ),
+ returnValue: _i7.Future<String>.value(''),
+ returnValueForMissingStub: _i7.Future<String>.value(''),
+ ) as _i7.Future<String>);
+}
+
+/// A class which mocks [JavaScriptChannel].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockJavaScriptChannel extends _i1.Mock implements _i2.JavaScriptChannel {
+ @override
+ String get channelName => (super.noSuchMethod(
+ Invocation.getter(#channelName),
+ returnValue: '',
+ returnValueForMissingStub: '',
+ ) as String);
+ @override
+ void Function(String) get postMessage => (super.noSuchMethod(
+ Invocation.getter(#postMessage),
+ returnValue: (String message) {},
+ returnValueForMissingStub: (String message) {},
+ ) as void Function(String));
+ @override
+ _i2.JavaScriptChannel copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeJavaScriptChannel_9(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ returnValueForMissingStub: _FakeJavaScriptChannel_9(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.JavaScriptChannel);
+}
+
+/// A class which mocks [WebChromeClient].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebChromeClient extends _i1.Mock implements _i2.WebChromeClient {
+ @override
+ _i2.WebChromeClient copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebChromeClient_0(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ returnValueForMissingStub: _FakeWebChromeClient_0(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebChromeClient);
+}
+
+/// A class which mocks [WebSettings].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebSettings extends _i1.Mock implements _i2.WebSettings {
+ @override
+ _i7.Future<void> setDomStorageEnabled(bool? flag) => (super.noSuchMethod(
+ Invocation.method(
+ #setDomStorageEnabled,
+ [flag],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setJavaScriptCanOpenWindowsAutomatically(bool? flag) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setJavaScriptCanOpenWindowsAutomatically,
+ [flag],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setSupportMultipleWindows(bool? support) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setSupportMultipleWindows,
+ [support],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setJavaScriptEnabled(bool? flag) => (super.noSuchMethod(
+ Invocation.method(
+ #setJavaScriptEnabled,
+ [flag],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setUserAgentString(String? userAgentString) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setUserAgentString,
+ [userAgentString],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setMediaPlaybackRequiresUserGesture(bool? require) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setMediaPlaybackRequiresUserGesture,
+ [require],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setSupportZoom(bool? support) => (super.noSuchMethod(
+ Invocation.method(
+ #setSupportZoom,
+ [support],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setLoadWithOverviewMode(bool? overview) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setLoadWithOverviewMode,
+ [overview],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setUseWideViewPort(bool? use) => (super.noSuchMethod(
+ Invocation.method(
+ #setUseWideViewPort,
+ [use],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setDisplayZoomControls(bool? enabled) => (super.noSuchMethod(
+ Invocation.method(
+ #setDisplayZoomControls,
+ [enabled],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setBuiltInZoomControls(bool? enabled) => (super.noSuchMethod(
+ Invocation.method(
+ #setBuiltInZoomControls,
+ [enabled],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setAllowFileAccess(bool? enabled) => (super.noSuchMethod(
+ Invocation.method(
+ #setAllowFileAccess,
+ [enabled],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i2.WebSettings copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebSettings_12(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ returnValueForMissingStub: _FakeWebSettings_12(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebSettings);
+}
+
+/// A class which mocks [WebView].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebView extends _i1.Mock implements _i2.WebView {
+ @override
+ bool get useHybridComposition => (super.noSuchMethod(
+ Invocation.getter(#useHybridComposition),
+ returnValue: false,
+ returnValueForMissingStub: false,
+ ) as bool);
+ @override
+ _i2.WebSettings get settings => (super.noSuchMethod(
+ Invocation.getter(#settings),
+ returnValue: _FakeWebSettings_12(
+ this,
+ Invocation.getter(#settings),
+ ),
+ returnValueForMissingStub: _FakeWebSettings_12(
+ this,
+ Invocation.getter(#settings),
+ ),
+ ) as _i2.WebSettings);
+ @override
+ _i7.Future<void> loadData({
+ required String? data,
+ String? mimeType,
+ String? encoding,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #loadData,
+ [],
+ {
+ #data: data,
+ #mimeType: mimeType,
+ #encoding: encoding,
+ },
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> loadDataWithBaseUrl({
+ String? baseUrl,
+ required String? data,
+ String? mimeType,
+ String? encoding,
+ String? historyUrl,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #loadDataWithBaseUrl,
+ [],
+ {
+ #baseUrl: baseUrl,
+ #data: data,
+ #mimeType: mimeType,
+ #encoding: encoding,
+ #historyUrl: historyUrl,
+ },
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> loadUrl(
+ String? url,
+ Map<String, String>? headers,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #loadUrl,
+ [
+ url,
+ headers,
+ ],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> postUrl(
+ String? url,
+ _i12.Uint8List? data,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #postUrl,
+ [
+ url,
+ data,
+ ],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<String?> getUrl() => (super.noSuchMethod(
+ Invocation.method(
+ #getUrl,
+ [],
+ ),
+ returnValue: _i7.Future<String?>.value(),
+ returnValueForMissingStub: _i7.Future<String?>.value(),
+ ) as _i7.Future<String?>);
+ @override
+ _i7.Future<bool> canGoBack() => (super.noSuchMethod(
+ Invocation.method(
+ #canGoBack,
+ [],
+ ),
+ returnValue: _i7.Future<bool>.value(false),
+ returnValueForMissingStub: _i7.Future<bool>.value(false),
+ ) as _i7.Future<bool>);
+ @override
+ _i7.Future<bool> canGoForward() => (super.noSuchMethod(
+ Invocation.method(
+ #canGoForward,
+ [],
+ ),
+ returnValue: _i7.Future<bool>.value(false),
+ returnValueForMissingStub: _i7.Future<bool>.value(false),
+ ) as _i7.Future<bool>);
+ @override
+ _i7.Future<void> goBack() => (super.noSuchMethod(
+ Invocation.method(
+ #goBack,
+ [],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> goForward() => (super.noSuchMethod(
+ Invocation.method(
+ #goForward,
+ [],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> reload() => (super.noSuchMethod(
+ Invocation.method(
+ #reload,
+ [],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> clearCache(bool? includeDiskFiles) => (super.noSuchMethod(
+ Invocation.method(
+ #clearCache,
+ [includeDiskFiles],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<String?> evaluateJavascript(String? javascriptString) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #evaluateJavascript,
+ [javascriptString],
+ ),
+ returnValue: _i7.Future<String?>.value(),
+ returnValueForMissingStub: _i7.Future<String?>.value(),
+ ) as _i7.Future<String?>);
+ @override
+ _i7.Future<String?> getTitle() => (super.noSuchMethod(
+ Invocation.method(
+ #getTitle,
+ [],
+ ),
+ returnValue: _i7.Future<String?>.value(),
+ returnValueForMissingStub: _i7.Future<String?>.value(),
+ ) as _i7.Future<String?>);
+ @override
+ _i7.Future<void> scrollTo(
+ int? x,
+ int? y,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #scrollTo,
+ [
+ x,
+ y,
+ ],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> scrollBy(
+ int? x,
+ int? y,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #scrollBy,
+ [
+ x,
+ y,
+ ],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<int> getScrollX() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollX,
+ [],
+ ),
+ returnValue: _i7.Future<int>.value(0),
+ returnValueForMissingStub: _i7.Future<int>.value(0),
+ ) as _i7.Future<int>);
+ @override
+ _i7.Future<int> getScrollY() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollY,
+ [],
+ ),
+ returnValue: _i7.Future<int>.value(0),
+ returnValueForMissingStub: _i7.Future<int>.value(0),
+ ) as _i7.Future<int>);
+ @override
+ _i7.Future<_i4.Offset> getScrollPosition() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ returnValue: _i7.Future<_i4.Offset>.value(_FakeOffset_6(
+ this,
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ )),
+ returnValueForMissingStub: _i7.Future<_i4.Offset>.value(_FakeOffset_6(
+ this,
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ )),
+ ) as _i7.Future<_i4.Offset>);
+ @override
+ _i7.Future<void> setWebViewClient(_i2.WebViewClient? webViewClient) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setWebViewClient,
+ [webViewClient],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> addJavaScriptChannel(
+ _i2.JavaScriptChannel? javaScriptChannel) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #addJavaScriptChannel,
+ [javaScriptChannel],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> removeJavaScriptChannel(
+ _i2.JavaScriptChannel? javaScriptChannel) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #removeJavaScriptChannel,
+ [javaScriptChannel],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setDownloadListener(_i2.DownloadListener? listener) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setDownloadListener,
+ [listener],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setWebChromeClient(_i2.WebChromeClient? client) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setWebChromeClient,
+ [client],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i7.Future<void> setBackgroundColor(_i4.Color? color) => (super.noSuchMethod(
+ Invocation.method(
+ #setBackgroundColor,
+ [color],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i2.WebView copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebView_7(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ returnValueForMissingStub: _FakeWebView_7(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebView);
+}
+
+/// A class which mocks [WebViewClient].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewClient extends _i1.Mock implements _i2.WebViewClient {
+ @override
+ _i7.Future<void> setSynchronousReturnValueForShouldOverrideUrlLoading(
+ bool? value) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setSynchronousReturnValueForShouldOverrideUrlLoading,
+ [value],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i2.WebViewClient copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebViewClient_1(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ returnValueForMissingStub: _FakeWebViewClient_1(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebViewClient);
+}
+
+/// A class which mocks [WebStorage].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebStorage extends _i1.Mock implements _i2.WebStorage {
+ @override
+ _i7.Future<void> deleteAllData() => (super.noSuchMethod(
+ Invocation.method(
+ #deleteAllData,
+ [],
+ ),
+ returnValue: _i7.Future<void>.value(),
+ returnValueForMissingStub: _i7.Future<void>.value(),
+ ) as _i7.Future<void>);
+ @override
+ _i2.WebStorage copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebStorage_13(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ returnValueForMissingStub: _FakeWebStorage_13(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebStorage);
+}
+
+/// A class which mocks [InstanceManager].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockInstanceManager extends _i1.Mock implements _i5.InstanceManager {
+ @override
+ void Function(int) get onWeakReferenceRemoved => (super.noSuchMethod(
+ Invocation.getter(#onWeakReferenceRemoved),
+ returnValue: (int __p0) {},
+ returnValueForMissingStub: (int __p0) {},
+ ) as void Function(int));
+ @override
+ set onWeakReferenceRemoved(void Function(int)? _onWeakReferenceRemoved) =>
+ super.noSuchMethod(
+ Invocation.setter(
+ #onWeakReferenceRemoved,
+ _onWeakReferenceRemoved,
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ int addDartCreatedInstance(_i5.Copyable? instance) => (super.noSuchMethod(
+ Invocation.method(
+ #addDartCreatedInstance,
+ [instance],
+ ),
+ returnValue: 0,
+ returnValueForMissingStub: 0,
+ ) as int);
+ @override
+ int? removeWeakReference(_i5.Copyable? instance) => (super.noSuchMethod(
+ Invocation.method(
+ #removeWeakReference,
+ [instance],
+ ),
+ returnValueForMissingStub: null,
+ ) as int?);
+ @override
+ T? remove<T extends _i5.Copyable>(int? identifier) => (super.noSuchMethod(
+ Invocation.method(
+ #remove,
+ [identifier],
+ ),
+ returnValueForMissingStub: null,
+ ) as T?);
+ @override
+ T? getInstanceWithWeakReference<T extends _i5.Copyable>(int? identifier) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getInstanceWithWeakReference,
+ [identifier],
+ ),
+ returnValueForMissingStub: null,
+ ) as T?);
+ @override
+ int? getIdentifier(_i5.Copyable? instance) => (super.noSuchMethod(
+ Invocation.method(
+ #getIdentifier,
+ [instance],
+ ),
+ returnValueForMissingStub: null,
+ ) as int?);
+ @override
+ void addHostCreatedInstance(
+ _i5.Copyable? instance,
+ int? identifier,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #addHostCreatedInstance,
+ [
+ instance,
+ identifier,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ bool containsIdentifier(int? identifier) => (super.noSuchMethod(
+ Invocation.method(
+ #containsIdentifier,
+ [identifier],
+ ),
+ returnValue: false,
+ returnValueForMissingStub: false,
+ ) as bool);
+}
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.dart
new file mode 100644
index 0000000..9e7422f
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.dart
@@ -0,0 +1,79 @@
+// 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.
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'package:webview_flutter_android/src/android_webview.dart'
+ as android_webview;
+import 'package:webview_flutter_android/webview_flutter_android.dart';
+import 'package:webview_flutter_platform_interface/src/webview_platform.dart';
+
+import 'android_webview_cookie_manager_test.mocks.dart';
+
+@GenerateMocks(<Type>[android_webview.CookieManager])
+void main() {
+ TestWidgetsFlutterBinding.ensureInitialized();
+
+ test('clearCookies should call android_webview.clearCookies', () async {
+ final android_webview.CookieManager mockCookieManager = MockCookieManager();
+
+ when(mockCookieManager.clearCookies())
+ .thenAnswer((_) => Future<bool>.value(true));
+
+ final AndroidWebViewCookieManagerCreationParams params =
+ AndroidWebViewCookieManagerCreationParams
+ .fromPlatformWebViewCookieManagerCreationParams(
+ const PlatformWebViewCookieManagerCreationParams());
+
+ final bool hasClearedCookies = await AndroidWebViewCookieManager(params,
+ cookieManager: mockCookieManager)
+ .clearCookies();
+
+ expect(hasClearedCookies, true);
+ verify(mockCookieManager.clearCookies());
+ });
+
+ test('setCookie should throw ArgumentError for cookie with invalid path', () {
+ final AndroidWebViewCookieManagerCreationParams params =
+ AndroidWebViewCookieManagerCreationParams
+ .fromPlatformWebViewCookieManagerCreationParams(
+ const PlatformWebViewCookieManagerCreationParams());
+
+ final AndroidWebViewCookieManager androidCookieManager =
+ AndroidWebViewCookieManager(params, cookieManager: MockCookieManager());
+
+ expect(
+ () => androidCookieManager.setCookie(const WebViewCookie(
+ name: 'foo',
+ value: 'bar',
+ domain: 'flutter.dev',
+ path: 'invalid;path',
+ )),
+ throwsA(const TypeMatcher<ArgumentError>()),
+ );
+ });
+
+ test(
+ 'setCookie should call android_webview.csetCookie with properly formatted cookie value',
+ () {
+ final android_webview.CookieManager mockCookieManager = MockCookieManager();
+ final AndroidWebViewCookieManagerCreationParams params =
+ AndroidWebViewCookieManagerCreationParams
+ .fromPlatformWebViewCookieManagerCreationParams(
+ const PlatformWebViewCookieManagerCreationParams());
+
+ AndroidWebViewCookieManager(params, cookieManager: mockCookieManager)
+ .setCookie(const WebViewCookie(
+ name: 'foo&',
+ value: 'bar@',
+ domain: 'flutter.dev',
+ ));
+
+ verify(mockCookieManager.setCookie(
+ 'flutter.dev',
+ 'foo%26=bar%40; path=/',
+ ));
+ });
+}
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart
new file mode 100644
index 0000000..0732180
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_cookie_manager_test.mocks.dart
@@ -0,0 +1,54 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_android/test/android_webview_cookie_manager_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i3;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_android/src/android_webview.dart' as _i2;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+/// A class which mocks [CookieManager].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockCookieManager extends _i1.Mock implements _i2.CookieManager {
+ MockCookieManager() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i3.Future<void> setCookie(
+ String? url,
+ String? value,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setCookie,
+ [
+ url,
+ value,
+ ],
+ ),
+ returnValue: _i3.Future<void>.value(),
+ returnValueForMissingStub: _i3.Future<void>.value(),
+ ) as _i3.Future<void>);
+ @override
+ _i3.Future<bool> clearCookies() => (super.noSuchMethod(
+ Invocation.method(
+ #clearCookies,
+ [],
+ ),
+ returnValue: _i3.Future<bool>.value(false),
+ ) as _i3.Future<bool>);
+}
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart
index f3ec4bd..4e972fe 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.dart
@@ -269,7 +269,7 @@
final WebViewClient mockWebViewClient = MockWebViewClient();
when(mockWebViewClient.copy()).thenReturn(MockWebViewClient());
- when(mockWebViewClient.shouldOverrideUrlLoading).thenReturn(false);
+ instanceManager.addDartCreatedInstance(mockWebViewClient);
webView.setWebViewClient(mockWebViewClient);
final int webViewClientInstanceId =
@@ -334,6 +334,7 @@
final DownloadListener mockDownloadListener = MockDownloadListener();
when(mockDownloadListener.copy()).thenReturn(MockDownloadListener());
+ instanceManager.addDartCreatedInstance(mockDownloadListener);
webView.setDownloadListener(mockDownloadListener);
final int downloadListenerInstanceId =
@@ -345,16 +346,6 @@
});
test('setWebChromeClient', () {
- // Setting a WebChromeClient requires setting a WebViewClient first.
- TestWebViewClientHostApi.setup(MockTestWebViewClientHostApi());
- WebViewClient.api = WebViewClientHostApiImpl(
- instanceManager: instanceManager,
- );
- final WebViewClient mockWebViewClient = MockWebViewClient();
- when(mockWebViewClient.copy()).thenReturn(MockWebViewClient());
- when(mockWebViewClient.shouldOverrideUrlLoading).thenReturn(false);
- webView.setWebViewClient(mockWebViewClient);
-
TestWebChromeClientHostApi.setup(MockTestWebChromeClientHostApi());
WebChromeClient.api = WebChromeClientHostApiImpl(
instanceManager: instanceManager,
@@ -362,6 +353,7 @@
final WebChromeClient mockWebChromeClient = MockWebChromeClient();
when(mockWebChromeClient.copy()).thenReturn(MockWebChromeClient());
+ instanceManager.addDartCreatedInstance(mockWebChromeClient);
webView.setWebChromeClient(mockWebChromeClient);
final int webChromeClientInstanceId =
@@ -372,21 +364,6 @@
));
});
- test('release', () {
- final MockTestWebSettingsHostApi mockWebSettingsPlatformHostApi =
- MockTestWebSettingsHostApi();
- TestWebSettingsHostApi.setup(mockWebSettingsPlatformHostApi);
-
- WebSettings.api =
- WebSettingsHostApiImpl(instanceManager: instanceManager);
- final int webSettingsInstanceId =
- instanceManager.getIdentifier(webView.settings)!;
-
- webView.release();
- verify(mockWebSettingsPlatformHostApi.dispose(webSettingsInstanceId));
- verify(mockPlatformHostApi.dispose(webViewInstanceId));
- });
-
test('copy', () {
expect(webView.copy(), isA<WebView>());
});
@@ -544,16 +521,22 @@
});
test('postMessage', () {
+ late final String result;
+ when(mockJavaScriptChannel.postMessage).thenReturn((String message) {
+ result = message;
+ });
+
flutterApi.postMessage(
mockJavaScriptChannelInstanceId,
'Hello, World!',
);
- verify(mockJavaScriptChannel.postMessage('Hello, World!'));
+
+ expect(result, 'Hello, World!');
});
test('copy', () {
expect(
- JavaScriptChannel.detached('channel').copy(),
+ JavaScriptChannel.detached('channel', postMessage: (_) {}).copy(),
isA<JavaScriptChannel>(),
);
});
@@ -588,30 +571,51 @@
});
test('onPageStarted', () {
+ late final List<Object> result;
+ when(mockWebViewClient.onPageStarted).thenReturn(
+ (WebView webView, String url) {
+ result = <Object>[webView, url];
+ },
+ );
+
flutterApi.onPageStarted(
mockWebViewClientInstanceId,
mockWebViewInstanceId,
'https://www.google.com',
);
- verify(mockWebViewClient.onPageStarted(
- mockWebView,
- 'https://www.google.com',
- ));
+
+ expect(result, <Object>[mockWebView, 'https://www.google.com']);
});
test('onPageFinished', () {
+ late final List<Object> result;
+ when(mockWebViewClient.onPageFinished).thenReturn(
+ (WebView webView, String url) {
+ result = <Object>[webView, url];
+ },
+ );
+
flutterApi.onPageFinished(
mockWebViewClientInstanceId,
mockWebViewInstanceId,
'https://www.google.com',
);
- verify(mockWebViewClient.onPageFinished(
- mockWebView,
- 'https://www.google.com',
- ));
+
+ expect(result, <Object>[mockWebView, 'https://www.google.com']);
});
test('onReceivedRequestError', () {
+ late final List<Object> result;
+ when(mockWebViewClient.onReceivedRequestError).thenReturn(
+ (
+ WebView webView,
+ WebResourceRequest request,
+ WebResourceError error,
+ ) {
+ result = <Object>[webView, request, error];
+ },
+ );
+
flutterApi.onReceivedRequestError(
mockWebViewClientInstanceId,
mockWebViewInstanceId,
@@ -626,14 +630,25 @@
WebResourceErrorData(errorCode: 34, description: 'error description'),
);
- verify(mockWebViewClient.onReceivedRequestError(
- mockWebView,
- argThat(isNotNull),
- argThat(isNotNull),
- ));
+ expect(
+ result,
+ containsAllInOrder(<Object?>[mockWebView, isNotNull, isNotNull]),
+ );
});
test('onReceivedError', () {
+ late final List<Object> result;
+ when(mockWebViewClient.onReceivedError).thenReturn(
+ (
+ WebView webView,
+ int errorCode,
+ String description,
+ String failingUrl,
+ ) {
+ result = <Object>[webView, errorCode, description, failingUrl];
+ },
+ );
+
flutterApi.onReceivedError(
mockWebViewClientInstanceId,
mockWebViewInstanceId,
@@ -642,15 +657,22 @@
'https://www.google.com',
);
- verify(mockWebViewClient.onReceivedError(
- mockWebView,
- 14,
- 'desc',
- 'https://www.google.com',
- ));
+ expect(
+ result,
+ containsAllInOrder(
+ <Object?>[mockWebView, 14, 'desc', 'https://www.google.com'],
+ ),
+ );
});
test('requestLoading', () {
+ late final List<Object> result;
+ when(mockWebViewClient.requestLoading).thenReturn(
+ (WebView webView, WebResourceRequest request) {
+ result = <Object>[webView, request];
+ },
+ );
+
flutterApi.requestLoading(
mockWebViewClientInstanceId,
mockWebViewInstanceId,
@@ -664,20 +686,27 @@
),
);
- verify(mockWebViewClient.requestLoading(
- mockWebView,
- argThat(isNotNull),
- ));
+ expect(
+ result,
+ containsAllInOrder(<Object?>[mockWebView, isNotNull]),
+ );
});
test('urlLoading', () {
+ late final List<Object> result;
+ when(mockWebViewClient.urlLoading).thenReturn(
+ (WebView webView, String url) {
+ result = <Object>[webView, url];
+ },
+ );
+
flutterApi.urlLoading(mockWebViewClientInstanceId,
mockWebViewInstanceId, 'https://www.google.com');
- verify(mockWebViewClient.urlLoading(
- mockWebView,
- 'https://www.google.com',
- ));
+ expect(
+ result,
+ containsAllInOrder(<Object?>[mockWebView, 'https://www.google.com']),
+ );
});
test('copy', () {
@@ -705,7 +734,26 @@
instanceManager.addDartCreatedInstance(mockDownloadListener);
});
- test('onPageStarted', () {
+ test('onDownloadStart', () {
+ late final List<Object> result;
+ when(mockDownloadListener.onDownloadStart).thenReturn(
+ (
+ String url,
+ String userAgent,
+ String contentDisposition,
+ String mimetype,
+ int contentLength,
+ ) {
+ result = <Object>[
+ url,
+ userAgent,
+ contentDisposition,
+ mimetype,
+ contentLength,
+ ];
+ },
+ );
+
flutterApi.onDownloadStart(
mockDownloadListenerInstanceId,
'url',
@@ -714,17 +762,26 @@
'mimetype',
45,
);
- verify(mockDownloadListener.onDownloadStart(
- 'url',
- 'userAgent',
- 'contentDescription',
- 'mimetype',
- 45,
- ));
+
+ expect(
+ result,
+ containsAllInOrder(<Object?>[
+ 'url',
+ 'userAgent',
+ 'contentDescription',
+ 'mimetype',
+ 45,
+ ]),
+ );
});
test('copy', () {
- expect(DownloadListener.detached().copy(), isA<DownloadListener>());
+ expect(
+ DownloadListener.detached(
+ onDownloadStart: (_, __, ____, _____, ______) {},
+ ).copy(),
+ isA<DownloadListener>(),
+ );
});
});
@@ -757,13 +814,21 @@
instanceManager.addDartCreatedInstance(mockWebView);
});
- test('onPageStarted', () {
+ test('onProgressChanged', () {
+ late final List<Object> result;
+ when(mockWebChromeClient.onProgressChanged).thenReturn(
+ (WebView webView, int progress) {
+ result = <Object>[webView, progress];
+ },
+ );
+
flutterApi.onProgressChanged(
mockWebChromeClientInstanceId,
mockWebViewInstanceId,
76,
);
- verify(mockWebChromeClient.onProgressChanged(mockWebView, 76));
+
+ expect(result, containsAllInOrder(<Object?>[mockWebView, 76]));
});
test('copy', () {
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart
index 116ac83..81cdc9e 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview_test.mocks.dart
@@ -1,7 +1,8 @@
-// Mocks generated by Mockito 5.2.0 from annotations
+// Mocks generated by Mockito 5.3.2 from annotations
// in webview_flutter_android/test/android_webview_test.dart.
// Do not manually edit this file.
+// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i5;
import 'dart:typed_data' as _i7;
import 'dart:ui' as _i4;
@@ -21,24 +22,90 @@
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
-class _FakeDownloadListener_0 extends _i1.Fake
- implements _i2.DownloadListener {}
+class _FakeDownloadListener_0 extends _i1.SmartFake
+ implements _i2.DownloadListener {
+ _FakeDownloadListener_0(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
-class _FakeJavaScriptChannel_1 extends _i1.Fake
- implements _i2.JavaScriptChannel {}
+class _FakeJavaScriptChannel_1 extends _i1.SmartFake
+ implements _i2.JavaScriptChannel {
+ _FakeJavaScriptChannel_1(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
-class _FakeWebViewPoint_2 extends _i1.Fake implements _i3.WebViewPoint {}
+class _FakeWebViewPoint_2 extends _i1.SmartFake implements _i3.WebViewPoint {
+ _FakeWebViewPoint_2(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
-class _FakeWebChromeClient_3 extends _i1.Fake implements _i2.WebChromeClient {}
+class _FakeWebChromeClient_3 extends _i1.SmartFake
+ implements _i2.WebChromeClient {
+ _FakeWebChromeClient_3(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
-class _FakeWebSettings_4 extends _i1.Fake implements _i2.WebSettings {}
+class _FakeWebSettings_4 extends _i1.SmartFake implements _i2.WebSettings {
+ _FakeWebSettings_4(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
-class _FakeOffset_5 extends _i1.Fake implements _i4.Offset {}
+class _FakeOffset_5 extends _i1.SmartFake implements _i4.Offset {
+ _FakeOffset_5(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
-class _FakeWebView_6 extends _i1.Fake implements _i2.WebView {}
+class _FakeWebView_6 extends _i1.SmartFake implements _i2.WebView {
+ _FakeWebView_6(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
-class _FakeWebViewClient_7 extends _i1.Fake implements _i2.WebViewClient {}
+class _FakeWebViewClient_7 extends _i1.SmartFake implements _i2.WebViewClient {
+ _FakeWebViewClient_7(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
/// A class which mocks [CookieManagerHostApi].
///
@@ -50,14 +117,29 @@
}
@override
- _i5.Future<bool> clearCookies() =>
- (super.noSuchMethod(Invocation.method(#clearCookies, []),
- returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
+ _i5.Future<bool> clearCookies() => (super.noSuchMethod(
+ Invocation.method(
+ #clearCookies,
+ [],
+ ),
+ returnValue: _i5.Future<bool>.value(false),
+ ) as _i5.Future<bool>);
@override
- _i5.Future<void> setCookie(String? arg_url, String? arg_value) =>
- (super.noSuchMethod(Invocation.method(#setCookie, [arg_url, arg_value]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> setCookie(
+ String? arg_url,
+ String? arg_value,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setCookie,
+ [
+ arg_url,
+ arg_value,
+ ],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
}
/// A class which mocks [DownloadListener].
@@ -69,16 +151,42 @@
}
@override
- void onDownloadStart(String? url, String? userAgent,
- String? contentDisposition, String? mimetype, int? contentLength) =>
- super.noSuchMethod(
- Invocation.method(#onDownloadStart,
- [url, userAgent, contentDisposition, mimetype, contentLength]),
- returnValueForMissingStub: null);
+ void Function(
+ String,
+ String,
+ String,
+ String,
+ int,
+ ) get onDownloadStart => (super.noSuchMethod(
+ Invocation.getter(#onDownloadStart),
+ returnValue: (
+ String url,
+ String userAgent,
+ String contentDisposition,
+ String mimetype,
+ int contentLength,
+ ) {},
+ ) as void Function(
+ String,
+ String,
+ String,
+ String,
+ int,
+ ));
@override
- _i2.DownloadListener copy() =>
- (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeDownloadListener_0()) as _i2.DownloadListener);
+ _i2.DownloadListener copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeDownloadListener_0(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.DownloadListener);
}
/// A class which mocks [JavaScriptChannel].
@@ -90,17 +198,29 @@
}
@override
- String get channelName =>
- (super.noSuchMethod(Invocation.getter(#channelName), returnValue: '')
- as String);
+ String get channelName => (super.noSuchMethod(
+ Invocation.getter(#channelName),
+ returnValue: '',
+ ) as String);
@override
- void postMessage(String? message) =>
- super.noSuchMethod(Invocation.method(#postMessage, [message]),
- returnValueForMissingStub: null);
+ void Function(String) get postMessage => (super.noSuchMethod(
+ Invocation.getter(#postMessage),
+ returnValue: (String message) {},
+ ) as void Function(String));
@override
- _i2.JavaScriptChannel copy() =>
- (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeJavaScriptChannel_1()) as _i2.JavaScriptChannel);
+ _i2.JavaScriptChannel copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeJavaScriptChannel_1(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.JavaScriptChannel);
}
/// A class which mocks [TestDownloadListenerHostApi].
@@ -113,9 +233,13 @@
}
@override
- void create(int? instanceId) =>
- super.noSuchMethod(Invocation.method(#create, [instanceId]),
- returnValueForMissingStub: null);
+ void create(int? instanceId) => super.noSuchMethod(
+ Invocation.method(
+ #create,
+ [instanceId],
+ ),
+ returnValueForMissingStub: null,
+ );
}
/// A class which mocks [TestJavaObjectHostApi].
@@ -128,9 +252,13 @@
}
@override
- void dispose(int? identifier) =>
- super.noSuchMethod(Invocation.method(#dispose, [identifier]),
- returnValueForMissingStub: null);
+ void dispose(int? identifier) => super.noSuchMethod(
+ Invocation.method(
+ #dispose,
+ [identifier],
+ ),
+ returnValueForMissingStub: null,
+ );
}
/// A class which mocks [TestJavaScriptChannelHostApi].
@@ -143,9 +271,20 @@
}
@override
- void create(int? instanceId, String? channelName) =>
- super.noSuchMethod(Invocation.method(#create, [instanceId, channelName]),
- returnValueForMissingStub: null);
+ void create(
+ int? instanceId,
+ String? channelName,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #create,
+ [
+ instanceId,
+ channelName,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
}
/// A class which mocks [TestWebChromeClientHostApi].
@@ -158,10 +297,13 @@
}
@override
- void create(int? instanceId, int? webViewClientInstanceId) =>
- super.noSuchMethod(
- Invocation.method(#create, [instanceId, webViewClientInstanceId]),
- returnValueForMissingStub: null);
+ void create(int? instanceId) => super.noSuchMethod(
+ Invocation.method(
+ #create,
+ [instanceId],
+ ),
+ returnValueForMissingStub: null,
+ );
}
/// A class which mocks [TestWebSettingsHostApi].
@@ -174,70 +316,200 @@
}
@override
- void create(int? instanceId, int? webViewInstanceId) => super.noSuchMethod(
- Invocation.method(#create, [instanceId, webViewInstanceId]),
- returnValueForMissingStub: null);
- @override
- void dispose(int? instanceId) =>
- super.noSuchMethod(Invocation.method(#dispose, [instanceId]),
- returnValueForMissingStub: null);
- @override
- void setDomStorageEnabled(int? instanceId, bool? flag) => super.noSuchMethod(
- Invocation.method(#setDomStorageEnabled, [instanceId, flag]),
- returnValueForMissingStub: null);
- @override
- void setJavaScriptCanOpenWindowsAutomatically(int? instanceId, bool? flag) =>
+ void create(
+ int? instanceId,
+ int? webViewInstanceId,
+ ) =>
super.noSuchMethod(
- Invocation.method(
- #setJavaScriptCanOpenWindowsAutomatically, [instanceId, flag]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #create,
+ [
+ instanceId,
+ webViewInstanceId,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setSupportMultipleWindows(int? instanceId, bool? support) =>
+ void setDomStorageEnabled(
+ int? instanceId,
+ bool? flag,
+ ) =>
super.noSuchMethod(
- Invocation.method(#setSupportMultipleWindows, [instanceId, support]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setDomStorageEnabled,
+ [
+ instanceId,
+ flag,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setJavaScriptEnabled(int? instanceId, bool? flag) => super.noSuchMethod(
- Invocation.method(#setJavaScriptEnabled, [instanceId, flag]),
- returnValueForMissingStub: null);
- @override
- void setUserAgentString(int? instanceId, String? userAgentString) =>
+ void setJavaScriptCanOpenWindowsAutomatically(
+ int? instanceId,
+ bool? flag,
+ ) =>
super.noSuchMethod(
- Invocation.method(#setUserAgentString, [instanceId, userAgentString]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setJavaScriptCanOpenWindowsAutomatically,
+ [
+ instanceId,
+ flag,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setMediaPlaybackRequiresUserGesture(int? instanceId, bool? require) =>
+ void setSupportMultipleWindows(
+ int? instanceId,
+ bool? support,
+ ) =>
super.noSuchMethod(
- Invocation.method(
- #setMediaPlaybackRequiresUserGesture, [instanceId, require]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setSupportMultipleWindows,
+ [
+ instanceId,
+ support,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setSupportZoom(int? instanceId, bool? support) => super.noSuchMethod(
- Invocation.method(#setSupportZoom, [instanceId, support]),
- returnValueForMissingStub: null);
- @override
- void setLoadWithOverviewMode(int? instanceId, bool? overview) =>
+ void setJavaScriptEnabled(
+ int? instanceId,
+ bool? flag,
+ ) =>
super.noSuchMethod(
- Invocation.method(#setLoadWithOverviewMode, [instanceId, overview]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setJavaScriptEnabled,
+ [
+ instanceId,
+ flag,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setUseWideViewPort(int? instanceId, bool? use) => super.noSuchMethod(
- Invocation.method(#setUseWideViewPort, [instanceId, use]),
- returnValueForMissingStub: null);
- @override
- void setDisplayZoomControls(int? instanceId, bool? enabled) =>
+ void setUserAgentString(
+ int? instanceId,
+ String? userAgentString,
+ ) =>
super.noSuchMethod(
- Invocation.method(#setDisplayZoomControls, [instanceId, enabled]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setUserAgentString,
+ [
+ instanceId,
+ userAgentString,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setBuiltInZoomControls(int? instanceId, bool? enabled) =>
+ void setMediaPlaybackRequiresUserGesture(
+ int? instanceId,
+ bool? require,
+ ) =>
super.noSuchMethod(
- Invocation.method(#setBuiltInZoomControls, [instanceId, enabled]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setMediaPlaybackRequiresUserGesture,
+ [
+ instanceId,
+ require,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setAllowFileAccess(int? instanceId, bool? enabled) => super.noSuchMethod(
- Invocation.method(#setAllowFileAccess, [instanceId, enabled]),
- returnValueForMissingStub: null);
+ void setSupportZoom(
+ int? instanceId,
+ bool? support,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #setSupportZoom,
+ [
+ instanceId,
+ support,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void setLoadWithOverviewMode(
+ int? instanceId,
+ bool? overview,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #setLoadWithOverviewMode,
+ [
+ instanceId,
+ overview,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void setUseWideViewPort(
+ int? instanceId,
+ bool? use,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #setUseWideViewPort,
+ [
+ instanceId,
+ use,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void setDisplayZoomControls(
+ int? instanceId,
+ bool? enabled,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #setDisplayZoomControls,
+ [
+ instanceId,
+ enabled,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void setBuiltInZoomControls(
+ int? instanceId,
+ bool? enabled,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #setBuiltInZoomControls,
+ [
+ instanceId,
+ enabled,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void setAllowFileAccess(
+ int? instanceId,
+ bool? enabled,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #setAllowFileAccess,
+ [
+ instanceId,
+ enabled,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
}
/// A class which mocks [TestWebStorageHostApi].
@@ -250,13 +522,21 @@
}
@override
- void create(int? instanceId) =>
- super.noSuchMethod(Invocation.method(#create, [instanceId]),
- returnValueForMissingStub: null);
+ void create(int? instanceId) => super.noSuchMethod(
+ Invocation.method(
+ #create,
+ [instanceId],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void deleteAllData(int? instanceId) =>
- super.noSuchMethod(Invocation.method(#deleteAllData, [instanceId]),
- returnValueForMissingStub: null);
+ void deleteAllData(int? instanceId) => super.noSuchMethod(
+ Invocation.method(
+ #deleteAllData,
+ [instanceId],
+ ),
+ returnValueForMissingStub: null,
+ );
}
/// A class which mocks [TestWebViewClientHostApi].
@@ -269,10 +549,28 @@
}
@override
- void create(int? instanceId, bool? shouldOverrideUrlLoading) =>
+ void create(int? instanceId) => super.noSuchMethod(
+ Invocation.method(
+ #create,
+ [instanceId],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void setSynchronousReturnValueForShouldOverrideUrlLoading(
+ int? instanceId,
+ bool? value,
+ ) =>
super.noSuchMethod(
- Invocation.method(#create, [instanceId, shouldOverrideUrlLoading]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setSynchronousReturnValueForShouldOverrideUrlLoading,
+ [
+ instanceId,
+ value,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
}
/// A class which mocks [TestWebViewHostApi].
@@ -285,135 +583,338 @@
}
@override
- void create(int? instanceId, bool? useHybridComposition) =>
+ void create(
+ int? instanceId,
+ bool? useHybridComposition,
+ ) =>
super.noSuchMethod(
- Invocation.method(#create, [instanceId, useHybridComposition]),
- returnValueForMissingStub: null);
- @override
- void dispose(int? instanceId) =>
- super.noSuchMethod(Invocation.method(#dispose, [instanceId]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #create,
+ [
+ instanceId,
+ useHybridComposition,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
void loadData(
- int? instanceId, String? data, String? mimeType, String? encoding) =>
+ int? instanceId,
+ String? data,
+ String? mimeType,
+ String? encoding,
+ ) =>
super.noSuchMethod(
- Invocation.method(#loadData, [instanceId, data, mimeType, encoding]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #loadData,
+ [
+ instanceId,
+ data,
+ mimeType,
+ encoding,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void loadDataWithBaseUrl(int? instanceId, String? baseUrl, String? data,
- String? mimeType, String? encoding, String? historyUrl) =>
+ void loadDataWithBaseUrl(
+ int? instanceId,
+ String? baseUrl,
+ String? data,
+ String? mimeType,
+ String? encoding,
+ String? historyUrl,
+ ) =>
super.noSuchMethod(
- Invocation.method(#loadDataWithBaseUrl,
- [instanceId, baseUrl, data, mimeType, encoding, historyUrl]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #loadDataWithBaseUrl,
+ [
+ instanceId,
+ baseUrl,
+ data,
+ mimeType,
+ encoding,
+ historyUrl,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void loadUrl(int? instanceId, String? url, Map<String?, String?>? headers) =>
+ void loadUrl(
+ int? instanceId,
+ String? url,
+ Map<String?, String?>? headers,
+ ) =>
super.noSuchMethod(
- Invocation.method(#loadUrl, [instanceId, url, headers]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #loadUrl,
+ [
+ instanceId,
+ url,
+ headers,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void postUrl(int? instanceId, String? url, _i7.Uint8List? data) =>
- super.noSuchMethod(Invocation.method(#postUrl, [instanceId, url, data]),
- returnValueForMissingStub: null);
- @override
- String? getUrl(int? instanceId) =>
- (super.noSuchMethod(Invocation.method(#getUrl, [instanceId])) as String?);
- @override
- bool canGoBack(int? instanceId) =>
- (super.noSuchMethod(Invocation.method(#canGoBack, [instanceId]),
- returnValue: false) as bool);
- @override
- bool canGoForward(int? instanceId) =>
- (super.noSuchMethod(Invocation.method(#canGoForward, [instanceId]),
- returnValue: false) as bool);
- @override
- void goBack(int? instanceId) =>
- super.noSuchMethod(Invocation.method(#goBack, [instanceId]),
- returnValueForMissingStub: null);
- @override
- void goForward(int? instanceId) =>
- super.noSuchMethod(Invocation.method(#goForward, [instanceId]),
- returnValueForMissingStub: null);
- @override
- void reload(int? instanceId) =>
- super.noSuchMethod(Invocation.method(#reload, [instanceId]),
- returnValueForMissingStub: null);
- @override
- void clearCache(int? instanceId, bool? includeDiskFiles) =>
+ void postUrl(
+ int? instanceId,
+ String? url,
+ _i7.Uint8List? data,
+ ) =>
super.noSuchMethod(
- Invocation.method(#clearCache, [instanceId, includeDiskFiles]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #postUrl,
+ [
+ instanceId,
+ url,
+ data,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ String? getUrl(int? instanceId) => (super.noSuchMethod(Invocation.method(
+ #getUrl,
+ [instanceId],
+ )) as String?);
+ @override
+ bool canGoBack(int? instanceId) => (super.noSuchMethod(
+ Invocation.method(
+ #canGoBack,
+ [instanceId],
+ ),
+ returnValue: false,
+ ) as bool);
+ @override
+ bool canGoForward(int? instanceId) => (super.noSuchMethod(
+ Invocation.method(
+ #canGoForward,
+ [instanceId],
+ ),
+ returnValue: false,
+ ) as bool);
+ @override
+ void goBack(int? instanceId) => super.noSuchMethod(
+ Invocation.method(
+ #goBack,
+ [instanceId],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void goForward(int? instanceId) => super.noSuchMethod(
+ Invocation.method(
+ #goForward,
+ [instanceId],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void reload(int? instanceId) => super.noSuchMethod(
+ Invocation.method(
+ #reload,
+ [instanceId],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void clearCache(
+ int? instanceId,
+ bool? includeDiskFiles,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #clearCache,
+ [
+ instanceId,
+ includeDiskFiles,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
_i5.Future<String?> evaluateJavascript(
- int? instanceId, String? javascriptString) =>
+ int? instanceId,
+ String? javascriptString,
+ ) =>
(super.noSuchMethod(
+ Invocation.method(
+ #evaluateJavascript,
+ [
+ instanceId,
+ javascriptString,
+ ],
+ ),
+ returnValue: _i5.Future<String?>.value(),
+ ) as _i5.Future<String?>);
+ @override
+ String? getTitle(int? instanceId) => (super.noSuchMethod(Invocation.method(
+ #getTitle,
+ [instanceId],
+ )) as String?);
+ @override
+ void scrollTo(
+ int? instanceId,
+ int? x,
+ int? y,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #scrollTo,
+ [
+ instanceId,
+ x,
+ y,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void scrollBy(
+ int? instanceId,
+ int? x,
+ int? y,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #scrollBy,
+ [
+ instanceId,
+ x,
+ y,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ int getScrollX(int? instanceId) => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollX,
+ [instanceId],
+ ),
+ returnValue: 0,
+ ) as int);
+ @override
+ int getScrollY(int? instanceId) => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollY,
+ [instanceId],
+ ),
+ returnValue: 0,
+ ) as int);
+ @override
+ _i3.WebViewPoint getScrollPosition(int? instanceId) => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollPosition,
+ [instanceId],
+ ),
+ returnValue: _FakeWebViewPoint_2(
+ this,
Invocation.method(
- #evaluateJavascript, [instanceId, javascriptString]),
- returnValue: Future<String?>.value()) as _i5.Future<String?>);
- @override
- String? getTitle(int? instanceId) =>
- (super.noSuchMethod(Invocation.method(#getTitle, [instanceId]))
- as String?);
- @override
- void scrollTo(int? instanceId, int? x, int? y) =>
- super.noSuchMethod(Invocation.method(#scrollTo, [instanceId, x, y]),
- returnValueForMissingStub: null);
- @override
- void scrollBy(int? instanceId, int? x, int? y) =>
- super.noSuchMethod(Invocation.method(#scrollBy, [instanceId, x, y]),
- returnValueForMissingStub: null);
- @override
- int getScrollX(int? instanceId) =>
- (super.noSuchMethod(Invocation.method(#getScrollX, [instanceId]),
- returnValue: 0) as int);
- @override
- int getScrollY(int? instanceId) =>
- (super.noSuchMethod(Invocation.method(#getScrollY, [instanceId]),
- returnValue: 0) as int);
- @override
- _i3.WebViewPoint getScrollPosition(int? instanceId) =>
- (super.noSuchMethod(Invocation.method(#getScrollPosition, [instanceId]),
- returnValue: _FakeWebViewPoint_2()) as _i3.WebViewPoint);
+ #getScrollPosition,
+ [instanceId],
+ ),
+ ),
+ ) as _i3.WebViewPoint);
@override
void setWebContentsDebuggingEnabled(bool? enabled) => super.noSuchMethod(
- Invocation.method(#setWebContentsDebuggingEnabled, [enabled]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setWebContentsDebuggingEnabled,
+ [enabled],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setWebViewClient(int? instanceId, int? webViewClientInstanceId) =>
+ void setWebViewClient(
+ int? instanceId,
+ int? webViewClientInstanceId,
+ ) =>
super.noSuchMethod(
- Invocation.method(
- #setWebViewClient, [instanceId, webViewClientInstanceId]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setWebViewClient,
+ [
+ instanceId,
+ webViewClientInstanceId,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
void addJavaScriptChannel(
- int? instanceId, int? javaScriptChannelInstanceId) =>
+ int? instanceId,
+ int? javaScriptChannelInstanceId,
+ ) =>
super.noSuchMethod(
- Invocation.method(
- #addJavaScriptChannel, [instanceId, javaScriptChannelInstanceId]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #addJavaScriptChannel,
+ [
+ instanceId,
+ javaScriptChannelInstanceId,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
void removeJavaScriptChannel(
- int? instanceId, int? javaScriptChannelInstanceId) =>
+ int? instanceId,
+ int? javaScriptChannelInstanceId,
+ ) =>
super.noSuchMethod(
- Invocation.method(#removeJavaScriptChannel,
- [instanceId, javaScriptChannelInstanceId]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #removeJavaScriptChannel,
+ [
+ instanceId,
+ javaScriptChannelInstanceId,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setDownloadListener(int? instanceId, int? listenerInstanceId) =>
+ void setDownloadListener(
+ int? instanceId,
+ int? listenerInstanceId,
+ ) =>
super.noSuchMethod(
- Invocation.method(
- #setDownloadListener, [instanceId, listenerInstanceId]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setDownloadListener,
+ [
+ instanceId,
+ listenerInstanceId,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setWebChromeClient(int? instanceId, int? clientInstanceId) =>
+ void setWebChromeClient(
+ int? instanceId,
+ int? clientInstanceId,
+ ) =>
super.noSuchMethod(
- Invocation.method(
- #setWebChromeClient, [instanceId, clientInstanceId]),
- returnValueForMissingStub: null);
+ Invocation.method(
+ #setWebChromeClient,
+ [
+ instanceId,
+ clientInstanceId,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
@override
- void setBackgroundColor(int? instanceId, int? color) => super.noSuchMethod(
- Invocation.method(#setBackgroundColor, [instanceId, color]),
- returnValueForMissingStub: null);
+ void setBackgroundColor(
+ int? instanceId,
+ int? color,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #setBackgroundColor,
+ [
+ instanceId,
+ color,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
}
/// A class which mocks [TestAssetManagerHostApi].
@@ -426,13 +927,21 @@
}
@override
- List<String?> list(String? path) =>
- (super.noSuchMethod(Invocation.method(#list, [path]),
- returnValue: <String?>[]) as List<String?>);
+ List<String?> list(String? path) => (super.noSuchMethod(
+ Invocation.method(
+ #list,
+ [path],
+ ),
+ returnValue: <String?>[],
+ ) as List<String?>);
@override
- String getAssetFilePathByName(String? name) =>
- (super.noSuchMethod(Invocation.method(#getAssetFilePathByName, [name]),
- returnValue: '') as String);
+ String getAssetFilePathByName(String? name) => (super.noSuchMethod(
+ Invocation.method(
+ #getAssetFilePathByName,
+ [name],
+ ),
+ returnValue: '',
+ ) as String);
}
/// A class which mocks [WebChromeClient].
@@ -444,13 +953,19 @@
}
@override
- void onProgressChanged(_i2.WebView? webView, int? progress) => super
- .noSuchMethod(Invocation.method(#onProgressChanged, [webView, progress]),
- returnValueForMissingStub: null);
- @override
- _i2.WebChromeClient copy() =>
- (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeWebChromeClient_3()) as _i2.WebChromeClient);
+ _i2.WebChromeClient copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebChromeClient_3(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebChromeClient);
}
/// A class which mocks [WebView].
@@ -462,153 +977,306 @@
}
@override
- bool get useHybridComposition =>
- (super.noSuchMethod(Invocation.getter(#useHybridComposition),
- returnValue: false) as bool);
+ bool get useHybridComposition => (super.noSuchMethod(
+ Invocation.getter(#useHybridComposition),
+ returnValue: false,
+ ) as bool);
@override
- _i2.WebSettings get settings =>
- (super.noSuchMethod(Invocation.getter(#settings),
- returnValue: _FakeWebSettings_4()) as _i2.WebSettings);
+ _i2.WebSettings get settings => (super.noSuchMethod(
+ Invocation.getter(#settings),
+ returnValue: _FakeWebSettings_4(
+ this,
+ Invocation.getter(#settings),
+ ),
+ ) as _i2.WebSettings);
@override
- _i5.Future<void> loadData(
- {String? data, String? mimeType, String? encoding}) =>
+ _i5.Future<void> loadData({
+ required String? data,
+ String? mimeType,
+ String? encoding,
+ }) =>
(super.noSuchMethod(
- Invocation.method(#loadData, [],
- {#data: data, #mimeType: mimeType, #encoding: encoding}),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ Invocation.method(
+ #loadData,
+ [],
+ {
+ #data: data,
+ #mimeType: mimeType,
+ #encoding: encoding,
+ },
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<void> loadDataWithBaseUrl(
- {String? baseUrl,
- String? data,
- String? mimeType,
- String? encoding,
- String? historyUrl}) =>
+ _i5.Future<void> loadDataWithBaseUrl({
+ String? baseUrl,
+ required String? data,
+ String? mimeType,
+ String? encoding,
+ String? historyUrl,
+ }) =>
(super.noSuchMethod(
- Invocation.method(#loadDataWithBaseUrl, [], {
+ Invocation.method(
+ #loadDataWithBaseUrl,
+ [],
+ {
#baseUrl: baseUrl,
#data: data,
#mimeType: mimeType,
#encoding: encoding,
- #historyUrl: historyUrl
- }),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ #historyUrl: historyUrl,
+ },
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<void> loadUrl(String? url, Map<String, String>? headers) =>
- (super.noSuchMethod(Invocation.method(#loadUrl, [url, headers]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> loadUrl(
+ String? url,
+ Map<String, String>? headers,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #loadUrl,
+ [
+ url,
+ headers,
+ ],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<void> postUrl(String? url, _i7.Uint8List? data) =>
- (super.noSuchMethod(Invocation.method(#postUrl, [url, data]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> postUrl(
+ String? url,
+ _i7.Uint8List? data,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #postUrl,
+ [
+ url,
+ data,
+ ],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<String?> getUrl() =>
- (super.noSuchMethod(Invocation.method(#getUrl, []),
- returnValue: Future<String?>.value()) as _i5.Future<String?>);
+ _i5.Future<String?> getUrl() => (super.noSuchMethod(
+ Invocation.method(
+ #getUrl,
+ [],
+ ),
+ returnValue: _i5.Future<String?>.value(),
+ ) as _i5.Future<String?>);
@override
- _i5.Future<bool> canGoBack() =>
- (super.noSuchMethod(Invocation.method(#canGoBack, []),
- returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
+ _i5.Future<bool> canGoBack() => (super.noSuchMethod(
+ Invocation.method(
+ #canGoBack,
+ [],
+ ),
+ returnValue: _i5.Future<bool>.value(false),
+ ) as _i5.Future<bool>);
@override
- _i5.Future<bool> canGoForward() =>
- (super.noSuchMethod(Invocation.method(#canGoForward, []),
- returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
+ _i5.Future<bool> canGoForward() => (super.noSuchMethod(
+ Invocation.method(
+ #canGoForward,
+ [],
+ ),
+ returnValue: _i5.Future<bool>.value(false),
+ ) as _i5.Future<bool>);
@override
- _i5.Future<void> goBack() =>
- (super.noSuchMethod(Invocation.method(#goBack, []),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> goBack() => (super.noSuchMethod(
+ Invocation.method(
+ #goBack,
+ [],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<void> goForward() =>
- (super.noSuchMethod(Invocation.method(#goForward, []),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> goForward() => (super.noSuchMethod(
+ Invocation.method(
+ #goForward,
+ [],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<void> reload() =>
- (super.noSuchMethod(Invocation.method(#reload, []),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> reload() => (super.noSuchMethod(
+ Invocation.method(
+ #reload,
+ [],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<void> clearCache(bool? includeDiskFiles) =>
- (super.noSuchMethod(Invocation.method(#clearCache, [includeDiskFiles]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> clearCache(bool? includeDiskFiles) => (super.noSuchMethod(
+ Invocation.method(
+ #clearCache,
+ [includeDiskFiles],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<String?> evaluateJavascript(String? javascriptString) => (super
- .noSuchMethod(Invocation.method(#evaluateJavascript, [javascriptString]),
- returnValue: Future<String?>.value()) as _i5.Future<String?>);
+ _i5.Future<String?> evaluateJavascript(String? javascriptString) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #evaluateJavascript,
+ [javascriptString],
+ ),
+ returnValue: _i5.Future<String?>.value(),
+ ) as _i5.Future<String?>);
@override
- _i5.Future<String?> getTitle() =>
- (super.noSuchMethod(Invocation.method(#getTitle, []),
- returnValue: Future<String?>.value()) as _i5.Future<String?>);
+ _i5.Future<String?> getTitle() => (super.noSuchMethod(
+ Invocation.method(
+ #getTitle,
+ [],
+ ),
+ returnValue: _i5.Future<String?>.value(),
+ ) as _i5.Future<String?>);
@override
- _i5.Future<void> scrollTo(int? x, int? y) =>
- (super.noSuchMethod(Invocation.method(#scrollTo, [x, y]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> scrollTo(
+ int? x,
+ int? y,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #scrollTo,
+ [
+ x,
+ y,
+ ],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<void> scrollBy(int? x, int? y) =>
- (super.noSuchMethod(Invocation.method(#scrollBy, [x, y]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> scrollBy(
+ int? x,
+ int? y,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #scrollBy,
+ [
+ x,
+ y,
+ ],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<int> getScrollX() =>
- (super.noSuchMethod(Invocation.method(#getScrollX, []),
- returnValue: Future<int>.value(0)) as _i5.Future<int>);
+ _i5.Future<int> getScrollX() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollX,
+ [],
+ ),
+ returnValue: _i5.Future<int>.value(0),
+ ) as _i5.Future<int>);
@override
- _i5.Future<int> getScrollY() =>
- (super.noSuchMethod(Invocation.method(#getScrollY, []),
- returnValue: Future<int>.value(0)) as _i5.Future<int>);
+ _i5.Future<int> getScrollY() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollY,
+ [],
+ ),
+ returnValue: _i5.Future<int>.value(0),
+ ) as _i5.Future<int>);
@override
- _i5.Future<_i4.Offset> getScrollPosition() =>
- (super.noSuchMethod(Invocation.method(#getScrollPosition, []),
- returnValue: Future<_i4.Offset>.value(_FakeOffset_5()))
- as _i5.Future<_i4.Offset>);
+ _i5.Future<_i4.Offset> getScrollPosition() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ returnValue: _i5.Future<_i4.Offset>.value(_FakeOffset_5(
+ this,
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ )),
+ ) as _i5.Future<_i4.Offset>);
@override
_i5.Future<void> setWebViewClient(_i2.WebViewClient? webViewClient) =>
- (super.noSuchMethod(Invocation.method(#setWebViewClient, [webViewClient]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ (super.noSuchMethod(
+ Invocation.method(
+ #setWebViewClient,
+ [webViewClient],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
_i5.Future<void> addJavaScriptChannel(
_i2.JavaScriptChannel? javaScriptChannel) =>
(super.noSuchMethod(
- Invocation.method(#addJavaScriptChannel, [javaScriptChannel]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ Invocation.method(
+ #addJavaScriptChannel,
+ [javaScriptChannel],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
_i5.Future<void> removeJavaScriptChannel(
_i2.JavaScriptChannel? javaScriptChannel) =>
(super.noSuchMethod(
- Invocation.method(#removeJavaScriptChannel, [javaScriptChannel]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ Invocation.method(
+ #removeJavaScriptChannel,
+ [javaScriptChannel],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
_i5.Future<void> setDownloadListener(_i2.DownloadListener? listener) =>
- (super.noSuchMethod(Invocation.method(#setDownloadListener, [listener]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ (super.noSuchMethod(
+ Invocation.method(
+ #setDownloadListener,
+ [listener],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
_i5.Future<void> setWebChromeClient(_i2.WebChromeClient? client) =>
- (super.noSuchMethod(Invocation.method(#setWebChromeClient, [client]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ (super.noSuchMethod(
+ Invocation.method(
+ #setWebChromeClient,
+ [client],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<void> setBackgroundColor(_i4.Color? color) =>
- (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
+ _i5.Future<void> setBackgroundColor(_i4.Color? color) => (super.noSuchMethod(
+ Invocation.method(
+ #setBackgroundColor,
+ [color],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- _i5.Future<void> release() =>
- (super.noSuchMethod(Invocation.method(#release, []),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i2.WebView copy() => (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeWebView_6()) as _i2.WebView);
+ _i2.WebView copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebView_6(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebView);
}
/// A class which mocks [WebViewClient].
@@ -620,39 +1288,28 @@
}
@override
- bool get shouldOverrideUrlLoading =>
- (super.noSuchMethod(Invocation.getter(#shouldOverrideUrlLoading),
- returnValue: false) as bool);
+ _i5.Future<void> setSynchronousReturnValueForShouldOverrideUrlLoading(
+ bool? value) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setSynchronousReturnValueForShouldOverrideUrlLoading,
+ [value],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
@override
- void onPageStarted(_i2.WebView? webView, String? url) =>
- super.noSuchMethod(Invocation.method(#onPageStarted, [webView, url]),
- returnValueForMissingStub: null);
- @override
- void onPageFinished(_i2.WebView? webView, String? url) =>
- super.noSuchMethod(Invocation.method(#onPageFinished, [webView, url]),
- returnValueForMissingStub: null);
- @override
- void onReceivedRequestError(_i2.WebView? webView,
- _i2.WebResourceRequest? request, _i2.WebResourceError? error) =>
- super.noSuchMethod(
- Invocation.method(#onReceivedRequestError, [webView, request, error]),
- returnValueForMissingStub: null);
- @override
- void onReceivedError(_i2.WebView? webView, int? errorCode,
- String? description, String? failingUrl) =>
- super.noSuchMethod(
+ _i2.WebViewClient copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebViewClient_7(
+ this,
Invocation.method(
- #onReceivedError, [webView, errorCode, description, failingUrl]),
- returnValueForMissingStub: null);
- @override
- void requestLoading(_i2.WebView? webView, _i2.WebResourceRequest? request) =>
- super.noSuchMethod(Invocation.method(#requestLoading, [webView, request]),
- returnValueForMissingStub: null);
- @override
- void urlLoading(_i2.WebView? webView, String? url) =>
- super.noSuchMethod(Invocation.method(#urlLoading, [webView, url]),
- returnValueForMissingStub: null);
- @override
- _i2.WebViewClient copy() => (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeWebViewClient_7()) as _i2.WebViewClient);
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebViewClient);
}
diff --git a/packages/webview_flutter/webview_flutter_android/test/surface_android_test.dart b/packages/webview_flutter/webview_flutter_android/test/legacy/surface_android_test.dart
similarity index 94%
rename from packages/webview_flutter/webview_flutter_android/test/surface_android_test.dart
rename to packages/webview_flutter/webview_flutter_android/test/legacy/surface_android_test.dart
index 63e752b..1657e1b 100644
--- a/packages/webview_flutter/webview_flutter_android/test/surface_android_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/legacy/surface_android_test.dart
@@ -7,8 +7,8 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
-import 'package:webview_flutter_android/webview_surface_android.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_android/src/legacy/webview_surface_android.dart';
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_cookie_manager_test.dart
similarity index 89%
rename from packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart
rename to packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_cookie_manager_test.dart
index 4f274ff..e4cd616 100644
--- a/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_cookie_manager_test.dart
@@ -7,8 +7,8 @@
import 'package:mockito/mockito.dart';
import 'package:webview_flutter_android/src/android_webview.dart'
as android_webview;
-import 'package:webview_flutter_android/webview_android_cookie_manager.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_android/src/legacy/webview_android_cookie_manager.dart';
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
import 'webview_android_cookie_manager_test.mocks.dart';
diff --git a/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_cookie_manager_test.mocks.dart
new file mode 100644
index 0000000..85aed14
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_cookie_manager_test.mocks.dart
@@ -0,0 +1,54 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_android/test/legacy/webview_android_cookie_manager_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i3;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_android/src/android_webview.dart' as _i2;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+/// A class which mocks [CookieManager].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockCookieManager extends _i1.Mock implements _i2.CookieManager {
+ MockCookieManager() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i3.Future<void> setCookie(
+ String? url,
+ String? value,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setCookie,
+ [
+ url,
+ value,
+ ],
+ ),
+ returnValue: _i3.Future<void>.value(),
+ returnValueForMissingStub: _i3.Future<void>.value(),
+ ) as _i3.Future<void>);
+ @override
+ _i3.Future<bool> clearCookies() => (super.noSuchMethod(
+ Invocation.method(
+ #clearCookies,
+ [],
+ ),
+ returnValue: _i3.Future<bool>.value(false),
+ ) as _i3.Future<bool>);
+}
diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.dart b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.dart
similarity index 75%
rename from packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.dart
rename to packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.dart
index b6d6239..909607a 100644
--- a/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.dart
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/widgets.dart';
@@ -13,11 +12,11 @@
as android_webview;
import 'package:webview_flutter_android/src/android_webview_api_impls.dart';
import 'package:webview_flutter_android/src/instance_manager.dart';
-import 'package:webview_flutter_android/webview_android_widget.dart';
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_android/src/legacy/webview_android_widget.dart';
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart';
-import 'android_webview_test.mocks.dart' show MockTestWebViewHostApi;
-import 'test_android_webview.pigeon.dart';
+import '../android_webview_test.mocks.dart' show MockTestWebViewHostApi;
+import '../test_android_webview.pigeon.dart';
import 'webview_android_widget_test.mocks.dart';
@GenerateMocks(<Type>[
@@ -26,10 +25,10 @@
android_webview.WebStorage,
android_webview.WebView,
android_webview.WebResourceRequest,
- WebViewAndroidDownloadListener,
+ android_webview.DownloadListener,
WebViewAndroidJavaScriptChannel,
- WebViewAndroidWebChromeClient,
- WebViewAndroidWebViewClient,
+ android_webview.WebChromeClient,
+ android_webview.WebViewClient,
JavascriptChannelRegistry,
WebViewPlatformCallbacksHandler,
WebViewProxy,
@@ -45,9 +44,9 @@
late MockWebViewProxy mockWebViewProxy;
late MockWebViewPlatformCallbacksHandler mockCallbacksHandler;
- late WebViewAndroidWebViewClient webViewClient;
- late WebViewAndroidDownloadListener downloadListener;
- late WebViewAndroidWebChromeClient webChromeClient;
+ late MockWebViewClient mockWebViewClient;
+ late android_webview.DownloadListener downloadListener;
+ late android_webview.WebChromeClient webChromeClient;
late MockJavascriptChannelRegistry mockJavascriptChannelRegistry;
@@ -58,12 +57,21 @@
mockWebView = MockWebView();
mockWebSettings = MockWebSettings();
mockWebStorage = MockWebStorage();
+ mockWebViewClient = MockWebViewClient();
when(mockWebView.settings).thenReturn(mockWebSettings);
mockWebViewProxy = MockWebViewProxy();
when(mockWebViewProxy.createWebView(
useHybridComposition: anyNamed('useHybridComposition'),
)).thenReturn(mockWebView);
+ when(mockWebViewProxy.createWebViewClient(
+ onPageStarted: anyNamed('onPageStarted'),
+ onPageFinished: anyNamed('onPageFinished'),
+ onReceivedError: anyNamed('onReceivedError'),
+ onReceivedRequestError: anyNamed('onReceivedRequestError'),
+ requestLoading: anyNamed('requestLoading'),
+ urlLoading: anyNamed('urlLoading'),
+ )).thenReturn(mockWebViewClient);
mockCallbacksHandler = MockWebViewPlatformCallbacksHandler();
mockJavascriptChannelRegistry = MockJavascriptChannelRegistry();
@@ -97,7 +105,7 @@
},
));
- webViewClient = testController.webViewClient;
+ mockWebViewClient = testController.webViewClient as MockWebViewClient;
downloadListener = testController.downloadListener;
webChromeClient = testController.webChromeClient;
}
@@ -114,9 +122,9 @@
verify(mockWebSettings.setBuiltInZoomControls(true));
verifyInOrder(<Future<void>>[
- mockWebView.setWebViewClient(webViewClient),
mockWebView.setDownloadListener(downloadListener),
mockWebView.setWebChromeClient(webChromeClient),
+ mockWebView.setWebViewClient(mockWebViewClient),
]);
});
@@ -225,6 +233,16 @@
});
testWidgets('hasNavigationDelegate', (WidgetTester tester) async {
+ final MockWebViewClient mockWebViewClient = MockWebViewClient();
+ when(mockWebViewProxy.createWebViewClient(
+ onPageStarted: anyNamed('onPageStarted'),
+ onPageFinished: anyNamed('onPageFinished'),
+ onReceivedError: anyNamed('onReceivedError'),
+ onReceivedRequestError: anyNamed('onReceivedRequestError'),
+ requestLoading: anyNamed('requestLoading'),
+ urlLoading: anyNamed('urlLoading'),
+ )).thenReturn(mockWebViewClient);
+
await buildWidget(
tester,
creationParams: CreationParams(
@@ -235,8 +253,10 @@
),
);
- expect(testController.webViewClient.handlesNavigation, isTrue);
- expect(testController.webViewClient.shouldOverrideUrlLoading, isTrue);
+ verify(
+ mockWebViewClient
+ .setSynchronousReturnValueForShouldOverrideUrlLoading(true),
+ );
});
testWidgets('debuggingEnabled true', (WidgetTester tester) async {
@@ -693,20 +713,53 @@
group('WebViewPlatformCallbacksHandler', () {
testWidgets('onPageStarted', (WidgetTester tester) async {
await buildWidget(tester);
- webViewClient.onPageStarted(mockWebView, 'https://google.com');
+ final void Function(android_webview.WebView, String) onPageStarted =
+ verify(mockWebViewProxy.createWebViewClient(
+ onPageStarted: captureAnyNamed('onPageStarted'),
+ onPageFinished: anyNamed('onPageFinished'),
+ onReceivedError: anyNamed('onReceivedError'),
+ onReceivedRequestError: anyNamed('onReceivedRequestError'),
+ requestLoading: anyNamed('requestLoading'),
+ urlLoading: anyNamed('urlLoading'),
+ )).captured.single as Function(android_webview.WebView, String);
+
+ onPageStarted(mockWebView, 'https://google.com');
verify(mockCallbacksHandler.onPageStarted('https://google.com'));
});
testWidgets('onPageFinished', (WidgetTester tester) async {
await buildWidget(tester);
- webViewClient.onPageFinished(mockWebView, 'https://google.com');
+
+ final void Function(android_webview.WebView, String) onPageFinished =
+ verify(mockWebViewProxy.createWebViewClient(
+ onPageStarted: anyNamed('onPageStarted'),
+ onPageFinished: captureAnyNamed('onPageFinished'),
+ onReceivedError: anyNamed('onReceivedError'),
+ onReceivedRequestError: anyNamed('onReceivedRequestError'),
+ requestLoading: anyNamed('requestLoading'),
+ urlLoading: anyNamed('urlLoading'),
+ )).captured.single as Function(android_webview.WebView, String);
+
+ onPageFinished(mockWebView, 'https://google.com');
verify(mockCallbacksHandler.onPageFinished('https://google.com'));
});
testWidgets('onWebResourceError from onReceivedError',
(WidgetTester tester) async {
await buildWidget(tester);
- webViewClient.onReceivedError(
+
+ final void Function(android_webview.WebView, int, String, String)
+ onReceivedError = verify(mockWebViewProxy.createWebViewClient(
+ onPageStarted: anyNamed('onPageStarted'),
+ onPageFinished: anyNamed('onPageFinished'),
+ onReceivedError: captureAnyNamed('onReceivedError'),
+ onReceivedRequestError: anyNamed('onReceivedRequestError'),
+ requestLoading: anyNamed('requestLoading'),
+ urlLoading: anyNamed('urlLoading'),
+ )).captured.single as Function(
+ android_webview.WebView, int, String, String);
+
+ onReceivedError(
mockWebView,
android_webview.WebViewClient.errorAuthentication,
'description',
@@ -727,7 +780,25 @@
testWidgets('onWebResourceError from onReceivedRequestError',
(WidgetTester tester) async {
await buildWidget(tester);
- webViewClient.onReceivedRequestError(
+
+ final void Function(
+ android_webview.WebView,
+ android_webview.WebResourceRequest,
+ android_webview.WebResourceError,
+ ) onReceivedRequestError = verify(mockWebViewProxy.createWebViewClient(
+ onPageStarted: anyNamed('onPageStarted'),
+ onPageFinished: anyNamed('onPageFinished'),
+ onReceivedError: anyNamed('onReceivedError'),
+ onReceivedRequestError: captureAnyNamed('onReceivedRequestError'),
+ requestLoading: anyNamed('requestLoading'),
+ urlLoading: anyNamed('urlLoading'),
+ )).captured.single as Function(
+ android_webview.WebView,
+ android_webview.WebResourceRequest,
+ android_webview.WebResourceError,
+ );
+
+ onReceivedRequestError(
mockWebView,
android_webview.WebResourceRequest(
url: 'https://google.com',
@@ -762,7 +833,17 @@
url: 'https://google.com',
)).thenReturn(true);
- webViewClient.urlLoading(mockWebView, 'https://google.com');
+ final void Function(android_webview.WebView, String) urlLoading =
+ verify(mockWebViewProxy.createWebViewClient(
+ onPageStarted: anyNamed('onPageStarted'),
+ onPageFinished: anyNamed('onPageFinished'),
+ onReceivedError: anyNamed('onReceivedError'),
+ onReceivedRequestError: anyNamed('onReceivedRequestError'),
+ requestLoading: anyNamed('requestLoading'),
+ urlLoading: captureAnyNamed('urlLoading'),
+ )).captured.single as Function(android_webview.WebView, String);
+
+ urlLoading(mockWebView, 'https://google.com');
verify(mockCallbacksHandler.onNavigationRequest(
url: 'https://google.com',
isForMainFrame: true,
@@ -778,7 +859,22 @@
url: 'https://google.com',
)).thenReturn(true);
- webViewClient.requestLoading(
+ final void Function(
+ android_webview.WebView,
+ android_webview.WebResourceRequest,
+ ) requestLoading = verify(mockWebViewProxy.createWebViewClient(
+ onPageStarted: anyNamed('onPageStarted'),
+ onPageFinished: anyNamed('onPageFinished'),
+ onReceivedError: anyNamed('onReceivedError'),
+ onReceivedRequestError: anyNamed('onReceivedRequestError'),
+ requestLoading: captureAnyNamed('requestLoading'),
+ urlLoading: anyNamed('urlLoading'),
+ )).captured.single as Function(
+ android_webview.WebView,
+ android_webview.WebResourceRequest,
+ );
+
+ requestLoading(
mockWebView,
android_webview.WebResourceRequest(
url: 'https://google.com',
@@ -843,192 +939,4 @@
verify(mockPlatformHostApi.setWebContentsDebuggingEnabled(false));
});
});
-
- group('WebViewAndroidWebViewClient', () {
- test(
- 'urlLoading should call loadUrl when onNavigationRequestCallback returns true',
- () {
- final Completer<void> completer = Completer<void>();
- final WebViewAndroidWebViewClient webViewClient =
- WebViewAndroidWebViewClient.handlesNavigation(
- onPageStartedCallback: (_) {},
- onPageFinishedCallback: (_) {},
- onWebResourceErrorCallback: (_) {},
- onNavigationRequestCallback: ({
- required bool isForMainFrame,
- required String url,
- }) =>
- true,
- loadUrl: (String url, Map<String, String>? headers) async {
- completer.complete();
- });
-
- webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
- expect(completer.isCompleted, isTrue);
- });
-
- test(
- 'urlLoading should call loadUrl when onNavigationRequestCallback returns a Future true',
- () async {
- final Completer<void> completer = Completer<void>();
- final WebViewAndroidWebViewClient webViewClient =
- WebViewAndroidWebViewClient.handlesNavigation(
- onPageStartedCallback: (_) {},
- onPageFinishedCallback: (_) {},
- onWebResourceErrorCallback: (_) {},
- onNavigationRequestCallback: ({
- required bool isForMainFrame,
- required String url,
- }) =>
- Future<bool>.value(true),
- loadUrl: (String url, Map<String, String>? headers) async {
- completer.complete();
- });
-
- webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
- expect(completer.future, completes);
- });
-
- test(
- 'urlLoading should not call laodUrl when onNavigationRequestCallback returns false',
- () async {
- final WebViewAndroidWebViewClient webViewClient =
- WebViewAndroidWebViewClient.handlesNavigation(
- onPageStartedCallback: (_) {},
- onPageFinishedCallback: (_) {},
- onWebResourceErrorCallback: (_) {},
- onNavigationRequestCallback: ({
- required bool isForMainFrame,
- required String url,
- }) =>
- false,
- loadUrl: (String url, Map<String, String>? headers) async {
- fail(
- 'loadUrl should not be called if onNavigationRequestCallback returns false.');
- });
-
- webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
- });
-
- test(
- 'urlLoading should not call loadUrl when onNavigationRequestCallback returns a Future false',
- () {
- final WebViewAndroidWebViewClient webViewClient =
- WebViewAndroidWebViewClient.handlesNavigation(
- onPageStartedCallback: (_) {},
- onPageFinishedCallback: (_) {},
- onWebResourceErrorCallback: (_) {},
- onNavigationRequestCallback: ({
- required bool isForMainFrame,
- required String url,
- }) =>
- Future<bool>.value(false),
- loadUrl: (String url, Map<String, String>? headers) async {
- fail(
- 'loadUrl should not be called if onNavigationRequestCallback returns false.');
- });
-
- webViewClient.urlLoading(MockWebView(), 'https://flutter.dev');
- });
-
- test(
- 'requestLoading should call loadUrl when onNavigationRequestCallback returns true',
- () {
- final Completer<void> completer = Completer<void>();
- final MockWebResourceRequest mockRequest = MockWebResourceRequest();
- when(mockRequest.isForMainFrame).thenReturn(true);
- when(mockRequest.url).thenReturn('https://flutter.dev');
- final WebViewAndroidWebViewClient webViewClient =
- WebViewAndroidWebViewClient.handlesNavigation(
- onPageStartedCallback: (_) {},
- onPageFinishedCallback: (_) {},
- onWebResourceErrorCallback: (_) {},
- onNavigationRequestCallback: ({
- required bool isForMainFrame,
- required String url,
- }) =>
- true,
- loadUrl: (String url, Map<String, String>? headers) async {
- expect(url, 'https://flutter.dev');
- completer.complete();
- });
-
- webViewClient.requestLoading(MockWebView(), mockRequest);
- expect(completer.isCompleted, isTrue);
- });
-
- test(
- 'requestLoading should call loadUrl when onNavigationRequestCallback returns a Future true',
- () async {
- final Completer<void> completer = Completer<void>();
- final MockWebResourceRequest mockRequest = MockWebResourceRequest();
- when(mockRequest.isForMainFrame).thenReturn(true);
- when(mockRequest.url).thenReturn('https://flutter.dev');
- final WebViewAndroidWebViewClient webViewClient =
- WebViewAndroidWebViewClient.handlesNavigation(
- onPageStartedCallback: (_) {},
- onPageFinishedCallback: (_) {},
- onWebResourceErrorCallback: (_) {},
- onNavigationRequestCallback: ({
- required bool isForMainFrame,
- required String url,
- }) =>
- Future<bool>.value(true),
- loadUrl: (String url, Map<String, String>? headers) async {
- expect(url, 'https://flutter.dev');
- completer.complete();
- });
-
- webViewClient.requestLoading(MockWebView(), mockRequest);
- expect(completer.future, completes);
- });
-
- test(
- 'requestLoading should not call loadUrl when onNavigationRequestCallback returns false',
- () {
- final MockWebResourceRequest mockRequest = MockWebResourceRequest();
- when(mockRequest.isForMainFrame).thenReturn(true);
- when(mockRequest.url).thenReturn('https://flutter.dev');
- final WebViewAndroidWebViewClient webViewClient =
- WebViewAndroidWebViewClient.handlesNavigation(
- onPageStartedCallback: (_) {},
- onPageFinishedCallback: (_) {},
- onWebResourceErrorCallback: (_) {},
- onNavigationRequestCallback: ({
- required bool isForMainFrame,
- required String url,
- }) =>
- false,
- loadUrl: (String url, Map<String, String>? headers) {
- fail(
- 'loadUrl should not be called if onNavigationRequestCallback returns false.');
- });
-
- webViewClient.requestLoading(MockWebView(), mockRequest);
- });
-
- test(
- 'requestLoading should not call loadUrl when onNavigationRequestCallback returns a Future false',
- () {
- final MockWebResourceRequest mockRequest = MockWebResourceRequest();
- when(mockRequest.isForMainFrame).thenReturn(true);
- when(mockRequest.url).thenReturn('https://flutter.dev');
- final WebViewAndroidWebViewClient webViewClient =
- WebViewAndroidWebViewClient.handlesNavigation(
- onPageStartedCallback: (_) {},
- onPageFinishedCallback: (_) {},
- onWebResourceErrorCallback: (_) {},
- onNavigationRequestCallback: ({
- required bool isForMainFrame,
- required String url,
- }) =>
- Future<bool>.value(false),
- loadUrl: (String url, Map<String, String>? headers) {
- fail(
- 'loadUrl should not be called if onNavigationRequestCallback returns false.');
- });
-
- webViewClient.requestLoading(MockWebView(), mockRequest);
- });
- });
}
diff --git a/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.mocks.dart
new file mode 100644
index 0000000..1f16c29
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/test/legacy/webview_android_widget_test.mocks.dart
@@ -0,0 +1,1016 @@
+// Mocks generated by Mockito 5.3.2 from annotations
+// in webview_flutter_android/test/legacy/webview_android_widget_test.dart.
+// Do not manually edit this file.
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'dart:async' as _i5;
+import 'dart:typed_data' as _i6;
+import 'dart:ui' as _i3;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 'package:webview_flutter_android/src/android_webview.dart' as _i2;
+import 'package:webview_flutter_android/src/legacy/webview_android_widget.dart'
+ as _i7;
+import 'package:webview_flutter_platform_interface/src/webview_flutter_platform_interface_legacy.dart'
+ as _i4;
+
+// ignore_for_file: type=lint
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+// ignore_for_file: subtype_of_sealed_class
+
+class _FakeWebSettings_0 extends _i1.SmartFake implements _i2.WebSettings {
+ _FakeWebSettings_0(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeWebStorage_1 extends _i1.SmartFake implements _i2.WebStorage {
+ _FakeWebStorage_1(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeOffset_2 extends _i1.SmartFake implements _i3.Offset {
+ _FakeOffset_2(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeWebView_3 extends _i1.SmartFake implements _i2.WebView {
+ _FakeWebView_3(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeDownloadListener_4 extends _i1.SmartFake
+ implements _i2.DownloadListener {
+ _FakeDownloadListener_4(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeJavascriptChannelRegistry_5 extends _i1.SmartFake
+ implements _i4.JavascriptChannelRegistry {
+ _FakeJavascriptChannelRegistry_5(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeJavaScriptChannel_6 extends _i1.SmartFake
+ implements _i2.JavaScriptChannel {
+ _FakeJavaScriptChannel_6(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeWebChromeClient_7 extends _i1.SmartFake
+ implements _i2.WebChromeClient {
+ _FakeWebChromeClient_7(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+class _FakeWebViewClient_8 extends _i1.SmartFake implements _i2.WebViewClient {
+ _FakeWebViewClient_8(
+ Object parent,
+ Invocation parentInvocation,
+ ) : super(
+ parent,
+ parentInvocation,
+ );
+}
+
+/// A class which mocks [FlutterAssetManager].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockFlutterAssetManager extends _i1.Mock
+ implements _i2.FlutterAssetManager {
+ MockFlutterAssetManager() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i5.Future<List<String?>> list(String? path) => (super.noSuchMethod(
+ Invocation.method(
+ #list,
+ [path],
+ ),
+ returnValue: _i5.Future<List<String?>>.value(<String?>[]),
+ ) as _i5.Future<List<String?>>);
+ @override
+ _i5.Future<String> getAssetFilePathByName(String? name) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #getAssetFilePathByName,
+ [name],
+ ),
+ returnValue: _i5.Future<String>.value(''),
+ ) as _i5.Future<String>);
+}
+
+/// A class which mocks [WebSettings].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebSettings extends _i1.Mock implements _i2.WebSettings {
+ MockWebSettings() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i5.Future<void> setDomStorageEnabled(bool? flag) => (super.noSuchMethod(
+ Invocation.method(
+ #setDomStorageEnabled,
+ [flag],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setJavaScriptCanOpenWindowsAutomatically(bool? flag) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setJavaScriptCanOpenWindowsAutomatically,
+ [flag],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setSupportMultipleWindows(bool? support) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setSupportMultipleWindows,
+ [support],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setJavaScriptEnabled(bool? flag) => (super.noSuchMethod(
+ Invocation.method(
+ #setJavaScriptEnabled,
+ [flag],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setUserAgentString(String? userAgentString) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setUserAgentString,
+ [userAgentString],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setMediaPlaybackRequiresUserGesture(bool? require) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setMediaPlaybackRequiresUserGesture,
+ [require],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setSupportZoom(bool? support) => (super.noSuchMethod(
+ Invocation.method(
+ #setSupportZoom,
+ [support],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setLoadWithOverviewMode(bool? overview) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setLoadWithOverviewMode,
+ [overview],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setUseWideViewPort(bool? use) => (super.noSuchMethod(
+ Invocation.method(
+ #setUseWideViewPort,
+ [use],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setDisplayZoomControls(bool? enabled) => (super.noSuchMethod(
+ Invocation.method(
+ #setDisplayZoomControls,
+ [enabled],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setBuiltInZoomControls(bool? enabled) => (super.noSuchMethod(
+ Invocation.method(
+ #setBuiltInZoomControls,
+ [enabled],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setAllowFileAccess(bool? enabled) => (super.noSuchMethod(
+ Invocation.method(
+ #setAllowFileAccess,
+ [enabled],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i2.WebSettings copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebSettings_0(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebSettings);
+}
+
+/// A class which mocks [WebStorage].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebStorage extends _i1.Mock implements _i2.WebStorage {
+ MockWebStorage() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i5.Future<void> deleteAllData() => (super.noSuchMethod(
+ Invocation.method(
+ #deleteAllData,
+ [],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i2.WebStorage copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebStorage_1(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebStorage);
+}
+
+/// A class which mocks [WebView].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebView extends _i1.Mock implements _i2.WebView {
+ MockWebView() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ bool get useHybridComposition => (super.noSuchMethod(
+ Invocation.getter(#useHybridComposition),
+ returnValue: false,
+ ) as bool);
+ @override
+ _i2.WebSettings get settings => (super.noSuchMethod(
+ Invocation.getter(#settings),
+ returnValue: _FakeWebSettings_0(
+ this,
+ Invocation.getter(#settings),
+ ),
+ ) as _i2.WebSettings);
+ @override
+ _i5.Future<void> loadData({
+ required String? data,
+ String? mimeType,
+ String? encoding,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #loadData,
+ [],
+ {
+ #data: data,
+ #mimeType: mimeType,
+ #encoding: encoding,
+ },
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> loadDataWithBaseUrl({
+ String? baseUrl,
+ required String? data,
+ String? mimeType,
+ String? encoding,
+ String? historyUrl,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #loadDataWithBaseUrl,
+ [],
+ {
+ #baseUrl: baseUrl,
+ #data: data,
+ #mimeType: mimeType,
+ #encoding: encoding,
+ #historyUrl: historyUrl,
+ },
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> loadUrl(
+ String? url,
+ Map<String, String>? headers,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #loadUrl,
+ [
+ url,
+ headers,
+ ],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> postUrl(
+ String? url,
+ _i6.Uint8List? data,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #postUrl,
+ [
+ url,
+ data,
+ ],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<String?> getUrl() => (super.noSuchMethod(
+ Invocation.method(
+ #getUrl,
+ [],
+ ),
+ returnValue: _i5.Future<String?>.value(),
+ ) as _i5.Future<String?>);
+ @override
+ _i5.Future<bool> canGoBack() => (super.noSuchMethod(
+ Invocation.method(
+ #canGoBack,
+ [],
+ ),
+ returnValue: _i5.Future<bool>.value(false),
+ ) as _i5.Future<bool>);
+ @override
+ _i5.Future<bool> canGoForward() => (super.noSuchMethod(
+ Invocation.method(
+ #canGoForward,
+ [],
+ ),
+ returnValue: _i5.Future<bool>.value(false),
+ ) as _i5.Future<bool>);
+ @override
+ _i5.Future<void> goBack() => (super.noSuchMethod(
+ Invocation.method(
+ #goBack,
+ [],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> goForward() => (super.noSuchMethod(
+ Invocation.method(
+ #goForward,
+ [],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> reload() => (super.noSuchMethod(
+ Invocation.method(
+ #reload,
+ [],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> clearCache(bool? includeDiskFiles) => (super.noSuchMethod(
+ Invocation.method(
+ #clearCache,
+ [includeDiskFiles],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<String?> evaluateJavascript(String? javascriptString) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #evaluateJavascript,
+ [javascriptString],
+ ),
+ returnValue: _i5.Future<String?>.value(),
+ ) as _i5.Future<String?>);
+ @override
+ _i5.Future<String?> getTitle() => (super.noSuchMethod(
+ Invocation.method(
+ #getTitle,
+ [],
+ ),
+ returnValue: _i5.Future<String?>.value(),
+ ) as _i5.Future<String?>);
+ @override
+ _i5.Future<void> scrollTo(
+ int? x,
+ int? y,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #scrollTo,
+ [
+ x,
+ y,
+ ],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> scrollBy(
+ int? x,
+ int? y,
+ ) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #scrollBy,
+ [
+ x,
+ y,
+ ],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<int> getScrollX() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollX,
+ [],
+ ),
+ returnValue: _i5.Future<int>.value(0),
+ ) as _i5.Future<int>);
+ @override
+ _i5.Future<int> getScrollY() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollY,
+ [],
+ ),
+ returnValue: _i5.Future<int>.value(0),
+ ) as _i5.Future<int>);
+ @override
+ _i5.Future<_i3.Offset> getScrollPosition() => (super.noSuchMethod(
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ returnValue: _i5.Future<_i3.Offset>.value(_FakeOffset_2(
+ this,
+ Invocation.method(
+ #getScrollPosition,
+ [],
+ ),
+ )),
+ ) as _i5.Future<_i3.Offset>);
+ @override
+ _i5.Future<void> setWebViewClient(_i2.WebViewClient? webViewClient) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setWebViewClient,
+ [webViewClient],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> addJavaScriptChannel(
+ _i2.JavaScriptChannel? javaScriptChannel) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #addJavaScriptChannel,
+ [javaScriptChannel],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> removeJavaScriptChannel(
+ _i2.JavaScriptChannel? javaScriptChannel) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #removeJavaScriptChannel,
+ [javaScriptChannel],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setDownloadListener(_i2.DownloadListener? listener) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setDownloadListener,
+ [listener],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setWebChromeClient(_i2.WebChromeClient? client) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setWebChromeClient,
+ [client],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i5.Future<void> setBackgroundColor(_i3.Color? color) => (super.noSuchMethod(
+ Invocation.method(
+ #setBackgroundColor,
+ [color],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i2.WebView copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebView_3(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebView);
+}
+
+/// A class which mocks [WebResourceRequest].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebResourceRequest extends _i1.Mock
+ implements _i2.WebResourceRequest {
+ MockWebResourceRequest() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ String get url => (super.noSuchMethod(
+ Invocation.getter(#url),
+ returnValue: '',
+ ) as String);
+ @override
+ bool get isForMainFrame => (super.noSuchMethod(
+ Invocation.getter(#isForMainFrame),
+ returnValue: false,
+ ) as bool);
+ @override
+ bool get hasGesture => (super.noSuchMethod(
+ Invocation.getter(#hasGesture),
+ returnValue: false,
+ ) as bool);
+ @override
+ String get method => (super.noSuchMethod(
+ Invocation.getter(#method),
+ returnValue: '',
+ ) as String);
+ @override
+ Map<String, String> get requestHeaders => (super.noSuchMethod(
+ Invocation.getter(#requestHeaders),
+ returnValue: <String, String>{},
+ ) as Map<String, String>);
+}
+
+/// A class which mocks [DownloadListener].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockDownloadListener extends _i1.Mock implements _i2.DownloadListener {
+ MockDownloadListener() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ void Function(
+ String,
+ String,
+ String,
+ String,
+ int,
+ ) get onDownloadStart => (super.noSuchMethod(
+ Invocation.getter(#onDownloadStart),
+ returnValue: (
+ String url,
+ String userAgent,
+ String contentDisposition,
+ String mimetype,
+ int contentLength,
+ ) {},
+ ) as void Function(
+ String,
+ String,
+ String,
+ String,
+ int,
+ ));
+ @override
+ _i2.DownloadListener copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeDownloadListener_4(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.DownloadListener);
+}
+
+/// A class which mocks [WebViewAndroidJavaScriptChannel].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewAndroidJavaScriptChannel extends _i1.Mock
+ implements _i7.WebViewAndroidJavaScriptChannel {
+ MockWebViewAndroidJavaScriptChannel() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i4.JavascriptChannelRegistry get javascriptChannelRegistry =>
+ (super.noSuchMethod(
+ Invocation.getter(#javascriptChannelRegistry),
+ returnValue: _FakeJavascriptChannelRegistry_5(
+ this,
+ Invocation.getter(#javascriptChannelRegistry),
+ ),
+ ) as _i4.JavascriptChannelRegistry);
+ @override
+ String get channelName => (super.noSuchMethod(
+ Invocation.getter(#channelName),
+ returnValue: '',
+ ) as String);
+ @override
+ void Function(String) get postMessage => (super.noSuchMethod(
+ Invocation.getter(#postMessage),
+ returnValue: (String message) {},
+ ) as void Function(String));
+ @override
+ _i2.JavaScriptChannel copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeJavaScriptChannel_6(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.JavaScriptChannel);
+}
+
+/// A class which mocks [WebChromeClient].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebChromeClient extends _i1.Mock implements _i2.WebChromeClient {
+ MockWebChromeClient() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i2.WebChromeClient copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebChromeClient_7(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebChromeClient);
+}
+
+/// A class which mocks [WebViewClient].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewClient extends _i1.Mock implements _i2.WebViewClient {
+ MockWebViewClient() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i5.Future<void> setSynchronousReturnValueForShouldOverrideUrlLoading(
+ bool? value) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setSynchronousReturnValueForShouldOverrideUrlLoading,
+ [value],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+ @override
+ _i2.WebViewClient copy() => (super.noSuchMethod(
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ returnValue: _FakeWebViewClient_8(
+ this,
+ Invocation.method(
+ #copy,
+ [],
+ ),
+ ),
+ ) as _i2.WebViewClient);
+}
+
+/// A class which mocks [JavascriptChannelRegistry].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockJavascriptChannelRegistry extends _i1.Mock
+ implements _i4.JavascriptChannelRegistry {
+ MockJavascriptChannelRegistry() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ Map<String, _i4.JavascriptChannel> get channels => (super.noSuchMethod(
+ Invocation.getter(#channels),
+ returnValue: <String, _i4.JavascriptChannel>{},
+ ) as Map<String, _i4.JavascriptChannel>);
+ @override
+ void onJavascriptChannelMessage(
+ String? channel,
+ String? message,
+ ) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #onJavascriptChannelMessage,
+ [
+ channel,
+ message,
+ ],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void updateJavascriptChannelsFromSet(Set<_i4.JavascriptChannel>? channels) =>
+ super.noSuchMethod(
+ Invocation.method(
+ #updateJavascriptChannelsFromSet,
+ [channels],
+ ),
+ returnValueForMissingStub: null,
+ );
+}
+
+/// A class which mocks [WebViewPlatformCallbacksHandler].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewPlatformCallbacksHandler extends _i1.Mock
+ implements _i4.WebViewPlatformCallbacksHandler {
+ MockWebViewPlatformCallbacksHandler() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i5.FutureOr<bool> onNavigationRequest({
+ required String? url,
+ required bool? isForMainFrame,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #onNavigationRequest,
+ [],
+ {
+ #url: url,
+ #isForMainFrame: isForMainFrame,
+ },
+ ),
+ returnValue: _i5.Future<bool>.value(false),
+ ) as _i5.FutureOr<bool>);
+ @override
+ void onPageStarted(String? url) => super.noSuchMethod(
+ Invocation.method(
+ #onPageStarted,
+ [url],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void onPageFinished(String? url) => super.noSuchMethod(
+ Invocation.method(
+ #onPageFinished,
+ [url],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void onProgress(int? progress) => super.noSuchMethod(
+ Invocation.method(
+ #onProgress,
+ [progress],
+ ),
+ returnValueForMissingStub: null,
+ );
+ @override
+ void onWebResourceError(_i4.WebResourceError? error) => super.noSuchMethod(
+ Invocation.method(
+ #onWebResourceError,
+ [error],
+ ),
+ returnValueForMissingStub: null,
+ );
+}
+
+/// A class which mocks [WebViewProxy].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockWebViewProxy extends _i1.Mock implements _i7.WebViewProxy {
+ MockWebViewProxy() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i2.WebView createWebView({required bool? useHybridComposition}) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #createWebView,
+ [],
+ {#useHybridComposition: useHybridComposition},
+ ),
+ returnValue: _FakeWebView_3(
+ this,
+ Invocation.method(
+ #createWebView,
+ [],
+ {#useHybridComposition: useHybridComposition},
+ ),
+ ),
+ ) as _i2.WebView);
+ @override
+ _i2.WebViewClient createWebViewClient({
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageStarted,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ onPageFinished,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ _i2.WebResourceError,
+ )?
+ onReceivedRequestError,
+ void Function(
+ _i2.WebView,
+ int,
+ String,
+ String,
+ )?
+ onReceivedError,
+ void Function(
+ _i2.WebView,
+ _i2.WebResourceRequest,
+ )?
+ requestLoading,
+ void Function(
+ _i2.WebView,
+ String,
+ )?
+ urlLoading,
+ }) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #createWebViewClient,
+ [],
+ {
+ #onPageStarted: onPageStarted,
+ #onPageFinished: onPageFinished,
+ #onReceivedRequestError: onReceivedRequestError,
+ #onReceivedError: onReceivedError,
+ #requestLoading: requestLoading,
+ #urlLoading: urlLoading,
+ },
+ ),
+ returnValue: _FakeWebViewClient_8(
+ this,
+ Invocation.method(
+ #createWebViewClient,
+ [],
+ {
+ #onPageStarted: onPageStarted,
+ #onPageFinished: onPageFinished,
+ #onReceivedRequestError: onReceivedRequestError,
+ #onReceivedError: onReceivedError,
+ #requestLoading: requestLoading,
+ #urlLoading: urlLoading,
+ },
+ ),
+ ),
+ ) as _i2.WebViewClient);
+ @override
+ _i5.Future<void> setWebContentsDebuggingEnabled(bool? enabled) =>
+ (super.noSuchMethod(
+ Invocation.method(
+ #setWebContentsDebuggingEnabled,
+ [enabled],
+ ),
+ returnValue: _i5.Future<void>.value(),
+ returnValueForMissingStub: _i5.Future<void>.value(),
+ ) as _i5.Future<void>);
+}
diff --git a/packages/webview_flutter/webview_flutter_android/test/test_android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/test/test_android_webview.pigeon.dart
index afc80ab..bcfb453 100644
--- a/packages/webview_flutter/webview_flutter_android/test/test_android_webview.pigeon.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/test_android_webview.pigeon.dart
@@ -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 (v4.0.2), do not edit directly.
+// Autogenerated from Pigeon (v4.2.3), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
// ignore_for_file: avoid_relative_lib_imports
@@ -13,12 +13,13 @@
import 'package:webview_flutter_android/src/android_webview.pigeon.dart';
-class _TestJavaObjectHostApiCodec extends StandardMessageCodec {
- const _TestJavaObjectHostApiCodec();
-}
-
+/// Handles methods calls to the native Java Object class.
+///
+/// Also handles calls to remove the reference to an instance with `dispose`.
+///
+/// See https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html.
abstract class TestJavaObjectHostApi {
- static const MessageCodec<Object?> codec = _TestJavaObjectHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
void dispose(int identifier);
static void setup(TestJavaObjectHostApi? api,
@@ -73,7 +74,6 @@
static const MessageCodec<Object?> codec = _TestWebViewHostApiCodec();
void create(int instanceId, bool useHybridComposition);
- void dispose(int instanceId);
void loadData(
int instanceId, String data, String? mimeType, String? encoding);
void loadDataWithBaseUrl(int instanceId, String? baseUrl, String data,
@@ -127,25 +127,6 @@
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.WebViewHostApi.dispose', codec,
- binaryMessenger: binaryMessenger);
- if (api == null) {
- channel.setMockMessageHandler(null);
- } else {
- channel.setMockMessageHandler((Object? message) async {
- assert(message != null,
- 'Argument for dev.flutter.pigeon.WebViewHostApi.dispose was null.');
- final List<Object?> args = (message as List<Object?>?)!;
- final int? arg_instanceId = (args[0] as int?);
- assert(arg_instanceId != null,
- 'Argument for dev.flutter.pigeon.WebViewHostApi.dispose was null, expected non-null int.');
- api.dispose(arg_instanceId!);
- return <Object?, Object?>{};
- });
- }
- }
- {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebViewHostApi.loadData', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
@@ -684,15 +665,10 @@
}
}
-class _TestWebSettingsHostApiCodec extends StandardMessageCodec {
- const _TestWebSettingsHostApiCodec();
-}
-
abstract class TestWebSettingsHostApi {
- static const MessageCodec<Object?> codec = _TestWebSettingsHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
void create(int instanceId, int webViewInstanceId);
- void dispose(int instanceId);
void setDomStorageEnabled(int instanceId, bool flag);
void setJavaScriptCanOpenWindowsAutomatically(int instanceId, bool flag);
void setSupportMultipleWindows(int instanceId, bool support);
@@ -731,25 +707,6 @@
}
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.WebSettingsHostApi.dispose', codec,
- binaryMessenger: binaryMessenger);
- if (api == null) {
- channel.setMockMessageHandler(null);
- } else {
- channel.setMockMessageHandler((Object? message) async {
- assert(message != null,
- 'Argument for dev.flutter.pigeon.WebSettingsHostApi.dispose was null.');
- final List<Object?> args = (message as List<Object?>?)!;
- final int? arg_instanceId = (args[0] as int?);
- assert(arg_instanceId != null,
- 'Argument for dev.flutter.pigeon.WebSettingsHostApi.dispose was null, expected non-null int.');
- api.dispose(arg_instanceId!);
- return <Object?, Object?>{};
- });
- }
- }
- {
- final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
@@ -1019,13 +976,8 @@
}
}
-class _TestJavaScriptChannelHostApiCodec extends StandardMessageCodec {
- const _TestJavaScriptChannelHostApiCodec();
-}
-
abstract class TestJavaScriptChannelHostApi {
- static const MessageCodec<Object?> codec =
- _TestJavaScriptChannelHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
void create(int instanceId, String channelName);
static void setup(TestJavaScriptChannelHostApi? api,
@@ -1055,14 +1007,12 @@
}
}
-class _TestWebViewClientHostApiCodec extends StandardMessageCodec {
- const _TestWebViewClientHostApiCodec();
-}
-
abstract class TestWebViewClientHostApi {
- static const MessageCodec<Object?> codec = _TestWebViewClientHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
- void create(int instanceId, bool shouldOverrideUrlLoading);
+ void create(int instanceId);
+ void setSynchronousReturnValueForShouldOverrideUrlLoading(
+ int instanceId, bool value);
static void setup(TestWebViewClientHostApi? api,
{BinaryMessenger? binaryMessenger}) {
{
@@ -1079,10 +1029,31 @@
final int? arg_instanceId = (args[0] as int?);
assert(arg_instanceId != null,
'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null, expected non-null int.');
- final bool? arg_shouldOverrideUrlLoading = (args[1] as bool?);
- assert(arg_shouldOverrideUrlLoading != null,
- 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null, expected non-null bool.');
- api.create(arg_instanceId!, arg_shouldOverrideUrlLoading!);
+ api.create(arg_instanceId!);
+ return <Object?, Object?>{};
+ });
+ }
+ }
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.WebViewClientHostApi.setSynchronousReturnValueForShouldOverrideUrlLoading',
+ codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.WebViewClientHostApi.setSynchronousReturnValueForShouldOverrideUrlLoading was null.');
+ final List<Object?> args = (message as List<Object?>?)!;
+ final int? arg_instanceId = (args[0] as int?);
+ assert(arg_instanceId != null,
+ 'Argument for dev.flutter.pigeon.WebViewClientHostApi.setSynchronousReturnValueForShouldOverrideUrlLoading was null, expected non-null int.');
+ final bool? arg_value = (args[1] as bool?);
+ assert(arg_value != null,
+ 'Argument for dev.flutter.pigeon.WebViewClientHostApi.setSynchronousReturnValueForShouldOverrideUrlLoading was null, expected non-null bool.');
+ api.setSynchronousReturnValueForShouldOverrideUrlLoading(
+ arg_instanceId!, arg_value!);
return <Object?, Object?>{};
});
}
@@ -1090,13 +1061,8 @@
}
}
-class _TestDownloadListenerHostApiCodec extends StandardMessageCodec {
- const _TestDownloadListenerHostApiCodec();
-}
-
abstract class TestDownloadListenerHostApi {
- static const MessageCodec<Object?> codec =
- _TestDownloadListenerHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
void create(int instanceId);
static void setup(TestDownloadListenerHostApi? api,
@@ -1123,14 +1089,10 @@
}
}
-class _TestWebChromeClientHostApiCodec extends StandardMessageCodec {
- const _TestWebChromeClientHostApiCodec();
-}
-
abstract class TestWebChromeClientHostApi {
- static const MessageCodec<Object?> codec = _TestWebChromeClientHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
- void create(int instanceId, int webViewClientInstanceId);
+ void create(int instanceId);
static void setup(TestWebChromeClientHostApi? api,
{BinaryMessenger? binaryMessenger}) {
{
@@ -1147,10 +1109,7 @@
final int? arg_instanceId = (args[0] as int?);
assert(arg_instanceId != null,
'Argument for dev.flutter.pigeon.WebChromeClientHostApi.create was null, expected non-null int.');
- final int? arg_webViewClientInstanceId = (args[1] as int?);
- assert(arg_webViewClientInstanceId != null,
- 'Argument for dev.flutter.pigeon.WebChromeClientHostApi.create was null, expected non-null int.');
- api.create(arg_instanceId!, arg_webViewClientInstanceId!);
+ api.create(arg_instanceId!);
return <Object?, Object?>{};
});
}
@@ -1158,12 +1117,8 @@
}
}
-class _TestAssetManagerHostApiCodec extends StandardMessageCodec {
- const _TestAssetManagerHostApiCodec();
-}
-
abstract class TestAssetManagerHostApi {
- static const MessageCodec<Object?> codec = _TestAssetManagerHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
List<String?> list(String path);
String getAssetFilePathByName(String name);
@@ -1211,12 +1166,8 @@
}
}
-class _TestWebStorageHostApiCodec extends StandardMessageCodec {
- const _TestWebStorageHostApiCodec();
-}
-
abstract class TestWebStorageHostApi {
- static const MessageCodec<Object?> codec = _TestWebStorageHostApiCodec();
+ static const MessageCodec<Object?> codec = StandardMessageCodec();
void create(int instanceId);
void deleteAllData(int instanceId);
diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.mocks.dart
deleted file mode 100644
index 308aba4..0000000
--- a/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.mocks.dart
+++ /dev/null
@@ -1,37 +0,0 @@
-// Mocks generated by Mockito 5.2.0 from annotations
-// in webview_flutter_android/test/webview_android_cookie_manager_test.dart.
-// Do not manually edit this file.
-
-import 'dart:async' as _i3;
-
-import 'package:mockito/mockito.dart' as _i1;
-import 'package:webview_flutter_android/src/android_webview.dart' as _i2;
-
-// ignore_for_file: type=lint
-// ignore_for_file: avoid_redundant_argument_values
-// ignore_for_file: avoid_setters_without_getters
-// ignore_for_file: comment_references
-// ignore_for_file: implementation_imports
-// ignore_for_file: invalid_use_of_visible_for_testing_member
-// ignore_for_file: prefer_const_constructors
-// ignore_for_file: unnecessary_parenthesis
-// ignore_for_file: camel_case_types
-
-/// A class which mocks [CookieManager].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockCookieManager extends _i1.Mock implements _i2.CookieManager {
- MockCookieManager() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i3.Future<void> setCookie(String? url, String? value) =>
- (super.noSuchMethod(Invocation.method(#setCookie, [url, value]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i3.Future<void>);
- @override
- _i3.Future<bool> clearCookies() =>
- (super.noSuchMethod(Invocation.method(#clearCookies, []),
- returnValue: Future<bool>.value(false)) as _i3.Future<bool>);
-}
diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.mocks.dart b/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.mocks.dart
deleted file mode 100644
index acaff1c..0000000
--- a/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.mocks.dart
+++ /dev/null
@@ -1,572 +0,0 @@
-// Mocks generated by Mockito 5.2.0 from annotations
-// in webview_flutter_android/test/webview_android_widget_test.dart.
-// Do not manually edit this file.
-
-import 'dart:async' as _i5;
-import 'dart:typed_data' as _i6;
-import 'dart:ui' as _i3;
-
-import 'package:mockito/mockito.dart' as _i1;
-import 'package:webview_flutter_android/src/android_webview.dart' as _i2;
-import 'package:webview_flutter_android/webview_android_widget.dart' as _i7;
-import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'
- as _i4;
-
-// ignore_for_file: type=lint
-// ignore_for_file: avoid_redundant_argument_values
-// ignore_for_file: avoid_setters_without_getters
-// ignore_for_file: comment_references
-// ignore_for_file: implementation_imports
-// ignore_for_file: invalid_use_of_visible_for_testing_member
-// ignore_for_file: prefer_const_constructors
-// ignore_for_file: unnecessary_parenthesis
-// ignore_for_file: camel_case_types
-
-class _FakeWebSettings_0 extends _i1.Fake implements _i2.WebSettings {}
-
-class _FakeWebStorage_1 extends _i1.Fake implements _i2.WebStorage {}
-
-class _FakeOffset_2 extends _i1.Fake implements _i3.Offset {}
-
-class _FakeWebView_3 extends _i1.Fake implements _i2.WebView {}
-
-class _FakeDownloadListener_4 extends _i1.Fake
- implements _i2.DownloadListener {}
-
-class _FakeJavascriptChannelRegistry_5 extends _i1.Fake
- implements _i4.JavascriptChannelRegistry {}
-
-class _FakeJavaScriptChannel_6 extends _i1.Fake
- implements _i2.JavaScriptChannel {}
-
-class _FakeWebChromeClient_7 extends _i1.Fake implements _i2.WebChromeClient {}
-
-class _FakeWebViewClient_8 extends _i1.Fake implements _i2.WebViewClient {}
-
-/// A class which mocks [FlutterAssetManager].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockFlutterAssetManager extends _i1.Mock
- implements _i2.FlutterAssetManager {
- MockFlutterAssetManager() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i5.Future<List<String?>> list(String? path) =>
- (super.noSuchMethod(Invocation.method(#list, [path]),
- returnValue: Future<List<String?>>.value(<String?>[]))
- as _i5.Future<List<String?>>);
- @override
- _i5.Future<String> getAssetFilePathByName(String? name) =>
- (super.noSuchMethod(Invocation.method(#getAssetFilePathByName, [name]),
- returnValue: Future<String>.value('')) as _i5.Future<String>);
-}
-
-/// A class which mocks [WebSettings].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebSettings extends _i1.Mock implements _i2.WebSettings {
- MockWebSettings() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i5.Future<void> setDomStorageEnabled(bool? flag) =>
- (super.noSuchMethod(Invocation.method(#setDomStorageEnabled, [flag]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setJavaScriptCanOpenWindowsAutomatically(bool? flag) =>
- (super.noSuchMethod(
- Invocation.method(#setJavaScriptCanOpenWindowsAutomatically, [flag]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setSupportMultipleWindows(bool? support) => (super
- .noSuchMethod(Invocation.method(#setSupportMultipleWindows, [support]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setJavaScriptEnabled(bool? flag) =>
- (super.noSuchMethod(Invocation.method(#setJavaScriptEnabled, [flag]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setUserAgentString(String? userAgentString) => (super
- .noSuchMethod(Invocation.method(#setUserAgentString, [userAgentString]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setMediaPlaybackRequiresUserGesture(bool? require) =>
- (super.noSuchMethod(
- Invocation.method(#setMediaPlaybackRequiresUserGesture, [require]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setSupportZoom(bool? support) =>
- (super.noSuchMethod(Invocation.method(#setSupportZoom, [support]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setLoadWithOverviewMode(bool? overview) => (super
- .noSuchMethod(Invocation.method(#setLoadWithOverviewMode, [overview]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setUseWideViewPort(bool? use) =>
- (super.noSuchMethod(Invocation.method(#setUseWideViewPort, [use]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setDisplayZoomControls(bool? enabled) =>
- (super.noSuchMethod(Invocation.method(#setDisplayZoomControls, [enabled]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setBuiltInZoomControls(bool? enabled) =>
- (super.noSuchMethod(Invocation.method(#setBuiltInZoomControls, [enabled]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setAllowFileAccess(bool? enabled) =>
- (super.noSuchMethod(Invocation.method(#setAllowFileAccess, [enabled]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i2.WebSettings copy() => (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeWebSettings_0()) as _i2.WebSettings);
-}
-
-/// A class which mocks [WebStorage].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebStorage extends _i1.Mock implements _i2.WebStorage {
- MockWebStorage() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i5.Future<void> deleteAllData() =>
- (super.noSuchMethod(Invocation.method(#deleteAllData, []),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i2.WebStorage copy() => (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeWebStorage_1()) as _i2.WebStorage);
-}
-
-/// A class which mocks [WebView].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebView extends _i1.Mock implements _i2.WebView {
- MockWebView() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- bool get useHybridComposition =>
- (super.noSuchMethod(Invocation.getter(#useHybridComposition),
- returnValue: false) as bool);
- @override
- _i2.WebSettings get settings =>
- (super.noSuchMethod(Invocation.getter(#settings),
- returnValue: _FakeWebSettings_0()) as _i2.WebSettings);
- @override
- _i5.Future<void> loadData(
- {String? data, String? mimeType, String? encoding}) =>
- (super.noSuchMethod(
- Invocation.method(#loadData, [],
- {#data: data, #mimeType: mimeType, #encoding: encoding}),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> loadDataWithBaseUrl(
- {String? baseUrl,
- String? data,
- String? mimeType,
- String? encoding,
- String? historyUrl}) =>
- (super.noSuchMethod(
- Invocation.method(#loadDataWithBaseUrl, [], {
- #baseUrl: baseUrl,
- #data: data,
- #mimeType: mimeType,
- #encoding: encoding,
- #historyUrl: historyUrl
- }),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> loadUrl(String? url, Map<String, String>? headers) =>
- (super.noSuchMethod(Invocation.method(#loadUrl, [url, headers]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> postUrl(String? url, _i6.Uint8List? data) =>
- (super.noSuchMethod(Invocation.method(#postUrl, [url, data]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<String?> getUrl() =>
- (super.noSuchMethod(Invocation.method(#getUrl, []),
- returnValue: Future<String?>.value()) as _i5.Future<String?>);
- @override
- _i5.Future<bool> canGoBack() =>
- (super.noSuchMethod(Invocation.method(#canGoBack, []),
- returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
- @override
- _i5.Future<bool> canGoForward() =>
- (super.noSuchMethod(Invocation.method(#canGoForward, []),
- returnValue: Future<bool>.value(false)) as _i5.Future<bool>);
- @override
- _i5.Future<void> goBack() =>
- (super.noSuchMethod(Invocation.method(#goBack, []),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> goForward() =>
- (super.noSuchMethod(Invocation.method(#goForward, []),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> reload() =>
- (super.noSuchMethod(Invocation.method(#reload, []),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> clearCache(bool? includeDiskFiles) =>
- (super.noSuchMethod(Invocation.method(#clearCache, [includeDiskFiles]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<String?> evaluateJavascript(String? javascriptString) => (super
- .noSuchMethod(Invocation.method(#evaluateJavascript, [javascriptString]),
- returnValue: Future<String?>.value()) as _i5.Future<String?>);
- @override
- _i5.Future<String?> getTitle() =>
- (super.noSuchMethod(Invocation.method(#getTitle, []),
- returnValue: Future<String?>.value()) as _i5.Future<String?>);
- @override
- _i5.Future<void> scrollTo(int? x, int? y) =>
- (super.noSuchMethod(Invocation.method(#scrollTo, [x, y]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> scrollBy(int? x, int? y) =>
- (super.noSuchMethod(Invocation.method(#scrollBy, [x, y]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<int> getScrollX() =>
- (super.noSuchMethod(Invocation.method(#getScrollX, []),
- returnValue: Future<int>.value(0)) as _i5.Future<int>);
- @override
- _i5.Future<int> getScrollY() =>
- (super.noSuchMethod(Invocation.method(#getScrollY, []),
- returnValue: Future<int>.value(0)) as _i5.Future<int>);
- @override
- _i5.Future<_i3.Offset> getScrollPosition() =>
- (super.noSuchMethod(Invocation.method(#getScrollPosition, []),
- returnValue: Future<_i3.Offset>.value(_FakeOffset_2()))
- as _i5.Future<_i3.Offset>);
- @override
- _i5.Future<void> setWebViewClient(_i2.WebViewClient? webViewClient) =>
- (super.noSuchMethod(Invocation.method(#setWebViewClient, [webViewClient]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> addJavaScriptChannel(
- _i2.JavaScriptChannel? javaScriptChannel) =>
- (super.noSuchMethod(
- Invocation.method(#addJavaScriptChannel, [javaScriptChannel]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> removeJavaScriptChannel(
- _i2.JavaScriptChannel? javaScriptChannel) =>
- (super.noSuchMethod(
- Invocation.method(#removeJavaScriptChannel, [javaScriptChannel]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setDownloadListener(_i2.DownloadListener? listener) =>
- (super.noSuchMethod(Invocation.method(#setDownloadListener, [listener]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setWebChromeClient(_i2.WebChromeClient? client) =>
- (super.noSuchMethod(Invocation.method(#setWebChromeClient, [client]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> setBackgroundColor(_i3.Color? color) =>
- (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i5.Future<void> release() =>
- (super.noSuchMethod(Invocation.method(#release, []),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
- @override
- _i2.WebView copy() => (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeWebView_3()) as _i2.WebView);
-}
-
-/// A class which mocks [WebResourceRequest].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebResourceRequest extends _i1.Mock
- implements _i2.WebResourceRequest {
- MockWebResourceRequest() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- String get url =>
- (super.noSuchMethod(Invocation.getter(#url), returnValue: '') as String);
- @override
- bool get isForMainFrame => (super
- .noSuchMethod(Invocation.getter(#isForMainFrame), returnValue: false)
- as bool);
- @override
- bool get hasGesture =>
- (super.noSuchMethod(Invocation.getter(#hasGesture), returnValue: false)
- as bool);
- @override
- String get method =>
- (super.noSuchMethod(Invocation.getter(#method), returnValue: '')
- as String);
- @override
- Map<String, String> get requestHeaders =>
- (super.noSuchMethod(Invocation.getter(#requestHeaders),
- returnValue: <String, String>{}) as Map<String, String>);
-}
-
-/// A class which mocks [WebViewAndroidDownloadListener].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebViewAndroidDownloadListener extends _i1.Mock
- implements _i7.WebViewAndroidDownloadListener {
- MockWebViewAndroidDownloadListener() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i5.Future<void> Function(String, Map<String, String>?) get loadUrl =>
- (super.noSuchMethod(Invocation.getter(#loadUrl),
- returnValue: (String url, Map<String, String>? headers) =>
- Future<void>.value()) as _i5.Future<void> Function(
- String, Map<String, String>?));
- @override
- void onDownloadStart(String? url, String? userAgent,
- String? contentDisposition, String? mimetype, int? contentLength) =>
- super.noSuchMethod(
- Invocation.method(#onDownloadStart,
- [url, userAgent, contentDisposition, mimetype, contentLength]),
- returnValueForMissingStub: null);
- @override
- _i2.DownloadListener copy() =>
- (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeDownloadListener_4()) as _i2.DownloadListener);
-}
-
-/// A class which mocks [WebViewAndroidJavaScriptChannel].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebViewAndroidJavaScriptChannel extends _i1.Mock
- implements _i7.WebViewAndroidJavaScriptChannel {
- MockWebViewAndroidJavaScriptChannel() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i4.JavascriptChannelRegistry get javascriptChannelRegistry =>
- (super.noSuchMethod(Invocation.getter(#javascriptChannelRegistry),
- returnValue: _FakeJavascriptChannelRegistry_5())
- as _i4.JavascriptChannelRegistry);
- @override
- String get channelName =>
- (super.noSuchMethod(Invocation.getter(#channelName), returnValue: '')
- as String);
- @override
- void postMessage(String? message) =>
- super.noSuchMethod(Invocation.method(#postMessage, [message]),
- returnValueForMissingStub: null);
- @override
- _i2.JavaScriptChannel copy() =>
- (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeJavaScriptChannel_6()) as _i2.JavaScriptChannel);
-}
-
-/// A class which mocks [WebViewAndroidWebChromeClient].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebViewAndroidWebChromeClient extends _i1.Mock
- implements _i7.WebViewAndroidWebChromeClient {
- MockWebViewAndroidWebChromeClient() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- void onProgressChanged(_i2.WebView? webView, int? progress) => super
- .noSuchMethod(Invocation.method(#onProgressChanged, [webView, progress]),
- returnValueForMissingStub: null);
- @override
- _i2.WebChromeClient copy() =>
- (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeWebChromeClient_7()) as _i2.WebChromeClient);
-}
-
-/// A class which mocks [WebViewAndroidWebViewClient].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebViewAndroidWebViewClient extends _i1.Mock
- implements _i7.WebViewAndroidWebViewClient {
- MockWebViewAndroidWebViewClient() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- void Function(String) get onPageStartedCallback =>
- (super.noSuchMethod(Invocation.getter(#onPageStartedCallback),
- returnValue: (String url) {}) as void Function(String));
- @override
- void Function(String) get onPageFinishedCallback =>
- (super.noSuchMethod(Invocation.getter(#onPageFinishedCallback),
- returnValue: (String url) {}) as void Function(String));
- @override
- void Function(_i4.WebResourceError) get onWebResourceErrorCallback =>
- (super.noSuchMethod(Invocation.getter(#onWebResourceErrorCallback),
- returnValue: (_i4.WebResourceError error) {})
- as void Function(_i4.WebResourceError));
- @override
- set onWebResourceErrorCallback(
- void Function(_i4.WebResourceError)? _onWebResourceErrorCallback) =>
- super.noSuchMethod(
- Invocation.setter(
- #onWebResourceErrorCallback, _onWebResourceErrorCallback),
- returnValueForMissingStub: null);
- @override
- bool get handlesNavigation =>
- (super.noSuchMethod(Invocation.getter(#handlesNavigation),
- returnValue: false) as bool);
- @override
- bool get shouldOverrideUrlLoading =>
- (super.noSuchMethod(Invocation.getter(#shouldOverrideUrlLoading),
- returnValue: false) as bool);
- @override
- void onPageStarted(_i2.WebView? webView, String? url) =>
- super.noSuchMethod(Invocation.method(#onPageStarted, [webView, url]),
- returnValueForMissingStub: null);
- @override
- void onPageFinished(_i2.WebView? webView, String? url) =>
- super.noSuchMethod(Invocation.method(#onPageFinished, [webView, url]),
- returnValueForMissingStub: null);
- @override
- void onReceivedError(_i2.WebView? webView, int? errorCode,
- String? description, String? failingUrl) =>
- super.noSuchMethod(
- Invocation.method(
- #onReceivedError, [webView, errorCode, description, failingUrl]),
- returnValueForMissingStub: null);
- @override
- void onReceivedRequestError(_i2.WebView? webView,
- _i2.WebResourceRequest? request, _i2.WebResourceError? error) =>
- super.noSuchMethod(
- Invocation.method(#onReceivedRequestError, [webView, request, error]),
- returnValueForMissingStub: null);
- @override
- void urlLoading(_i2.WebView? webView, String? url) =>
- super.noSuchMethod(Invocation.method(#urlLoading, [webView, url]),
- returnValueForMissingStub: null);
- @override
- void requestLoading(_i2.WebView? webView, _i2.WebResourceRequest? request) =>
- super.noSuchMethod(Invocation.method(#requestLoading, [webView, request]),
- returnValueForMissingStub: null);
- @override
- _i2.WebViewClient copy() => (super.noSuchMethod(Invocation.method(#copy, []),
- returnValue: _FakeWebViewClient_8()) as _i2.WebViewClient);
-}
-
-/// A class which mocks [JavascriptChannelRegistry].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockJavascriptChannelRegistry extends _i1.Mock
- implements _i4.JavascriptChannelRegistry {
- MockJavascriptChannelRegistry() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- Map<String, _i4.JavascriptChannel> get channels =>
- (super.noSuchMethod(Invocation.getter(#channels),
- returnValue: <String, _i4.JavascriptChannel>{})
- as Map<String, _i4.JavascriptChannel>);
- @override
- void onJavascriptChannelMessage(String? channel, String? message) =>
- super.noSuchMethod(
- Invocation.method(#onJavascriptChannelMessage, [channel, message]),
- returnValueForMissingStub: null);
- @override
- void updateJavascriptChannelsFromSet(Set<_i4.JavascriptChannel>? channels) =>
- super.noSuchMethod(
- Invocation.method(#updateJavascriptChannelsFromSet, [channels]),
- returnValueForMissingStub: null);
-}
-
-/// A class which mocks [WebViewPlatformCallbacksHandler].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebViewPlatformCallbacksHandler extends _i1.Mock
- implements _i4.WebViewPlatformCallbacksHandler {
- MockWebViewPlatformCallbacksHandler() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i5.FutureOr<bool> onNavigationRequest({String? url, bool? isForMainFrame}) =>
- (super.noSuchMethod(
- Invocation.method(#onNavigationRequest, [],
- {#url: url, #isForMainFrame: isForMainFrame}),
- returnValue: Future<bool>.value(false)) as _i5.FutureOr<bool>);
- @override
- void onPageStarted(String? url) =>
- super.noSuchMethod(Invocation.method(#onPageStarted, [url]),
- returnValueForMissingStub: null);
- @override
- void onPageFinished(String? url) =>
- super.noSuchMethod(Invocation.method(#onPageFinished, [url]),
- returnValueForMissingStub: null);
- @override
- void onProgress(int? progress) =>
- super.noSuchMethod(Invocation.method(#onProgress, [progress]),
- returnValueForMissingStub: null);
- @override
- void onWebResourceError(_i4.WebResourceError? error) =>
- super.noSuchMethod(Invocation.method(#onWebResourceError, [error]),
- returnValueForMissingStub: null);
-}
-
-/// A class which mocks [WebViewProxy].
-///
-/// See the documentation for Mockito's code generation for more information.
-class MockWebViewProxy extends _i1.Mock implements _i7.WebViewProxy {
- MockWebViewProxy() {
- _i1.throwOnMissingStub(this);
- }
-
- @override
- _i2.WebView createWebView({bool? useHybridComposition}) =>
- (super.noSuchMethod(
- Invocation.method(#createWebView, [],
- {#useHybridComposition: useHybridComposition}),
- returnValue: _FakeWebView_3()) as _i2.WebView);
- @override
- _i5.Future<void> setWebContentsDebuggingEnabled(bool? enabled) =>
- (super.noSuchMethod(
- Invocation.method(#setWebContentsDebuggingEnabled, [enabled]),
- returnValue: Future<void>.value(),
- returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
-}
diff --git a/script/configs/exclude_all_plugins_app.yaml b/script/configs/exclude_all_plugins_app.yaml
index 62b20d9..bf00b6c 100644
--- a/script/configs/exclude_all_plugins_app.yaml
+++ b/script/configs/exclude_all_plugins_app.yaml
@@ -8,4 +8,8 @@
# This is a permament entry, as it should never be a direct app dependency.
- plugin_platform_interface
+# Packages below are temporarily added to push and release a new webview
+# interface. Remove packages with release of `webview_flutter` 4.0.0. See
+# https://github.com/flutter/flutter/issues/94051.
- webview_flutter_platform_interface
+- webview_flutter_android