[webview_flutter_android] Clear local storage when `clearCache` is called (#5086)
diff --git a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart
index 02ee197..70e8179 100644
--- a/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter/example/integration_test/webview_flutter_test.dart
@@ -1217,6 +1217,52 @@
},
skip: _skipDueToIssue86757,
);
+
+ testWidgets(
+ 'clearCache should clear local storage',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final Completer<void> onPageFinished = Completer<void>();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: primaryUrl,
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageFinished: (_) => onPageFinished.complete(),
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ ),
+ ),
+ );
+
+ final WebViewController controller = await controllerCompleter.future;
+ await onPageFinished.future;
+
+ await controller.runJavascript('localStorage.setItem("myCat", "Tom");');
+
+ expect(
+ controller.runJavascriptReturningResult(
+ 'localStorage.getItem("myCat");',
+ ),
+ completion(_webviewString('Tom')),
+ );
+
+ await controller.clearCache();
+
+ expect(
+ controller.runJavascriptReturningResult(
+ 'localStorage.getItem("myCat");',
+ ),
+ completion(_webviewNull()),
+ );
+ },
+ // TODO(bparrishMines): Unskip once https://github.com/flutter/plugins/pull/5086 lands and is published.
+ skip: Platform.isAndroid,
+ );
}
// JavaScript booleans evaluate to different string values on Android and iOS.
@@ -1228,6 +1274,24 @@
return value ? 'true' : 'false';
}
+// JavaScript `null` evaluate to different string values on Android and iOS.
+// This utility method returns the string boolean value of the current platform.
+String _webviewNull() {
+ if (defaultTargetPlatform == TargetPlatform.iOS) {
+ return '<null>';
+ }
+ return 'null';
+}
+
+// JavaScript String evaluate to different string values on Android and iOS.
+// This utility method returns the string boolean value of the current platform.
+String _webviewString(String value) {
+ if (defaultTargetPlatform == TargetPlatform.iOS) {
+ return value;
+ }
+ return '"$value"';
+}
+
/// 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;');
diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
index 12d20b0..ad81b0f 100644
--- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md
@@ -1,6 +1,8 @@
-## NEXT
+## 2.8.4
* Fixes bug preventing `mockito` code generation for tests.
+* Fixes regression where local storage wasn't cleared when `WebViewController.clearCache` was
+ called.
## 2.8.3
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 15b78b7..afca5ee 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
@@ -2199,6 +2199,80 @@
}
}
+ 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(Long instanceId);
+
+ void deleteAllData(Long instanceId);
+
+ /** The codec used by WebStorageHostApi. */
+ static MessageCodec<Object> getCodec() {
+ return WebStorageHostApiCodec.INSTANCE;
+ }
+
+ /**
+ * Sets up an instance of `WebStorageHostApi` to handle messages through the `binaryMessenger`.
+ */
+ static void setup(BinaryMessenger binaryMessenger, WebStorageHostApi api) {
+ {
+ BasicMessageChannel<Object> channel =
+ new BasicMessageChannel<>(
+ binaryMessenger, "dev.flutter.pigeon.WebStorageHostApi.create", 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.create(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.WebStorageHostApi.deleteAllData", 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.deleteAllData(instanceIdArg.longValue());
+ wrapped.put("result", null);
+ } catch (Error | RuntimeException exception) {
+ wrapped.put("error", wrapError(exception));
+ }
+ reply.reply(wrapped);
+ });
+ } else {
+ channel.setMessageHandler(null);
+ }
+ }
+ }
+ }
+
private static Map<String, Object> wrapError(Throwable exception) {
Map<String, Object> errorMap = new HashMap<>();
errorMap.put("message", exception.toString());
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebStorageHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebStorageHostApiImpl.java
new file mode 100644
index 0000000..42e7603
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebStorageHostApiImpl.java
@@ -0,0 +1,53 @@
+// 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;
+
+import android.webkit.WebStorage;
+import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebStorageHostApi;
+
+/**
+ * Host api implementation for {@link WebStorage}.
+ *
+ * <p>Handles creating {@link WebStorage}s that intercommunicate with a paired Dart object.
+ */
+public class WebStorageHostApiImpl implements WebStorageHostApi {
+ private final InstanceManager instanceManager;
+ private final WebStorageCreator webStorageCreator;
+
+ /** Handles creating {@link WebStorage} for a {@link WebStorageHostApiImpl}. */
+ public static class WebStorageCreator {
+ /**
+ * Creates a {@link WebStorage}.
+ *
+ * @return the created {@link WebStorage}. Defaults to {@link WebStorage#getInstance}
+ */
+ public WebStorage createWebStorage() {
+ return WebStorage.getInstance();
+ }
+ }
+
+ /**
+ * Creates a host API that handles creating {@link WebStorage} and invoke its methods.
+ *
+ * @param instanceManager maintains instances stored to communicate with Dart objects
+ * @param webStorageCreator handles creating {@link WebStorage}s
+ */
+ public WebStorageHostApiImpl(
+ InstanceManager instanceManager, WebStorageCreator webStorageCreator) {
+ this.instanceManager = instanceManager;
+ this.webStorageCreator = webStorageCreator;
+ }
+
+ @Override
+ public void create(Long instanceId) {
+ instanceManager.addInstance(webStorageCreator.createWebStorage(), instanceId);
+ }
+
+ @Override
+ public void deleteAllData(Long instanceId) {
+ final WebStorage webStorage = (WebStorage) instanceManager.getInstance(instanceId);
+ webStorage.deleteAllData();
+ }
+}
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 4ef622f..67202eb 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
@@ -19,6 +19,7 @@
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebSettingsHostApi;
+import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebStorageHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewClientHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewHostApi;
@@ -116,6 +117,9 @@
FlutterAssetManagerHostApi.setup(
binaryMessenger, new FlutterAssetManagerHostApiImpl(flutterAssetManager));
CookieManagerHostApi.setup(binaryMessenger, new CookieManagerHostApiImpl());
+ WebStorageHostApi.setup(
+ binaryMessenger,
+ new WebStorageHostApiImpl(instanceManager, new WebStorageHostApiImpl.WebStorageCreator()));
}
@Override
diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebStorageHostApiImplTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebStorageHostApiImplTest.java
new file mode 100644
index 0000000..e2845c2
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/WebStorageHostApiImplTest.java
@@ -0,0 +1,41 @@
+// 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;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.webkit.WebStorage;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+public class WebStorageHostApiImplTest {
+ @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ @Mock public WebStorage mockWebStorage;
+
+ @Mock WebStorageHostApiImpl.WebStorageCreator mockWebStorageCreator;
+
+ InstanceManager testInstanceManager;
+ WebStorageHostApiImpl testHostApiImpl;
+
+ @Before
+ public void setUp() {
+ testInstanceManager = new InstanceManager();
+ when(mockWebStorageCreator.createWebStorage()).thenReturn(mockWebStorage);
+ testHostApiImpl = new WebStorageHostApiImpl(testInstanceManager, mockWebStorageCreator);
+ testHostApiImpl.create(0L);
+ }
+
+ @Test
+ public void deleteAllData() {
+ testHostApiImpl.deleteAllData(0L);
+ verify(mockWebStorage).deleteAllData();
+ }
+}
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 58f2f36..f1e9528 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
@@ -1377,6 +1377,50 @@
);
},
);
+
+ testWidgets(
+ 'clearCache should clear local storage',
+ (WidgetTester tester) async {
+ final Completer<WebViewController> controllerCompleter =
+ Completer<WebViewController>();
+ final Completer<void> onPageFinished = Completer<void>();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: WebView(
+ key: GlobalKey(),
+ initialUrl: primaryUrl,
+ javascriptMode: JavascriptMode.unrestricted,
+ onPageFinished: (_) => onPageFinished.complete(),
+ onWebViewCreated: (WebViewController controller) {
+ controllerCompleter.complete(controller);
+ },
+ ),
+ ),
+ );
+
+ final WebViewController controller = await controllerCompleter.future;
+ await onPageFinished.future;
+
+ await controller.runJavascript('localStorage.setItem("myCat", "Tom");');
+
+ expect(
+ controller.runJavascriptReturningResult(
+ 'localStorage.getItem("myCat");',
+ ),
+ completion('"Tom"'),
+ );
+
+ await controller.clearCache();
+
+ expect(
+ controller.runJavascriptReturningResult(
+ 'localStorage.getItem("myCat");',
+ ),
+ completion('null'),
+ );
+ },
+ );
}
// JavaScript booleans evaluate to different string values on Android and iOS.
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 1098932..bd50640 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
@@ -852,3 +852,30 @@
Future<String> getAssetFilePathByName(String name) =>
api.getAssetFilePathByName(name);
}
+
+/// Manages the JavaScript storage APIs provided by the [WebView].
+///
+/// Wraps [WebStorage](https://developer.android.com/reference/android/webkit/WebStorage).
+class WebStorage {
+ /// Constructs a [WebStorage].
+ ///
+ /// This constructor is only used for testing. An instance should be obtained
+ /// with [WebStorage.instance].
+ @visibleForTesting
+ WebStorage() {
+ AndroidWebViewFlutterApis.instance.ensureSetUp();
+ api.createFromInstance(this);
+ }
+
+ /// Pigeon Host Api implementation for [WebStorage].
+ @visibleForTesting
+ static WebStorageHostApiImpl api = WebStorageHostApiImpl();
+
+ /// The singleton instance of this class.
+ static WebStorage instance = WebStorage();
+
+ /// Clears all storage currently being used by the JavaScript storage APIs.
+ Future<void> deleteAllData() {
+ return api.deleteAllDataFromInstance(this);
+ }
+}
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 20391c4..4a0965e 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
@@ -1860,3 +1860,69 @@
}
}
}
+
+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();
+
+ Future<void> create(int arg_instanceId) async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.WebStorageHostApi.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.',
+ details: null,
+ );
+ } 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> deleteAllData(int arg_instanceId) async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.WebStorageHostApi.deleteAllData', 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.',
+ details: null,
+ );
+ } 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;
+ }
+ }
+}
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 ead60f6..9c980c8 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
@@ -787,3 +787,30 @@
instance!.onProgressChanged(webViewInstance!, progress);
}
}
+
+/// Host api implementation for [WebStorage].
+class WebStorageHostApiImpl extends WebStorageHostApi {
+ /// Constructs a [WebStorageHostApiImpl].
+ WebStorageHostApiImpl({
+ BinaryMessenger? binaryMessenger,
+ InstanceManager? instanceManager,
+ }) : super(binaryMessenger: binaryMessenger) {
+ this.instanceManager = instanceManager ?? InstanceManager.instance;
+ }
+
+ /// Maintains instances stored to communicate with java objects.
+ late final InstanceManager instanceManager;
+
+ /// Helper method to convert instances ids to objects.
+ Future<void> createFromInstance(WebStorage instance) async {
+ final int? instanceId = instanceManager.tryAddInstance(instance);
+ if (instanceId != null) {
+ return create(instanceId);
+ }
+ }
+
+ /// Helper method to convert instances ids to objects.
+ Future<void> deleteAllDataFromInstance(WebStorage instance) {
+ return deleteAllData(instanceManager.getInstanceId(instance)!);
+ }
+}
diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart
index 7200aaa..28d169c 100644
--- a/packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart
+++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart
@@ -23,6 +23,7 @@
@visibleForTesting this.webViewProxy = const WebViewProxy(),
@visibleForTesting
this.flutterAssetManager = const android_webview.FlutterAssetManager(),
+ @visibleForTesting this.webStorage,
});
/// Initial parameters used to setup the WebView.
@@ -59,6 +60,9 @@
final Widget Function(WebViewAndroidPlatformController controller)
onBuildWidget;
+ /// Manages the JavaScript storage APIs.
+ final android_webview.WebStorage? webStorage;
+
@override
State<StatefulWidget> createState() => _WebViewAndroidWidgetState();
}
@@ -76,6 +80,7 @@
javascriptChannelRegistry: widget.javascriptChannelRegistry,
webViewProxy: widget.webViewProxy,
flutterAssetManager: widget.flutterAssetManager,
+ webStorage: widget.webStorage,
);
}
@@ -102,7 +107,9 @@
@visibleForTesting this.webViewProxy = const WebViewProxy(),
@visibleForTesting
this.flutterAssetManager = const android_webview.FlutterAssetManager(),
- }) : assert(creationParams.webSettings?.hasNavigationDelegate != null),
+ @visibleForTesting android_webview.WebStorage? webStorage,
+ }) : webStorage = webStorage ?? android_webview.WebStorage.instance,
+ assert(creationParams.webSettings?.hasNavigationDelegate != null),
super(callbacksHandler) {
webView = webViewProxy.createWebView(
useHybridComposition: useHybridComposition,
@@ -160,6 +167,9 @@
late final WebViewAndroidWebChromeClient webChromeClient =
WebViewAndroidWebChromeClient();
+ /// Manages the JavaScript storage APIs.
+ final android_webview.WebStorage webStorage;
+
/// Receive various notifications and requests for [android_webview.WebView].
@visibleForTesting
WebViewAndroidWebViewClient get webViewClient => _webViewClient;
@@ -254,7 +264,10 @@
Future<void> reload() => webView.reload();
@override
- Future<void> clearCache() => webView.clearCache(true);
+ Future<void> clearCache() {
+ webView.clearCache(true);
+ return webStorage.deleteAllData();
+ }
@override
Future<void> updateSettings(WebSettings setting) async {
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 b298352..d3d18f6 100644
--- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
+++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart
@@ -222,3 +222,10 @@
void onProgressChanged(int instanceId, int webViewInstanceId, int progress);
}
+
+@HostApi(dartHostTestHandler: 'TestWebStorageHostApi')
+abstract class WebStorageHostApi {
+ void create(int instanceId);
+
+ void deleteAllData(int instanceId);
+}
diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
index 35f0e2f..5c3c83a 100644
--- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml
@@ -2,7 +2,7 @@
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.8.3
+version: 2.8.4
environment:
sdk: ">=2.14.0 <3.0.0"
diff --git a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart
index 7461263..4ee4b1d 100644
--- a/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/android_webview.pigeon.dart
@@ -1157,3 +1157,55 @@
}
}
}
+
+class _TestWebStorageHostApiCodec extends StandardMessageCodec {
+ const _TestWebStorageHostApiCodec();
+}
+
+abstract class TestWebStorageHostApi {
+ static const MessageCodec<Object?> codec = _TestWebStorageHostApiCodec();
+
+ void create(int instanceId);
+ void deleteAllData(int instanceId);
+ static void setup(TestWebStorageHostApi? api,
+ {BinaryMessenger? binaryMessenger}) {
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.WebStorageHostApi.create', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.WebStorageHostApi.create 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.WebStorageHostApi.create was null, expected non-null int.');
+ api.create(arg_instanceId!);
+ return <Object?, Object?>{};
+ });
+ }
+ }
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.WebStorageHostApi.deleteAllData', codec,
+ binaryMessenger: binaryMessenger);
+ if (api == null) {
+ channel.setMockMessageHandler(null);
+ } else {
+ channel.setMockMessageHandler((Object? message) async {
+ assert(message != null,
+ 'Argument for dev.flutter.pigeon.WebStorageHostApi.deleteAllData 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.WebStorageHostApi.deleteAllData was null, expected non-null int.');
+ api.deleteAllData(arg_instanceId!);
+ return <Object?, Object?>{};
+ });
+ }
+ }
+ }
+}
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 91385ff..e2e6513 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
@@ -21,6 +21,7 @@
TestJavaScriptChannelHostApi,
TestWebChromeClientHostApi,
TestWebSettingsHostApi,
+ TestWebStorageHostApi,
TestWebViewClientHostApi,
TestWebViewHostApi,
TestAssetManagerHostApi,
@@ -677,4 +678,29 @@
verify(CookieManager.api.clearCookies());
});
});
+
+ group('WebStorage', () {
+ late MockTestWebStorageHostApi mockPlatformHostApi;
+
+ late WebStorage webStorage;
+ late int webStorageInstanceId;
+
+ setUp(() {
+ mockPlatformHostApi = MockTestWebStorageHostApi();
+ TestWebStorageHostApi.setup(mockPlatformHostApi);
+
+ webStorage = WebStorage();
+ webStorageInstanceId =
+ WebStorage.api.instanceManager.getInstanceId(webStorage)!;
+ });
+
+ test('create', () {
+ verify(mockPlatformHostApi.create(webStorageInstanceId));
+ });
+
+ test('deleteAllData', () {
+ webStorage.deleteAllData();
+ verify(mockPlatformHostApi.deleteAllData(webStorageInstanceId));
+ });
+ });
}
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 d6023d7..e8859c9 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
@@ -201,6 +201,25 @@
returnValueForMissingStub: null);
}
+/// A class which mocks [TestWebStorageHostApi].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockTestWebStorageHostApi extends _i1.Mock
+ implements _i5.TestWebStorageHostApi {
+ MockTestWebStorageHostApi() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ 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);
+}
+
/// A class which mocks [TestWebViewClientHostApi].
///
/// See the documentation for Mockito's code generation for more information.
diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.dart b/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.dart
index af10939..46d6a29 100644
--- a/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.dart
+++ b/packages/webview_flutter/webview_flutter_android/test/webview_android_widget_test.dart
@@ -23,6 +23,7 @@
@GenerateMocks(<Type>[
android_webview.FlutterAssetManager,
android_webview.WebSettings,
+ android_webview.WebStorage,
android_webview.WebView,
WebViewAndroidDownloadListener,
WebViewAndroidJavaScriptChannel,
@@ -39,6 +40,7 @@
late MockFlutterAssetManager mockFlutterAssetManager;
late MockWebView mockWebView;
late MockWebSettings mockWebSettings;
+ late MockWebStorage mockWebStorage;
late MockWebViewProxy mockWebViewProxy;
late MockWebViewPlatformCallbacksHandler mockCallbacksHandler;
@@ -54,6 +56,7 @@
mockFlutterAssetManager = MockFlutterAssetManager();
mockWebView = MockWebView();
mockWebSettings = MockWebSettings();
+ mockWebStorage = MockWebStorage();
when(mockWebView.settings).thenReturn(mockWebSettings);
mockWebViewProxy = MockWebViewProxy();
@@ -86,6 +89,7 @@
javascriptChannelRegistry: mockJavascriptChannelRegistry,
webViewProxy: mockWebViewProxy,
flutterAssetManager: mockFlutterAssetManager,
+ webStorage: mockWebStorage,
onBuildWidget: (WebViewAndroidPlatformController controller) {
testController = controller;
return Container();
@@ -590,6 +594,7 @@
await testController.clearCache();
verify(mockWebView.clearCache(true));
+ verify(mockWebStorage.deleteAllData());
});
testWidgets('evaluateJavascript', (WidgetTester tester) async {
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
index f4d9abb..3385e79 100644
--- 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
@@ -121,6 +121,21 @@
returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
}
+/// 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
+ _i4.Future<void> deleteAllData() =>
+ (super.noSuchMethod(Invocation.method(#deleteAllData, []),
+ returnValue: Future<void>.value(),
+ returnValueForMissingStub: Future<void>.value()) as _i4.Future<void>);
+}
+
/// A class which mocks [WebView].
///
/// See the documentation for Mockito's code generation for more information.