From 9950ee57b0fe9a1c2cf1baa9c514b8e1158f9b78 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 15:06:59 +0100 Subject: [PATCH 01/25] Added cookie manager to interface. --- .../CHANGELOG.md | 6 +++ .../webview_method_channel.dart | 8 ++++ .../platform_interface.dart | 1 + .../webview_cookie_manager.dart | 24 ++++++++++ .../platform_interface/webview_platform.dart | 2 + .../lib/src/types/creation_params.dart | 8 +++- .../lib/src/types/types.dart | 1 + .../lib/src/types/webview_cookie.dart | 44 +++++++++++++++++++ .../pubspec.yaml | 2 +- .../webview_method_channel_test.dart | 20 +++++++++ .../webview_cookie_manager_test.dart | 27 ++++++++++++ .../test/src/types/webview_cookie_test.dart | 21 +++++++++ 12 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_cookie_manager.dart create mode 100644 packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart create mode 100644 packages/webview_flutter/webview_flutter_platform_interface/test/src/platform_interface/webview_cookie_manager_test.dart create mode 100644 packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_cookie_test.dart diff --git a/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md b/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md index efc43cf28ed1..e52e728965bd 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.6.0 + +* Adds platform interface for cookie manager. +* Deprecates `clearCookies` in WebViewPlatform in favour of `CookieManager#clearCookies`. +* Expanded `CreationParams` to include cookies to be set at webview creation. + ## 1.5.1 * Reverts the addition of `onUrlChanged`, which was unintentionally a breaking diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart index 8df9f4c62b33..1df1dad89abc 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart @@ -213,6 +213,12 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { .then((dynamic result) => result!); } + /// Method channel implementation for [WebViewPlatform.setCookie]. + static Future setCookie(WebViewCookie cookie) { + return _cookieManagerChannel.invokeMethod( + 'setCookie', cookie.toJson()); + } + static Map _webSettingsToMap(WebSettings? settings) { final Map map = {}; void _addIfNonNull(String key, dynamic value) { @@ -257,6 +263,8 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { 'userAgent': creationParams.userAgent, 'autoMediaPlaybackPolicy': creationParams.autoMediaPlaybackPolicy.index, 'usesHybridComposition': usesHybridComposition, + 'cookies': + creationParams.cookies.map((cookie) => cookie.toJson()).toList() }; } } diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/platform_interface.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/platform_interface.dart index 43f967fb13b0..be42dcbf7c54 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/platform_interface.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/platform_interface.dart @@ -6,3 +6,4 @@ export 'javascript_channel_registry.dart'; export 'webview_platform.dart'; export 'webview_platform_callbacks_handler.dart'; export 'webview_platform_controller.dart'; +export 'webview_cookie_manager.dart'; diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_cookie_manager.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_cookie_manager.dart new file mode 100644 index 000000000000..8fb087d2ac9e --- /dev/null +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_cookie_manager.dart @@ -0,0 +1,24 @@ +// 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/src/types/webview_cookie.dart'; + +/// Interface for a platform implementation of a cookie manager. +/// +/// This interface should only be extended, not implemented, as more methods may be added later. +abstract class WebViewCookieManagerPlatform { + /// Clears all cookies for all [WebView] instances. + /// + /// Returns true if cookies were present before clearing, else false. + Future clearCookies() { + throw UnimplementedError( + 'clearCookies is not implemented on the current platform'); + } + + /// Sets a cookie for all [WebView] instances. + Future setCookie(WebViewCookie cookie) { + throw UnimplementedError( + 'setCookie is not implemented on the current platform'); + } +} diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart index 4732f54d6456..a105adc5fc45 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; import 'package:webview_flutter_platform_interface/src/platform_interface/javascript_channel_registry.dart'; +import 'package:webview_flutter_platform_interface/src/types/webview_cookie.dart'; import '../types/types.dart'; import 'webview_platform_callbacks_handler.dart'; @@ -59,6 +60,7 @@ abstract class WebViewPlatform { /// Clears all cookies for all [WebView] instances. /// /// Returns true if cookies were present before clearing, else false. + @Deprecated('Use `WebViewCookieManager.clearCookies` instead.') Future clearCookies() { throw UnimplementedError( "WebView clearCookies is not implemented on the current platform"); diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/creation_params.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/creation_params.dart index f213e976ad84..477878b16b7b 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/creation_params.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/creation_params.dart @@ -2,6 +2,8 @@ // 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/src/types/types.dart'; + import 'auto_media_playback_policy.dart'; import 'web_settings.dart'; @@ -20,6 +22,7 @@ class CreationParams { this.userAgent, this.autoMediaPlaybackPolicy = AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + this.cookies = const [], }) : assert(autoMediaPlaybackPolicy != null); /// The initialUrl to load in the webview. @@ -53,8 +56,11 @@ class CreationParams { /// Which restrictions apply on automatic media playback. final AutoMediaPlaybackPolicy autoMediaPlaybackPolicy; + /// The initial set of cookies to set before the webview does its first load. + final List cookies; + @override String toString() { - return '$runtimeType(initialUrl: $initialUrl, settings: $webSettings, javascriptChannelNames: $javascriptChannelNames, UserAgent: $userAgent)'; + return '$runtimeType(initialUrl: $initialUrl, settings: $webSettings, javascriptChannelNames: $javascriptChannelNames, UserAgent: $userAgent, cookies: $cookies)'; } } diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart index 8ce834196cd8..9956c9250602 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart @@ -11,3 +11,4 @@ export 'web_resource_error.dart'; export 'web_resource_error_type.dart'; export 'web_settings.dart'; export 'webview_request.dart'; +export 'webview_cookie.dart'; diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart new file mode 100644 index 000000000000..5725462f5956 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart @@ -0,0 +1,44 @@ +// 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. + +/// Configuration to use when creating a new [WebViewPlatformController]. +/// +/// The `autoMediaPlaybackPolicy` parameter must not be null. +class WebViewCookie { + /// The name of the cookie. + /// + /// Its value should match "cookie-name" in RFC6265bis: + /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 + final String name; + + /// The value of the cookie. + /// + /// Its value should match "cookie-value" in RFC6265bis: + /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 + final String value; + + /// The value of the cookie. + /// + /// Its value should match "domain-value" in RFC6265bis: + /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 + final String domain; + + /// The value of the cookie. + /// + /// Its value should match "path-value" in RFC6265bis: + /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 + final String path; + + /// Construct a new [WebViewCookie]. + const WebViewCookie( + {required this.name, + required this.value, + required this.domain, + this.path = '/'}); + + /// Serialize a [WebViewCookie] to a Map. + Map toJson() { + return {'name': name, 'value': value, 'domain': domain, 'path': path}; + } +} diff --git a/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml b/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml index 33eb77cbefd5..3c0b5fa34b63 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/plugins/tree/master/packages/webview_flut issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview_flutter%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 1.5.1 +version: 1.6.0 environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart index 396013535aa9..63bb3006b3e4 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart @@ -590,6 +590,26 @@ void main() { ], ); }); + + test('setCookie', () async { + await MethodChannelWebViewPlatform.setCookie( + WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev')); + + expect( + log, + [ + isMethodCall( + 'setCookie', + arguments: { + 'name': 'foo', + 'value': 'bar', + 'domain': 'flutter.dev', + 'path': '/', + }, + ), + ], + ); + }); }); } diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/platform_interface/webview_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/platform_interface/webview_cookie_manager_test.dart new file mode 100644 index 000000000000..c03b7238415b --- /dev/null +++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/platform_interface/webview_cookie_manager_test.dart @@ -0,0 +1,27 @@ +// 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:webview_flutter_platform_interface/src/platform_interface/platform_interface.dart'; +import 'package:webview_flutter_platform_interface/src/types/webview_cookie.dart'; + +void main() { + WebViewCookieManagerPlatform? cookieManager; + + setUp(() { + cookieManager = TestWebViewCookieManagerPlatform(); + }); + + test('clearCookies should throw UnimplementedError', () { + expect(() => cookieManager!.clearCookies(), throwsUnimplementedError); + }); + + test('setCookie should throw UnimplementedError', () { + WebViewCookie cookie = + WebViewCookie(domain: 'flutter.dev', name: 'foo', value: 'bar'); + expect(() => cookieManager!.setCookie(cookie), throwsUnimplementedError); + }); +} + +class TestWebViewCookieManagerPlatform extends WebViewCookieManagerPlatform {} diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_cookie_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_cookie_test.dart new file mode 100644 index 000000000000..79db8a431dc0 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_cookie_test.dart @@ -0,0 +1,21 @@ +// 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:webview_flutter_platform_interface/src/types/types.dart'; + +void main() { + test('WebViewCookie should serialize correctly', () { + WebViewCookie cookie; + Map serializedCookie; + // Test serialization + cookie = WebViewCookie( + name: 'foo', value: 'bar', domain: 'example.com', path: '/test'); + serializedCookie = cookie.toJson(); + expect(serializedCookie['name'], 'foo'); + expect(serializedCookie['value'], 'bar'); + expect(serializedCookie['domain'], 'example.com'); + expect(serializedCookie['path'], '/test'); + }); +} From 4782a689fa7b5e0530d1c26f0aa206441a7de1de Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 15:11:50 +0100 Subject: [PATCH 02/25] Added Android implementation for new CookieManager. --- .../webview_flutter_android/CHANGELOG.md | 3 +- .../android/build.gradle | 8 +- .../CookieManagerHostApiImpl.java | 24 +++ .../webviewflutter/FlutterCookieManager.java | 56 ------- .../GeneratedAndroidWebView.java | 92 +++++++++++- .../webviewflutter/WebViewFlutterPlugin.java | 15 +- .../CookieManagerHostApiImplTest.java | 79 ++++++++++ .../webviewflutter/utils/TestUtils.java | 47 ++++++ .../example/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../example/lib/web_view.dart | 34 +++++ .../lib/src/android_webview.dart | 41 +++++ .../lib/src/android_webview.pigeon.dart | 70 ++++++++- .../lib/webview_android.dart | 4 +- .../lib/webview_android_cookie_manager.dart | 44 ++++++ .../lib/webview_android_widget.dart | 5 +- .../pigeons/android_webview.dart | 8 + .../webview_flutter_android/pubspec.yaml | 6 +- .../test/android_webview.pigeon.dart | 140 +++++++++--------- .../test/android_webview_test.dart | 17 +++ .../test/android_webview_test.mocks.dart | 41 +++-- .../webview_android_cookie_manager_test.dart | 53 +++++++ ...iew_android_cookie_manager_test.mocks.dart | 38 +++++ .../webview_android_widget_test.mocks.dart | 4 - 24 files changed, 658 insertions(+), 175 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java delete mode 100644 packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImplTest.java create mode 100644 packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/utils/TestUtils.java create mode 100644 packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart create mode 100644 packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart create mode 100644 packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.mocks.dart diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index ae76ea8bc342..95c1f79dcea7 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,6 +1,7 @@ -## NEXT +## 2.4.0 * Updates compileSdkVersion to 31. +* Implemented new cookie manager for setting cookies and providing initial cookies. ## 2.3.0 diff --git a/packages/webview_flutter/webview_flutter_android/android/build.gradle b/packages/webview_flutter/webview_flutter_android/android/build.gradle index e70d4e68edc8..c087839d2777 100644 --- a/packages/webview_flutter/webview_flutter_android/android/build.gradle +++ b/packages/webview_flutter/webview_flutter_android/android/build.gradle @@ -43,8 +43,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } testOptions { @@ -58,8 +58,4 @@ android { } } } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } } diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java new file mode 100644 index 000000000000..337301e3453d --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java @@ -0,0 +1,24 @@ +package io.flutter.plugins.webviewflutter; + +import android.os.Build; +import android.webkit.CookieManager; + + +class CookieManagerHostApiImpl implements GeneratedAndroidWebView.CookieManagerHostApi { + @Override + public void clearCookies(GeneratedAndroidWebView.Result result) { + CookieManager cookieManager = CookieManager.getInstance(); + final boolean hasCookies = cookieManager.hasCookies(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + cookieManager.removeAllCookies(value -> result.success(hasCookies)); + } else { + cookieManager.removeAllCookie(); + result.success(hasCookies); + } + } + + @Override + public void setCookie(String url, String value) { + CookieManager.getInstance().setCookie(url, value); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java deleted file mode 100644 index df3f21daadeb..000000000000 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java +++ /dev/null @@ -1,56 +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; - -import android.os.Build; -import android.os.Build.VERSION_CODES; -import android.webkit.CookieManager; -import android.webkit.ValueCallback; -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.MethodCallHandler; -import io.flutter.plugin.common.MethodChannel.Result; - -class FlutterCookieManager implements MethodCallHandler { - private final MethodChannel methodChannel; - - FlutterCookieManager(BinaryMessenger messenger) { - methodChannel = new MethodChannel(messenger, "plugins.flutter.io/cookie_manager"); - methodChannel.setMethodCallHandler(this); - } - - @Override - public void onMethodCall(MethodCall methodCall, Result result) { - switch (methodCall.method) { - case "clearCookies": - clearCookies(result); - break; - default: - result.notImplemented(); - } - } - - void dispose() { - methodChannel.setMethodCallHandler(null); - } - - private static void clearCookies(final Result result) { - CookieManager cookieManager = CookieManager.getInstance(); - final boolean hasCookies = cookieManager.hasCookies(); - if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - cookieManager.removeAllCookies( - new ValueCallback() { - @Override - public void onReceiveValue(Boolean value) { - result.success(hasCookies); - } - }); - } else { - cookieManager.removeAllCookie(); - result.success(hasCookies); - } - } -} 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 a34274893117..eaff3fa0bd8f 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,3 @@ -// 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 (v1.0.9), do not edit directly. // See also: https://pub.dev/packages/pigeon @@ -161,6 +157,94 @@ public interface Result { void error(Throwable error); } + 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 result); + + void setCookie(String url, String value); + + /** The codec used by CookieManagerHostApi. */ + static MessageCodec getCodec() { + return CookieManagerHostApiCodec.INSTANCE; + } + + /** + * Sets up an instance of `CookieManagerHostApi` to handle messages through the + * `binaryMessenger`. + */ + static void setup(BinaryMessenger binaryMessenger, CookieManagerHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.CookieManagerHostApi.clearCookies", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + Result resultCallback = + new Result() { + public void success(Boolean result) { + wrapped.put("result", result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + wrapped.put("error", wrapError(error)); + reply.reply(wrapped); + } + }; + + api.clearCookies(resultCallback); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + reply.reply(wrapped); + } + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.CookieManagerHostApi.setCookie", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + String urlArg = (String) args.get(0); + if (urlArg == null) { + throw new NullPointerException("urlArg unexpectedly null."); + } + String valueArg = (String) args.get(1); + if (valueArg == null) { + throw new NullPointerException("valueArg unexpectedly null."); + } + api.setCookie(urlArg, valueArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + private static class WebViewHostApiCodec extends StandardMessageCodec { public static final WebViewHostApiCodec INSTANCE = new WebViewHostApiCodec(); 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 2b174ff35e6f..288c64a69963 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 @@ -29,8 +29,8 @@ */ public class WebViewFlutterPlugin implements FlutterPlugin, ActivityAware { private FlutterPluginBinding pluginBinding; - private FlutterCookieManager flutterCookieManager; private WebViewHostApiImpl webViewHostApi; + private CookieManagerHostApiImpl cookieManagerHostApi; private JavaScriptChannelHostApiImpl javaScriptChannelHostApi; /** @@ -62,7 +62,6 @@ public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registra registrar.platformViewRegistry(), registrar.activity(), registrar.view()); - new FlutterCookieManager(registrar.messenger()); } private void setUp( @@ -70,7 +69,6 @@ private void setUp( PlatformViewRegistry viewRegistry, Context context, View containerView) { - new FlutterCookieManager(binaryMessenger); InstanceManager instanceManager = new InstanceManager(); @@ -86,6 +84,7 @@ private void setUp( new JavaScriptChannelHostApiImpl.JavaScriptChannelCreator(), new JavaScriptChannelFlutterApiImpl(binaryMessenger, instanceManager), new Handler(context.getMainLooper())); + cookieManagerHostApi = new CookieManagerHostApiImpl(); WebViewHostApi.setup(binaryMessenger, webViewHostApi); JavaScriptChannelHostApi.setup(binaryMessenger, javaScriptChannelHostApi); @@ -111,6 +110,7 @@ private void setUp( binaryMessenger, new WebSettingsHostApiImpl( instanceManager, new WebSettingsHostApiImpl.WebSettingsCreator())); + GeneratedAndroidWebView.CookieManagerHostApi.setup(binaryMessenger, cookieManagerHostApi); } @Override @@ -124,14 +124,7 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { } @Override - public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { - if (flutterCookieManager == null) { - return; - } - - flutterCookieManager.dispose(); - flutterCookieManager = null; - } + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {} @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) { diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImplTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImplTest.java new file mode 100644 index 000000000000..1e2fea4681e3 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImplTest.java @@ -0,0 +1,79 @@ +package io.flutter.plugins.webviewflutter; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.os.Build; +import android.webkit.CookieManager; +import android.webkit.ValueCallback; +import io.flutter.plugins.webviewflutter.utils.TestUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockedStatic; + +public class CookieManagerHostApiImplTest { + + private CookieManager cookieManager; + private MockedStatic staticMockCookieManager; + + @Before + public void setup() { + staticMockCookieManager = mockStatic(CookieManager.class); + cookieManager = mock(CookieManager.class); + when(CookieManager.getInstance()).thenReturn(cookieManager); + when(cookieManager.hasCookies()).thenReturn(true); + doAnswer( + answer -> { + ((ValueCallback) answer.getArgument(0)).onReceiveValue(true); + return null; + }) + .when(cookieManager) + .removeAllCookies(any()); + } + + @After + public void tearDown() { + staticMockCookieManager.close(); + } + + @Test + public void setCookieShouldCallSetCookie() { + // Setup + CookieManagerHostApiImpl impl = new CookieManagerHostApiImpl(); + // Run + impl.setCookie("flutter.dev", "foo=bar; path=/"); + // Verify + verify(cookieManager).setCookie("flutter.dev", "foo=bar; path=/"); + } + + @Test + public void clearCookiesShouldCallRemoveAllCookiesOnAndroidLAbove() { + // Setup + TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.LOLLIPOP); + GeneratedAndroidWebView.Result result = mock(GeneratedAndroidWebView.Result.class); + CookieManagerHostApiImpl impl = new CookieManagerHostApiImpl(); + // Run + impl.clearCookies(result); + // Verify + verify(cookieManager).removeAllCookies(any()); + verify(result).success(true); + } + + @Test + public void clearCookiesShouldCallRemoveAllCookieBelowAndroidL() { + // Setup + TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.KITKAT_WATCH); + GeneratedAndroidWebView.Result result = mock(GeneratedAndroidWebView.Result.class); + CookieManagerHostApiImpl impl = new CookieManagerHostApiImpl(); + // Run + impl.clearCookies(result); + // Verify + verify(cookieManager).removeAllCookie(); + verify(result).success(true); + } +} diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/utils/TestUtils.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/utils/TestUtils.java new file mode 100644 index 000000000000..31e7d58ee13f --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/utils/TestUtils.java @@ -0,0 +1,47 @@ +// 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.utils; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import org.junit.Assert; + +public class TestUtils { + public static void setFinalStatic(Class classToModify, String fieldName, Object newValue) { + try { + Field field = classToModify.getField(fieldName); + field.setAccessible(true); + + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + + field.set(null, newValue); + } catch (Exception e) { + Assert.fail("Unable to mock static field: " + fieldName); + } + } + + public static void setPrivateField(T instance, String fieldName, Object newValue) { + try { + Field field = instance.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(instance, newValue); + } catch (Exception e) { + Assert.fail("Unable to mock private field: " + fieldName); + } + } + + public static Object getPrivateField(T instance, String fieldName) { + try { + Field field = instance.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + return field.get(instance); + } catch (Exception e) { + Assert.fail("Unable to mock private field: " + fieldName); + return null; + } + } +} diff --git a/packages/webview_flutter/webview_flutter_android/example/android/build.gradle b/packages/webview_flutter/webview_flutter_android/example/android/build.gradle index e101ac08df55..d21451f63b46 100644 --- a/packages/webview_flutter/webview_flutter_android/example/android/build.gradle +++ b/packages/webview_flutter/webview_flutter_android/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:7.0.3' } } diff --git a/packages/webview_flutter/webview_flutter_android/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/webview_flutter/webview_flutter_android/example/android/gradle/wrapper/gradle-wrapper.properties index 2819f022f1fd..b8793d3c0d69 100644 --- a/packages/webview_flutter/webview_flutter_android/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/webview_flutter/webview_flutter_android/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart index 9a535cc38d2b..55a6fbb4df06 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart @@ -3,11 +3,13 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:io'; 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'; import 'navigation_decision.dart'; @@ -61,6 +63,7 @@ class WebView extends StatefulWidget { Key? key, this.onWebViewCreated, this.initialUrl, + this.initialCookies = const [], this.javascriptMode = JavascriptMode.disabled, this.javascriptChannels, this.navigationDelegate, @@ -103,6 +106,9 @@ class WebView extends StatefulWidget { /// The initial URL to load. final String? initialUrl; + /// The initial cookies to set. + final List initialCookies; + /// Whether JavaScript execution is enabled. final JavascriptMode javascriptMode; @@ -287,6 +293,7 @@ class _WebViewState extends State { _javascriptChannelRegistry.channels.keys.toSet(), autoMediaPlaybackPolicy: widget.initialMediaPlaybackPolicy, userAgent: widget.userAgent, + cookies: widget.initialCookies, ), javascriptChannelRegistry: _javascriptChannelRegistry, ); @@ -631,3 +638,30 @@ WebSettings _webSettingsFromWidget(WebView widget) { zoomEnabled: widget.zoomEnabled, ); } + +class WebViewCookieManager extends WebViewCookieManagerPlatform { + static WebViewCookieManager? _instance; + + static WebViewCookieManager get instance => + _instance ??= WebViewCookieManager._(); + + WebViewCookieManager._(); + + @override + Future clearCookies() async { + if (Platform.isAndroid) { + return WebViewAndroidCookieManager.instance.clearCookies(); + } else { + return super.clearCookies(); + } + } + + @override + Future setCookie(WebViewCookie cookie) { + if (Platform.isAndroid) { + return WebViewAndroidCookieManager.instance.setCookie(cookie); + } else { + return super.setCookie(cookie); + } + } +} 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 1d0dc259ca3d..2b21803b6e68 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 @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart' show AndroidViewSurface; +import 'android_webview.pigeon.dart'; import 'android_webview_api_impls.dart'; // TODO(bparrishMines): This can be removed once pigeon supports null values: https://github.com/flutter/flutter/issues/59118 @@ -270,6 +271,46 @@ class WebView { } } +/// Manages cookies globally for all webviews. +class CookieManager { + CookieManager._(); + + static CookieManager? _instance; + + static CookieManager get instance => _instance ??= CookieManager._(); + + /// Setter for the singleton value, for testing purposes only. + @visibleForTesting + static set instance(CookieManager value) => _instance = value; + + /// Pigeon Host Api implementation for [CookieManager]. + @visibleForTesting + static CookieManagerHostApi api = CookieManagerHostApi(); + + /// Sets a single cookie (key-value pair) for the given URL. Any existing + /// cookie with the same host, path and name will be replaced with the new + /// cookie. The cookie being set will be ignored if it is expired. To set + /// multiple cookies, your application should invoke this method multiple + /// times. + /// + /// The value parameter must follow the format of the Set-Cookie HTTP + /// response header defined by RFC6265bis. This is a key-value pair of the + /// form "key=value", optionally followed by a list of cookie attributes + /// delimited with semicolons (ex. "key=value; Max-Age=123"). Please consult + /// the RFC specification for a list of valid attributes. + /// + /// Note: if specifying a value containing the "Secure" attribute, url must + /// use the "https://" scheme. + /// + /// Params: + /// url – the URL for which the cookie is to be set + /// value – the cookie as a string, using the format of the 'Set-Cookie' HTTP response header + Future setCookie(String url, String value) => api.setCookie(url, value); + + /// Removes all cookies. + Future clearCookies() => api.clearCookies(); +} + /// Manages settings state for a [WebView]. /// /// When a WebView is first created, it obtains a set of default settings. These 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 7fb95f1dd942..40b13407da77 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,3 @@ -// 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 (v1.0.9), 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 @@ -63,6 +59,72 @@ class WebResourceErrorData { } } +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 codec = _CookieManagerHostApiCodec(); + + Future clearCookies() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.CookieManagerHostApi.clearCookies', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send(null) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as bool?)!; + } + } + + Future setCookie(String arg_url, String arg_value) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.CookieManagerHostApi.setCookie', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = await channel + .send([arg_url, arg_value]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} + class _WebViewHostApiCodec extends StandardMessageCodec { const _WebViewHostApiCodec(); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index ee474b9d43f8..2d1fe1433dca 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; +import 'package:webview_flutter_android/webview_android_cookie_manager.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; import 'src/android_webview.dart'; @@ -65,5 +66,6 @@ class AndroidWebView implements WebViewPlatform { } @override - Future clearCookies() => MethodChannelWebViewPlatform.clearCookies(); + Future clearCookies() => + WebViewAndroidCookieManager.instance.clearCookies(); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart new file mode 100644 index 000000000000..62be234dc4db --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart @@ -0,0 +1,44 @@ +// 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_android/src/android_webview.dart' + as android_webview; +import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; + +/// Handles all cookie operations for the current platform. +class WebViewAndroidCookieManager extends WebViewCookieManagerPlatform { + WebViewAndroidCookieManager._(); + + static WebViewAndroidCookieManager? _instance; + + /// Obtain a singleton instance for [WebViewAndroidCookieManager]. + static WebViewAndroidCookieManager get instance => + _instance ??= WebViewAndroidCookieManager._(); + + @override + Future clearCookies() => + android_webview.CookieManager.instance.clearCookies(); + + @override + Future setCookie(WebViewCookie cookie) { + if (!_isValidPath(cookie.path)) { + throw ArgumentError( + 'The path property for the provided cookie was not given a legal value.'); + } + return android_webview.CookieManager.instance.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/webview_android_widget.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android_widget.dart index d63d641ab7cb..a841984d47c3 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 @@ -5,7 +5,7 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; - +import 'package:webview_flutter_android/webview_android_cookie_manager.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; import 'src/android_webview.dart' as android_webview; @@ -281,6 +281,9 @@ class WebViewAndroidPlatformController extends WebViewPlatformController { ); addJavascriptChannels(creationParams.javascriptChannelNames); + + creationParams.cookies + .forEach(WebViewAndroidCookieManager.instance.setCookie); } Future _setHasProgressTracking(bool hasProgressTracking) 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 47bc42058ba9..860aa611ee14 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -18,6 +18,14 @@ class WebResourceErrorData { String? description; } +@HostApi() +abstract class CookieManagerHostApi { + @async + bool clearCookies(); + + void setCookie(String url, String value); +} + @HostApi(dartHostTestHandler: 'TestWebViewHostApi') abstract class WebViewHostApi { void create(int instanceId, bool useHybridComposition); diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 705951b1fda0..125d2d32130b 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/plugins/tree/master/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.3.0 +version: 2.4.0 environment: sdk: ">=2.14.0 <3.0.0" @@ -19,7 +19,9 @@ flutter: dependencies: flutter: sdk: flutter - webview_flutter_platform_interface: ^1.2.0 +# TODO (BeMacized): Update dependency once platform interface has been published. + webview_flutter_platform_interface: + path: ../webview_flutter_platform_interface dev_dependencies: build_runner: ^2.1.4 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 07bbebb6d9d7..daf3e9a46890 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 @@ -1,10 +1,6 @@ -// 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 (v1.0.9), 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, avoid_relative_lib_imports +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import // @dart = 2.12 import 'dart:async'; import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; @@ -56,10 +52,10 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null, expected non-null int.'); - final bool? arg_useHybridComposition = args[1] as bool?; + final bool? arg_useHybridComposition = (args[1] as bool?); assert(arg_useHybridComposition != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.create was null, expected non-null bool.'); api.create(arg_instanceId!, arg_useHybridComposition!); @@ -78,7 +74,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.dispose was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + 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!); @@ -97,10 +93,10 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null int.'); - final String? arg_url = args[1] as String?; + final String? arg_url = (args[1] as String?); assert(arg_url != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.loadUrl was null, expected non-null String.'); final Map? arg_headers = @@ -123,7 +119,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getUrl was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getUrl was null, expected non-null int.'); final String output = api.getUrl(arg_instanceId!); @@ -142,7 +138,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoBack was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoBack was null, expected non-null int.'); final bool output = api.canGoBack(arg_instanceId!); @@ -161,7 +157,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoForward was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.canGoForward was null, expected non-null int.'); final bool output = api.canGoForward(arg_instanceId!); @@ -180,7 +176,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goBack was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goBack was null, expected non-null int.'); api.goBack(arg_instanceId!); @@ -199,7 +195,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goForward was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.goForward was null, expected non-null int.'); api.goForward(arg_instanceId!); @@ -218,7 +214,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.reload was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.reload was null, expected non-null int.'); api.reload(arg_instanceId!); @@ -237,10 +233,10 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null, expected non-null int.'); - final bool? arg_includeDiskFiles = args[1] as bool?; + final bool? arg_includeDiskFiles = (args[1] as bool?); assert(arg_includeDiskFiles != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.clearCache was null, expected non-null bool.'); api.clearCache(arg_instanceId!, arg_includeDiskFiles!); @@ -259,10 +255,10 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null, expected non-null int.'); - final String? arg_javascriptString = args[1] as String?; + final String? arg_javascriptString = (args[1] as String?); assert(arg_javascriptString != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.evaluateJavascript was null, expected non-null String.'); final String output = await api.evaluateJavascript( @@ -282,7 +278,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getTitle was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getTitle was null, expected non-null int.'); final String output = api.getTitle(arg_instanceId!); @@ -301,13 +297,13 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); - final int? arg_x = args[1] as int?; + final int? arg_x = (args[1] as int?); assert(arg_x != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); - final int? arg_y = args[2] as int?; + final int? arg_y = (args[2] as int?); assert(arg_y != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollTo was null, expected non-null int.'); api.scrollTo(arg_instanceId!, arg_x!, arg_y!); @@ -326,13 +322,13 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); - final int? arg_x = args[1] as int?; + final int? arg_x = (args[1] as int?); assert(arg_x != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); - final int? arg_y = args[2] as int?; + final int? arg_y = (args[2] as int?); assert(arg_y != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.scrollBy was null, expected non-null int.'); api.scrollBy(arg_instanceId!, arg_x!, arg_y!); @@ -351,7 +347,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollX was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollX was null, expected non-null int.'); final int output = api.getScrollX(arg_instanceId!); @@ -370,7 +366,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollY was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.getScrollY was null, expected non-null int.'); final int output = api.getScrollY(arg_instanceId!); @@ -390,7 +386,7 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled was null.'); final List args = (message as List?)!; - final bool? arg_enabled = args[0] as bool?; + final bool? arg_enabled = (args[0] as bool?); assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebContentsDebuggingEnabled was null, expected non-null bool.'); api.setWebContentsDebuggingEnabled(arg_enabled!); @@ -409,10 +405,10 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null, expected non-null int.'); - final int? arg_webViewClientInstanceId = args[1] as int?; + final int? arg_webViewClientInstanceId = (args[1] as int?); assert(arg_webViewClientInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebViewClient was null, expected non-null int.'); api.setWebViewClient(arg_instanceId!, arg_webViewClientInstanceId!); @@ -431,10 +427,10 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null, expected non-null int.'); - final int? arg_javaScriptChannelInstanceId = args[1] as int?; + final int? arg_javaScriptChannelInstanceId = (args[1] as int?); assert(arg_javaScriptChannelInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.addJavaScriptChannel was null, expected non-null int.'); api.addJavaScriptChannel( @@ -454,10 +450,10 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null, expected non-null int.'); - final int? arg_javaScriptChannelInstanceId = args[1] as int?; + final int? arg_javaScriptChannelInstanceId = (args[1] as int?); assert(arg_javaScriptChannelInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.removeJavaScriptChannel was null, expected non-null int.'); api.removeJavaScriptChannel( @@ -477,10 +473,10 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null, expected non-null int.'); - final int? arg_listenerInstanceId = args[1] as int?; + final int? arg_listenerInstanceId = (args[1] as int?); assert(arg_listenerInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setDownloadListener was null, expected non-null int.'); api.setDownloadListener(arg_instanceId!, arg_listenerInstanceId!); @@ -499,10 +495,10 @@ abstract class TestWebViewHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebChromeClient was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebChromeClient was null, expected non-null int.'); - final int? arg_clientInstanceId = args[1] as int?; + final int? arg_clientInstanceId = (args[1] as int?); assert(arg_clientInstanceId != null, 'Argument for dev.flutter.pigeon.WebViewHostApi.setWebChromeClient was null, expected non-null int.'); api.setWebChromeClient(arg_instanceId!, arg_clientInstanceId!); @@ -546,10 +542,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null, expected non-null int.'); - final int? arg_webViewInstanceId = args[1] as int?; + final int? arg_webViewInstanceId = (args[1] as int?); assert(arg_webViewInstanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.create was null, expected non-null int.'); api.create(arg_instanceId!, arg_webViewInstanceId!); @@ -568,7 +564,7 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.dispose was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + 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!); @@ -587,10 +583,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null, expected non-null int.'); - final bool? arg_flag = args[1] as bool?; + final bool? arg_flag = (args[1] as bool?); assert(arg_flag != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDomStorageEnabled was null, expected non-null bool.'); api.setDomStorageEnabled(arg_instanceId!, arg_flag!); @@ -610,10 +606,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null, expected non-null int.'); - final bool? arg_flag = args[1] as bool?; + final bool? arg_flag = (args[1] as bool?); assert(arg_flag != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptCanOpenWindowsAutomatically was null, expected non-null bool.'); api.setJavaScriptCanOpenWindowsAutomatically( @@ -634,10 +630,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null, expected non-null int.'); - final bool? arg_support = args[1] as bool?; + final bool? arg_support = (args[1] as bool?); assert(arg_support != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportMultipleWindows was null, expected non-null bool.'); api.setSupportMultipleWindows(arg_instanceId!, arg_support!); @@ -656,10 +652,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null, expected non-null int.'); - final bool? arg_flag = args[1] as bool?; + final bool? arg_flag = (args[1] as bool?); assert(arg_flag != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setJavaScriptEnabled was null, expected non-null bool.'); api.setJavaScriptEnabled(arg_instanceId!, arg_flag!); @@ -678,10 +674,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null, expected non-null int.'); - final String? arg_userAgentString = args[1] as String?; + final String? arg_userAgentString = (args[1] as String?); assert(arg_userAgentString != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUserAgentString was null, expected non-null String.'); api.setUserAgentString(arg_instanceId!, arg_userAgentString!); @@ -701,10 +697,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null, expected non-null int.'); - final bool? arg_require = args[1] as bool?; + final bool? arg_require = (args[1] as bool?); assert(arg_require != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setMediaPlaybackRequiresUserGesture was null, expected non-null bool.'); api.setMediaPlaybackRequiresUserGesture( @@ -724,10 +720,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null, expected non-null int.'); - final bool? arg_support = args[1] as bool?; + final bool? arg_support = (args[1] as bool?); assert(arg_support != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setSupportZoom was null, expected non-null bool.'); api.setSupportZoom(arg_instanceId!, arg_support!); @@ -747,10 +743,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null, expected non-null int.'); - final bool? arg_overview = args[1] as bool?; + final bool? arg_overview = (args[1] as bool?); assert(arg_overview != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setLoadWithOverviewMode was null, expected non-null bool.'); api.setLoadWithOverviewMode(arg_instanceId!, arg_overview!); @@ -769,10 +765,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null, expected non-null int.'); - final bool? arg_use = args[1] as bool?; + final bool? arg_use = (args[1] as bool?); assert(arg_use != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setUseWideViewPort was null, expected non-null bool.'); api.setUseWideViewPort(arg_instanceId!, arg_use!); @@ -791,10 +787,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null, expected non-null int.'); - final bool? arg_enabled = args[1] as bool?; + final bool? arg_enabled = (args[1] as bool?); assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setDisplayZoomControls was null, expected non-null bool.'); api.setDisplayZoomControls(arg_instanceId!, arg_enabled!); @@ -813,10 +809,10 @@ abstract class TestWebSettingsHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null, expected non-null int.'); - final bool? arg_enabled = args[1] as bool?; + final bool? arg_enabled = (args[1] as bool?); assert(arg_enabled != null, 'Argument for dev.flutter.pigeon.WebSettingsHostApi.setBuiltInZoomControls was null, expected non-null bool.'); api.setBuiltInZoomControls(arg_instanceId!, arg_enabled!); @@ -849,10 +845,10 @@ abstract class TestJavaScriptChannelHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null, expected non-null int.'); - final String? arg_channelName = args[1] as String?; + final String? arg_channelName = (args[1] as String?); assert(arg_channelName != null, 'Argument for dev.flutter.pigeon.JavaScriptChannelHostApi.create was null, expected non-null String.'); api.create(arg_instanceId!, arg_channelName!); @@ -884,10 +880,10 @@ abstract class TestWebViewClientHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebViewClientHostApi.create was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + 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?; + 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!); @@ -920,7 +916,7 @@ abstract class TestDownloadListenerHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.create was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + final int? arg_instanceId = (args[0] as int?); assert(arg_instanceId != null, 'Argument for dev.flutter.pigeon.DownloadListenerHostApi.create was null, expected non-null int.'); api.create(arg_instanceId!); @@ -952,10 +948,10 @@ abstract class TestWebChromeClientHostApi { assert(message != null, 'Argument for dev.flutter.pigeon.WebChromeClientHostApi.create was null.'); final List args = (message as List?)!; - final int? arg_instanceId = args[0] as int?; + 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?; + 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!); 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 29c0c3a0bb34..369ecd67e4a6 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 @@ -14,6 +14,7 @@ import 'android_webview.pigeon.dart'; import 'android_webview_test.mocks.dart'; @GenerateMocks([ + CookieManagerHostApi, DownloadListener, JavaScriptChannel, TestDownloadListenerHostApi, @@ -591,4 +592,20 @@ void main() { }); }); }); + + group('CookieManager', () { + test('setCookie calls setCookie on CookieManagerHostApi', () { + CookieManager.api = MockCookieManagerHostApi(); + CookieManager.instance.setCookie('foo', 'bar'); + verify(CookieManager.api.setCookie('foo', 'bar')); + }); + + test('clearCookies calls clearCookies on CookieManagerHostApi', () { + CookieManager.api = MockCookieManagerHostApi(); + when(CookieManager.api.clearCookies()) + .thenAnswer((_) => Future.value(true)); + CookieManager.instance.clearCookies(); + verify(CookieManager.api.clearCookies()); + }); + }); } 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 4378ed7abf77..b13099ea1539 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,3 @@ -// 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. - // Mocks generated by Mockito 5.0.16 from annotations // in webview_flutter_android/test/android_webview_test.dart. // Do not manually edit this file. @@ -10,8 +6,9 @@ import 'dart:async' as _i4; import 'package:mockito/mockito.dart' as _i1; import 'package:webview_flutter_android/src/android_webview.dart' as _i2; +import 'package:webview_flutter_android/src/android_webview.pigeon.dart' as _i3; -import 'android_webview.pigeon.dart' as _i3; +import 'android_webview.pigeon.dart' as _i5; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters @@ -24,6 +21,28 @@ import 'android_webview.pigeon.dart' as _i3; class _FakeWebSettings_0 extends _i1.Fake implements _i2.WebSettings {} +/// A class which mocks [CookieManagerHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCookieManagerHostApi extends _i1.Mock + implements _i3.CookieManagerHostApi { + MockCookieManagerHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + _i4.Future clearCookies() => + (super.noSuchMethod(Invocation.method(#clearCookies, []), + returnValue: Future.value(false)) as _i4.Future); + @override + _i4.Future setCookie(String? arg_url, String? arg_value) => + (super.noSuchMethod(Invocation.method(#setCookie, [arg_url, arg_value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i4.Future); + @override + String toString() => super.toString(); +} + /// A class which mocks [DownloadListener]. /// /// See the documentation for Mockito's code generation for more information. @@ -67,7 +86,7 @@ class MockJavaScriptChannel extends _i1.Mock implements _i2.JavaScriptChannel { /// /// See the documentation for Mockito's code generation for more information. class MockTestDownloadListenerHostApi extends _i1.Mock - implements _i3.TestDownloadListenerHostApi { + implements _i5.TestDownloadListenerHostApi { MockTestDownloadListenerHostApi() { _i1.throwOnMissingStub(this); } @@ -84,7 +103,7 @@ class MockTestDownloadListenerHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestJavaScriptChannelHostApi extends _i1.Mock - implements _i3.TestJavaScriptChannelHostApi { + implements _i5.TestJavaScriptChannelHostApi { MockTestJavaScriptChannelHostApi() { _i1.throwOnMissingStub(this); } @@ -101,7 +120,7 @@ class MockTestJavaScriptChannelHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestWebChromeClientHostApi extends _i1.Mock - implements _i3.TestWebChromeClientHostApi { + implements _i5.TestWebChromeClientHostApi { MockTestWebChromeClientHostApi() { _i1.throwOnMissingStub(this); } @@ -119,7 +138,7 @@ class MockTestWebChromeClientHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestWebSettingsHostApi extends _i1.Mock - implements _i3.TestWebSettingsHostApi { + implements _i5.TestWebSettingsHostApi { MockTestWebSettingsHostApi() { _i1.throwOnMissingStub(this); } @@ -193,7 +212,7 @@ class MockTestWebSettingsHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestWebViewClientHostApi extends _i1.Mock - implements _i3.TestWebViewClientHostApi { + implements _i5.TestWebViewClientHostApi { MockTestWebViewClientHostApi() { _i1.throwOnMissingStub(this); } @@ -211,7 +230,7 @@ class MockTestWebViewClientHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestWebViewHostApi extends _i1.Mock - implements _i3.TestWebViewHostApi { + implements _i5.TestWebViewHostApi { MockTestWebViewHostApi() { _i1.throwOnMissingStub(this); } diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart new file mode 100644 index 000000000000..5818433ef33f --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart @@ -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. + +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_android_cookie_manager.dart'; +import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; + +import 'webview_android_cookie_manager_test.mocks.dart'; + +@GenerateMocks([android_webview.CookieManager]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + setUp(() { + android_webview.CookieManager.instance = MockCookieManager(); + }); + + test('clearCookies should call android_webview.clearCookies', () { + when(android_webview.CookieManager.instance.clearCookies()) + .thenAnswer((_) => Future.value(true)); + WebViewAndroidCookieManager.instance.clearCookies(); + verify(android_webview.CookieManager.instance.clearCookies()); + }); + + test('setCookie should throw ArgumentError for cookie with invalid path', () { + expect( + () => WebViewAndroidCookieManager.instance.setCookie(const WebViewCookie( + name: 'foo', + value: 'bar', + domain: 'flutter.dev', + path: 'invalid;path', + )), + throwsA(const TypeMatcher()), + ); + }); + + test( + 'setCookie should call android_webview.csetCookie with properly formatted cookie value', + () { + WebViewAndroidCookieManager.instance.setCookie(const WebViewCookie( + name: 'foo&', + value: 'bar@', + domain: 'flutter.dev', + )); + verify(android_webview.CookieManager.instance + .setCookie('flutter.dev', 'foo%26=bar%40; path=/')); + }); +} 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 new file mode 100644 index 000000000000..131977bd3dfd --- /dev/null +++ b/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.mocks.dart @@ -0,0 +1,38 @@ +// Mocks generated by Mockito 5.0.16 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: 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 setCookie(String? url, String? value) => + (super.noSuchMethod(Invocation.method(#setCookie, [url, value]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i3.Future); + @override + _i3.Future clearCookies() => + (super.noSuchMethod(Invocation.method(#clearCookies, []), + returnValue: Future.value(false)) as _i3.Future); + @override + String toString() => super.toString(); +} 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 c9d3324ecfc3..4f20b2d1e328 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 @@ -1,7 +1,3 @@ -// 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. - // Mocks generated by Mockito 5.0.16 from annotations // in webview_flutter_android/test/webview_android_widget_test.dart. // Do not manually edit this file. From 05778158d44494b21e2779872cf09577f191f05f Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 15:15:24 +0100 Subject: [PATCH 03/25] Added iOS implementation for new CookieManager. --- .../webview_flutter_wkwebview/CHANGELOG.md | 4 +- .../ios/Runner.xcodeproj/project.pbxproj | 70 +++++----- .../ios/RunnerTests/FLTCookieManagerTests.m | 127 ++++++++++++++++++ .../FLTWKNavigationDelegateTests.m | 1 + .../example/ios/RunnerTests/FLTWebViewTests.m | 26 +++- .../example/lib/web_view.dart | 33 +++++ .../ios/Classes/FLTCookieManager.h | 6 + .../ios/Classes/FLTCookieManager.m | 62 ++++++++- .../ios/Classes/FLTCookieManager_Test.h | 20 +++ .../ios/Classes/FLTWebViewFlutterPlugin.m | 5 +- .../ios/Classes/FlutterWebView.h | 4 +- .../ios/Classes/FlutterWebView.m | 9 +- .../ios/Classes/FlutterWebView.modulemap | 1 + .../lib/src/webview_ios_cookie_manager.dart | 38 ++++++ .../lib/webview_flutter_wkwebview.dart | 1 + .../webview_flutter_wkwebview/pubspec.yaml | 5 +- .../src/webview_ios_cookie_manager_test.dart | 64 +++++++++ 17 files changed, 430 insertions(+), 46 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTCookieManagerTests.m create mode 100644 packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager_Test.h create mode 100644 packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart create mode 100644 packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index 3b7816188dec..25e9c7613dae 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,6 +1,8 @@ -## NEXT +## 2.5.0 * Integration test fixes. +* Updates compileSdkVersion to 31. +* Implemented new cookie manager for setting cookies and providing initial cookies. ## 2.4.0 diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj index e292b1bd52fa..50faddbe8885 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 46; objects = { /* Begin PBXBuildFile section */ @@ -16,8 +16,9 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - AE8C124DC8CA68E4D9B30EAB /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 528CB85D53C983D2C5DAFDC5 /* libPods-RunnerTests.a */; }; + D7587C3652F6906210B3AE88 /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 17781D9462A1AEA7C99F8E45 /* libPods-RunnerTests.a */; }; DAF0E91266956134538CC667 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 572FFC2B2BA326B420B22679 /* libPods-Runner.a */; }; + E43693B527512C0F00382F85 /* FLTCookieManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E43693B427512C0F00382F85 /* FLTCookieManagerTests.m */; }; F7151F77266057800028CB91 /* FLTWebViewUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F76266057800028CB91 /* FLTWebViewUITests.m */; }; /* End PBXBuildFile section */ @@ -54,10 +55,11 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 17781D9462A1AEA7C99F8E45 /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2286ACB87EA8CA27E739AD6C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 39B2BDAA45DC06EAB8A6C4E7 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 528CB85D53C983D2C5DAFDC5 /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 572FFC2B2BA326B420B22679 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 5C776D27D0DDA247ED5EA72B /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 686B4BF82548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLTWKNavigationDelegateTests.m; sourceTree = ""; }; 68BDCAE923C3F7CB00D9C032 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68BDCAED23C3F7CB00D9C032 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -74,7 +76,7 @@ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B89AA31A64040E4A2F1E0CAF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - C370F140C3A19241FD8C5E64 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + E43693B427512C0F00382F85 /* FLTCookieManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTCookieManagerTests.m; sourceTree = ""; }; F7151F74266057800028CB91 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; F7151F76266057800028CB91 /* FLTWebViewUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTWebViewUITests.m; sourceTree = ""; }; F7151F78266057800028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -86,7 +88,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AE8C124DC8CA68E4D9B30EAB /* libPods-RunnerTests.a in Frameworks */, + D7587C3652F6906210B3AE88 /* libPods-RunnerTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -112,7 +114,7 @@ isa = PBXGroup; children = ( 572FFC2B2BA326B420B22679 /* libPods-Runner.a */, - 528CB85D53C983D2C5DAFDC5 /* libPods-RunnerTests.a */, + 17781D9462A1AEA7C99F8E45 /* libPods-RunnerTests.a */, ); name = Frameworks; sourceTree = ""; @@ -123,6 +125,7 @@ 686B4BF82548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m */, 68BDCAF523C3F97800D9C032 /* FLTWebViewTests.m */, 68BDCAED23C3F7CB00D9C032 /* Info.plist */, + E43693B427512C0F00382F85 /* FLTCookieManagerTests.m */, ); path = RunnerTests; sourceTree = ""; @@ -190,8 +193,8 @@ children = ( F7A1921261392D1CBDAEC2E8 /* Pods-Runner.debug.xcconfig */, B89AA31A64040E4A2F1E0CAF /* Pods-Runner.release.xcconfig */, - C370F140C3A19241FD8C5E64 /* Pods-RunnerTests.debug.xcconfig */, - 5C776D27D0DDA247ED5EA72B /* Pods-RunnerTests.release.xcconfig */, + 39B2BDAA45DC06EAB8A6C4E7 /* Pods-RunnerTests.debug.xcconfig */, + 2286ACB87EA8CA27E739AD6C /* Pods-RunnerTests.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -212,7 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 68BDCAF223C3F7CB00D9C032 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - 0067CEC0658A36CBFF8074E7 /* [CP] Check Pods Manifest.lock */, + AA38EF430495C2FB50F0F114 /* [CP] Check Pods Manifest.lock */, 68BDCAE523C3F7CB00D9C032 /* Sources */, 68BDCAE623C3F7CB00D9C032 /* Frameworks */, 68BDCAE723C3F7CB00D9C032 /* Resources */, @@ -338,7 +341,21 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 0067CEC0658A36CBFF8074E7 /* [CP] Check Pods Manifest.lock */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin\n"; + }; + 6F536C27DD48B395A30EBB65 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -353,28 +370,28 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Thin Binary"; + name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin\n"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; - 6F536C27DD48B395A30EBB65 /* [CP] Check Pods Manifest.lock */ = { + AA38EF430495C2FB50F0F114 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -389,27 +406,13 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -419,6 +422,7 @@ files = ( 334734012669319100DCC49E /* FLTWebViewTests.m in Sources */, 334734022669319400DCC49E /* FLTWKNavigationDelegateTests.m in Sources */, + E43693B527512C0F00382F85 /* FLTCookieManagerTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -477,7 +481,7 @@ /* Begin XCBuildConfiguration section */ 68BDCAF023C3F7CB00D9C032 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = C370F140C3A19241FD8C5E64 /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = 39B2BDAA45DC06EAB8A6C4E7 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -491,7 +495,7 @@ }; 68BDCAF123C3F7CB00D9C032 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5C776D27D0DDA247ED5EA72B /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = 2286ACB87EA8CA27E739AD6C /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTCookieManagerTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTCookieManagerTests.m new file mode 100644 index 000000000000..837c0d892b64 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTCookieManagerTests.m @@ -0,0 +1,127 @@ +// 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 Flutter; +@import XCTest; +@import webview_flutter_wkwebview; +@import webview_flutter_wkwebview.Test; + +// OCMock library doesn't generate a valid modulemap. +#import + +@interface FLTCookieManagerTests : XCTestCase + +@end + +@implementation FLTCookieManagerTests + +- (void)setUp { + [super setUp]; +} + +- (void)testSetCookieForResultSetsCookieAndReturnsResultOnIOS11 { + if (@available(iOS 11.0, *)) { + // Setup + XCTestExpectation *resultExpectation = [self + expectationWithDescription:@"Should return success result when setting cookie completes."]; + [FLTCookieManager.instance setHttpCookieStore:OCMClassMock(WKHTTPCookieStore.class)]; + NSDictionary *arguments = @{ + @"name" : @"foo", + @"value" : @"bar", + @"domain" : @"flutter.dev", + @"path" : @"/", + }; + NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{ + NSHTTPCookieName : arguments[@"name"], + NSHTTPCookieValue : arguments[@"value"], + NSHTTPCookieDomain : arguments[@"domain"], + NSHTTPCookiePath : arguments[@"path"], + }]; + [OCMStub([FLTCookieManager.instance.httpCookieStore setCookie:[OCMArg isEqual:cookie] + completionHandler:[OCMArg any]]) + andDo:^(NSInvocation *invocation) { + void (^setCookieCompletionHandler)(void); + [invocation getArgument:&setCookieCompletionHandler atIndex:3]; + setCookieCompletionHandler(); + }]; + // Run + [[FLTCookieManager instance] + setCookieForResult:^(id _Nullable result) { + XCTAssertNil(result); + [resultExpectation fulfill]; + } + arguments:arguments]; + // Verify + [self waitForExpectationsWithTimeout:30.0 handler:nil]; + } +} + +- (void)testSetCookieForDataSetsCookieOnIOS11 { + if (@available(iOS 11.0, *)) { + // Setup + WKHTTPCookieStore *mockHttpCookieStore = OCMClassMock(WKHTTPCookieStore.class); + [FLTCookieManager.instance setHttpCookieStore:mockHttpCookieStore]; + NSDictionary *cookieData = @{ + @"name" : @"foo", + @"value" : @"bar", + @"domain" : @"flutter.dev", + @"path" : @"/", + }; + // Run + [[FLTCookieManager instance] setCookieForData:cookieData]; + // Verify + NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{ + NSHTTPCookieName : cookieData[@"name"], + NSHTTPCookieValue : cookieData[@"value"], + NSHTTPCookieDomain : cookieData[@"domain"], + NSHTTPCookiePath : cookieData[@"path"], + }]; + OCMVerify([mockHttpCookieStore setCookie:[OCMArg isEqual:cookie] + completionHandler:[OCMArg any]]); + } +} + +- (void)testSetCookiesForDataSetsCookiesOnIOS11 { + if (@available(iOS 11.0, *)) { + // Setup + WKHTTPCookieStore *mockHttpCookieStore = OCMClassMock(WKHTTPCookieStore.class); + [FLTCookieManager.instance setHttpCookieStore:mockHttpCookieStore]; + NSArray *cookieDatas = @[ + @{ + @"name" : @"foo1", + @"value" : @"bar1", + @"domain" : @"flutter.dev", + @"path" : @"/", + }, + @{ + @"name" : @"foo2", + @"value" : @"bar2", + @"domain" : @"flutter2.dev", + @"path" : @"/2", + } + ]; + // Run + [[FLTCookieManager instance] setCookiesForData:cookieDatas]; + // Verify + NSHTTPCookie *cookie1 = [NSHTTPCookie cookieWithProperties:@{ + NSHTTPCookieName : cookieDatas[0][@"name"], + NSHTTPCookieValue : cookieDatas[0][@"value"], + NSHTTPCookieDomain : cookieDatas[0][@"domain"], + NSHTTPCookiePath : cookieDatas[0][@"path"], + }]; + + OCMVerify([mockHttpCookieStore setCookie:[OCMArg isEqual:cookie1] + completionHandler:[OCMArg any]]); + NSHTTPCookie *cookie2 = [NSHTTPCookie cookieWithProperties:@{ + NSHTTPCookieName : cookieDatas[1][@"name"], + NSHTTPCookieValue : cookieDatas[1][@"value"], + NSHTTPCookieDomain : cookieDatas[1][@"domain"], + NSHTTPCookiePath : cookieDatas[1][@"path"], + }]; + OCMVerify([mockHttpCookieStore setCookie:[OCMArg isEqual:cookie2] + completionHandler:[OCMArg any]]); + } +} + +@end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m index a819a9b53d60..d39a9f203d70 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m @@ -5,6 +5,7 @@ @import Flutter; @import XCTest; @import webview_flutter_wkwebview; +@import webview_flutter_wkwebview.Test; // OCMock library doesn't generate a valid modulemap. #import diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m index a3c314a79d2a..6c7c6bffbc3f 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m @@ -16,6 +16,8 @@ @interface FLTWebViewTests : XCTestCase @property(strong, nonatomic) NSObject *mockBinaryMessenger; +@property(strong, nonatomic) FLTCookieManager *mockCookieManager; + @end @implementation FLTWebViewTests @@ -23,6 +25,7 @@ @implementation FLTWebViewTests - (void)setUp { [super setUp]; self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); + self.mockCookieManager = OCMClassMock(FLTCookieManager.class); } - (void)testCanInitFLTWebViewController { @@ -35,8 +38,8 @@ - (void)testCanInitFLTWebViewController { } - (void)testCanInitFLTWebViewFactory { - FLTWebViewFactory *factory = - [[FLTWebViewFactory alloc] initWithMessenger:self.mockBinaryMessenger]; + FLTWebViewFactory *factory = [[FLTWebViewFactory alloc] initWithMessenger:self.mockBinaryMessenger + cookieManager:self.mockCookieManager]; XCTAssertNotNil(factory); } @@ -648,7 +651,7 @@ - (void)testOnLoadUrlLoadsRequestWithSuccessResult { [self waitForExpectationsWithTimeout:30.0 handler:nil]; } -- (void)testOnLoadRequestReturnsErroResultForInvalidRequest { +- (void)testOnLoadRequestReturnsErrorResultForInvalidRequest { // Setup FLTWebViewController *controller = [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400) @@ -697,4 +700,21 @@ - (void)testOnLoadRequestLoadsRequestWithSuccessResult { [self waitForExpectationsWithTimeout:30.0 handler:nil]; } +- (void)testCreateWithFrameShouldSetCookiesOnIOS11 { + if (@available(iOS 11, *)) { + // Setup + FLTWebViewFactory *factory = + [[FLTWebViewFactory alloc] initWithMessenger:self.mockBinaryMessenger + cookieManager:self.mockCookieManager]; + NSArray *cookies = + @[ @{@"name" : @"foo", @"value" : @"bar", @"domain" : @"flutter.dev", @"path" : @"/"} ]; + // Run + [factory createWithFrame:CGRectMake(0, 0, 300, 400) + viewIdentifier:1 + arguments:@{@"cookies" : cookies}]; + // Verify + OCMVerify([_mockCookieManager setCookiesForData:cookies]); + } +} + @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart index ab4b77336765..f7547aafa0ae 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -54,6 +55,7 @@ class WebView extends StatefulWidget { Key? key, this.onWebViewCreated, this.initialUrl, + this.initialCookies = const [], this.javascriptMode = JavascriptMode.disabled, this.javascriptChannels, this.navigationDelegate, @@ -94,6 +96,9 @@ class WebView extends StatefulWidget { /// The initial URL to load. final String? initialUrl; + /// The initial cookies to set. + final List initialCookies; + /// Whether JavaScript execution is enabled. final JavascriptMode javascriptMode; @@ -278,6 +283,7 @@ class _WebViewState extends State { _javascriptChannelRegistry.channels.keys.toSet(), autoMediaPlaybackPolicy: widget.initialMediaPlaybackPolicy, userAgent: widget.userAgent, + cookies: widget.initialCookies, ), javascriptChannelRegistry: _javascriptChannelRegistry, ); @@ -651,3 +657,30 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler { } } } + +class WebViewCookieManager extends WebViewCookieManagerPlatform { + static WebViewCookieManager? _instance; + + static WebViewCookieManager get instance => + _instance ??= WebViewCookieManager._(); + + WebViewCookieManager._(); + + @override + Future clearCookies() async { + if (Platform.isIOS) { + return WebViewIOSCookieManager.instance.clearCookies(); + } else { + return super.clearCookies(); + } + } + + @override + Future setCookie(WebViewCookie cookie) { + if (Platform.isIOS) { + return WebViewIOSCookieManager.instance.setCookie(cookie); + } else { + return super.setCookie(cookie); + } + } +} diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.h index 8fe331875250..dc5b8f589ade 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.h @@ -9,6 +9,12 @@ NS_ASSUME_NONNULL_BEGIN @interface FLTCookieManager : NSObject ++ (FLTCookieManager*)instance; + +- (void)setCookiesForData:(NSArray*)cookies; + +- (void)setCookieForData:(NSDictionary*)cookie; + @end NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.m index f4783ffb4123..39976d11153e 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.m @@ -3,22 +3,32 @@ // found in the LICENSE file. #import "FLTCookieManager.h" +#import "FLTCookieManager_Test.h" @implementation FLTCookieManager { + WKHTTPCookieStore *_httpCookieStore API_AVAILABLE(macos(10.13), ios(11.0)); } -+ (void)registerWithRegistrar:(NSObject *)registrar { - FLTCookieManager *instance = [[FLTCookieManager alloc] init]; ++ (FLTCookieManager *)instance { + static FLTCookieManager *instance = nil; + if (instance == nil) { + instance = [[FLTCookieManager alloc] init]; + } + return instance; +} ++ (void)registerWithRegistrar:(NSObject *)registrar { FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/cookie_manager" binaryMessenger:[registrar messenger]]; - [registrar addMethodCallDelegate:instance channel:channel]; + [registrar addMethodCallDelegate:[self instance] channel:channel]; } - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { if ([[call method] isEqualToString:@"clearCookies"]) { [self clearCookies:result]; + } else if ([[call method] isEqualToString:@"setCookie"]) { + [self setCookieForResult:result arguments:[call arguments]]; } else { result(FlutterMethodNotImplemented); } @@ -46,4 +56,50 @@ - (void)clearCookies:(FlutterResult)result { } } +- (void)setCookiesForData:(NSArray *)cookies { + for (id cookie in cookies) { + [self setCookieForData:cookie]; + } +} + +- (void)setCookieForData:(NSDictionary *)cookieData { + if (@available(iOS 11.0, *)) { + if (!_httpCookieStore) { + _httpCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore]; + } + NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{ + NSHTTPCookieName : cookieData[@"name"], + NSHTTPCookieValue : cookieData[@"value"], + NSHTTPCookieDomain : cookieData[@"domain"], + NSHTTPCookiePath : cookieData[@"path"], + }]; + [_httpCookieStore setCookie:cookie + completionHandler:^{ + }]; + } else { + NSLog(@"Setting cookies is not supported for Flutter WebViews prior to iOS 11."); + } +} + +- (void)setCookieForResult:(FlutterResult)result arguments:(NSDictionary *)arguments { + if (@available(iOS 11.0, *)) { + if (!_httpCookieStore) { + _httpCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore]; + } + NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{ + NSHTTPCookieName : arguments[@"name"], + NSHTTPCookieValue : arguments[@"value"], + NSHTTPCookieDomain : arguments[@"domain"], + NSHTTPCookiePath : arguments[@"path"], + }]; + [_httpCookieStore setCookie:cookie + completionHandler:^{ + result(nil); + }]; + } else { + NSLog(@"Setting cookies is not supported for Flutter WebViews prior to iOS 11."); + result(nil); + } +} + @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager_Test.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager_Test.h new file mode 100644 index 000000000000..fecec4932570 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager_Test.h @@ -0,0 +1,20 @@ +// 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 header is available in the Test module. Import via "@import webview_flutter_wkwebview.Test;" + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTCookieManager () + +@property(nonatomic, strong) + WKHTTPCookieStore *httpCookieStore API_AVAILABLE(macos(10.13), ios(11.0)); + +- (void)setCookieForResult:(FlutterResult)result arguments:(NSDictionary *)arguments; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m index 9f01416acc6a..0d04d6c3a9ee 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m @@ -9,10 +9,11 @@ @implementation FLTWebViewFlutterPlugin + (void)registerWithRegistrar:(NSObject*)registrar { + [FLTCookieManager registerWithRegistrar:registrar]; FLTWebViewFactory* webviewFactory = - [[FLTWebViewFactory alloc] initWithMessenger:registrar.messenger]; + [[FLTWebViewFactory alloc] initWithMessenger:registrar.messenger + cookieManager:[FLTCookieManager instance]]; [registrar registerViewFactory:webviewFactory withId:@"plugins.flutter.io/webview"]; - [FLTCookieManager registerWithRegistrar:registrar]; } @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h index 6d8e463c7b13..145a772c5015 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import #import #import @@ -31,7 +32,8 @@ NS_ASSUME_NONNULL_BEGIN @end @interface FLTWebViewFactory : NSObject -- (instancetype)initWithMessenger:(NSObject*)messenger; +- (instancetype)initWithMessenger:(NSObject*)messenger + cookieManager:(FLTCookieManager*)cookieManager; @end NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m index 351d1ae58760..696fde918be9 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m @@ -10,12 +10,15 @@ @implementation FLTWebViewFactory { NSObject* _messenger; + FLTCookieManager* _cookieManager; } -- (instancetype)initWithMessenger:(NSObject*)messenger { +- (instancetype)initWithMessenger:(NSObject*)messenger + cookieManager:(FLTCookieManager*)cookieManager { self = [super init]; if (self) { _messenger = messenger; + _cookieManager = cookieManager; } return self; } @@ -27,6 +30,10 @@ - (instancetype)initWithMessenger:(NSObject*)messenger { - (NSObject*)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args { + if (@available(iOS 11.0, *)) { + [_cookieManager setCookiesForData:args[@"cookies"]]; + } + FLTWebViewController* webviewController = [[FLTWebViewController alloc] initWithFrame:frame viewIdentifier:viewId arguments:args diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap index fa5143060381..096507557688 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap @@ -6,5 +6,6 @@ framework module webview_flutter_wkwebview { explicit module Test { header "FlutterWebView_Test.h" + header "FLTCookieManager_Test.h" } } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart new file mode 100644 index 000000000000..f6dde177ecf6 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart @@ -0,0 +1,38 @@ +// 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'; + +/// Handles all cookie operations for the current platform. +class WebViewIOSCookieManager extends WebViewCookieManagerPlatform { + WebViewIOSCookieManager._(); + + static WebViewIOSCookieManager? _instance; + + /// Obtain a singleton instance for [WebViewiOSCookieManager]. + static WebViewIOSCookieManager get instance => + _instance ??= WebViewIOSCookieManager._(); + + @override + Future clearCookies() => MethodChannelWebViewPlatform.clearCookies(); + + @override + Future setCookie(WebViewCookie cookie) { + if (!_isValidPath(cookie.path)) { + throw ArgumentError( + 'The path property for the provided cookie was not given a legal value.'); + } + return MethodChannelWebViewPlatform.setCookie(cookie); + } + + 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_wkwebview/lib/webview_flutter_wkwebview.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart index bbec415dccd0..a976bace2c75 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart @@ -3,3 +3,4 @@ // found in the LICENSE file. export 'src/webview_cupertino.dart'; +export 'src/webview_ios_cookie_manager.dart'; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index 466c1a2a4fcd..cdf2598f77eb 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_wkwebview description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control. repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_wkwebview issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 2.4.0 +version: 2.5.0 environment: sdk: ">=2.14.0 <3.0.0" @@ -18,7 +18,8 @@ flutter: dependencies: flutter: sdk: flutter - webview_flutter_platform_interface: ^1.3.0 + webview_flutter_platform_interface: + path: ../webview_flutter_platform_interface dev_dependencies: flutter_driver: diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart new file mode 100644 index 000000000000..10d13e44873e --- /dev/null +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart @@ -0,0 +1,64 @@ +// 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/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; +import 'package:webview_flutter_wkwebview/src/webview_ios_cookie_manager.dart'; + +main() { + TestWidgetsFlutterBinding.ensureInitialized(); + const MethodChannel cookieChannel = + MethodChannel('plugins.flutter.io/cookie_manager'); + final List log = []; + + cookieChannel.setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + + if (methodCall.method == 'clearCookies') { + return true; + } + + // Return null explicitly instead of relying on the implicit null + // returned by the method channel if no return statement is specified. + return null; + }); + + tearDown(() { + log.clear(); + }); + + test('clearCookies should call `clearCookies` on the method channel', + () async { + await WebViewIOSCookieManager.instance.clearCookies(); + expect( + log, + [ + isMethodCall( + 'clearCookies', + arguments: null, + ), + ], + ); + }); + + test('setCookie should call `setCookie` on the method channel', () async { + await WebViewIOSCookieManager.instance.setCookie( + WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev')); + expect( + log, + [ + isMethodCall( + 'setCookie', + arguments: { + 'name': 'foo', + 'value': 'bar', + 'domain': 'flutter.dev', + 'path': '/', + }, + ), + ], + ); + }); +} From 2e3dba3932fd36605b3fbfcb6f20a24f65e4fed9 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 15:16:01 +0100 Subject: [PATCH 04/25] Update pubspec --- packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index cdf2598f77eb..aa52363dadf8 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -18,6 +18,7 @@ flutter: dependencies: flutter: sdk: flutter +# TODO (BeMacized): Update dependency when platform interface has been updated and published. webview_flutter_platform_interface: path: ../webview_flutter_platform_interface From 4816d7132d6400816b6a3f1650a783017a4cd6a4 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 15:22:50 +0100 Subject: [PATCH 05/25] Revert accidental push of ios changes --- .../webview_flutter_wkwebview/CHANGELOG.md | 4 +- .../ios/Runner.xcodeproj/project.pbxproj | 70 +++++----- .../ios/RunnerTests/FLTCookieManagerTests.m | 127 ------------------ .../FLTWKNavigationDelegateTests.m | 1 - .../example/ios/RunnerTests/FLTWebViewTests.m | 26 +--- .../example/lib/web_view.dart | 33 ----- .../ios/Classes/FLTCookieManager.h | 6 - .../ios/Classes/FLTCookieManager.m | 62 +-------- .../ios/Classes/FLTCookieManager_Test.h | 20 --- .../ios/Classes/FLTWebViewFlutterPlugin.m | 5 +- .../ios/Classes/FlutterWebView.h | 4 +- .../ios/Classes/FlutterWebView.m | 9 +- .../ios/Classes/FlutterWebView.modulemap | 1 - .../lib/src/webview_ios_cookie_manager.dart | 38 ------ .../lib/webview_flutter_wkwebview.dart | 1 - .../webview_flutter_wkwebview/pubspec.yaml | 6 +- .../src/webview_ios_cookie_manager_test.dart | 64 --------- 17 files changed, 46 insertions(+), 431 deletions(-) delete mode 100644 packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTCookieManagerTests.m delete mode 100644 packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager_Test.h delete mode 100644 packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart delete mode 100644 packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index 25e9c7613dae..3b7816188dec 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,8 +1,6 @@ -## 2.5.0 +## NEXT * Integration test fixes. -* Updates compileSdkVersion to 31. -* Implemented new cookie manager for setting cookies and providing initial cookies. ## 2.4.0 diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj index 50faddbe8885..e292b1bd52fa 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ @@ -16,9 +16,8 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - D7587C3652F6906210B3AE88 /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 17781D9462A1AEA7C99F8E45 /* libPods-RunnerTests.a */; }; + AE8C124DC8CA68E4D9B30EAB /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 528CB85D53C983D2C5DAFDC5 /* libPods-RunnerTests.a */; }; DAF0E91266956134538CC667 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 572FFC2B2BA326B420B22679 /* libPods-Runner.a */; }; - E43693B527512C0F00382F85 /* FLTCookieManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E43693B427512C0F00382F85 /* FLTCookieManagerTests.m */; }; F7151F77266057800028CB91 /* FLTWebViewUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F76266057800028CB91 /* FLTWebViewUITests.m */; }; /* End PBXBuildFile section */ @@ -55,11 +54,10 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 17781D9462A1AEA7C99F8E45 /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 2286ACB87EA8CA27E739AD6C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 39B2BDAA45DC06EAB8A6C4E7 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 528CB85D53C983D2C5DAFDC5 /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 572FFC2B2BA326B420B22679 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5C776D27D0DDA247ED5EA72B /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 686B4BF82548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLTWKNavigationDelegateTests.m; sourceTree = ""; }; 68BDCAE923C3F7CB00D9C032 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68BDCAED23C3F7CB00D9C032 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -76,7 +74,7 @@ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B89AA31A64040E4A2F1E0CAF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - E43693B427512C0F00382F85 /* FLTCookieManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTCookieManagerTests.m; sourceTree = ""; }; + C370F140C3A19241FD8C5E64 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; F7151F74266057800028CB91 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; F7151F76266057800028CB91 /* FLTWebViewUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTWebViewUITests.m; sourceTree = ""; }; F7151F78266057800028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -88,7 +86,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D7587C3652F6906210B3AE88 /* libPods-RunnerTests.a in Frameworks */, + AE8C124DC8CA68E4D9B30EAB /* libPods-RunnerTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -114,7 +112,7 @@ isa = PBXGroup; children = ( 572FFC2B2BA326B420B22679 /* libPods-Runner.a */, - 17781D9462A1AEA7C99F8E45 /* libPods-RunnerTests.a */, + 528CB85D53C983D2C5DAFDC5 /* libPods-RunnerTests.a */, ); name = Frameworks; sourceTree = ""; @@ -125,7 +123,6 @@ 686B4BF82548DBC7000AEA36 /* FLTWKNavigationDelegateTests.m */, 68BDCAF523C3F97800D9C032 /* FLTWebViewTests.m */, 68BDCAED23C3F7CB00D9C032 /* Info.plist */, - E43693B427512C0F00382F85 /* FLTCookieManagerTests.m */, ); path = RunnerTests; sourceTree = ""; @@ -193,8 +190,8 @@ children = ( F7A1921261392D1CBDAEC2E8 /* Pods-Runner.debug.xcconfig */, B89AA31A64040E4A2F1E0CAF /* Pods-Runner.release.xcconfig */, - 39B2BDAA45DC06EAB8A6C4E7 /* Pods-RunnerTests.debug.xcconfig */, - 2286ACB87EA8CA27E739AD6C /* Pods-RunnerTests.release.xcconfig */, + C370F140C3A19241FD8C5E64 /* Pods-RunnerTests.debug.xcconfig */, + 5C776D27D0DDA247ED5EA72B /* Pods-RunnerTests.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -215,7 +212,7 @@ isa = PBXNativeTarget; buildConfigurationList = 68BDCAF223C3F7CB00D9C032 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - AA38EF430495C2FB50F0F114 /* [CP] Check Pods Manifest.lock */, + 0067CEC0658A36CBFF8074E7 /* [CP] Check Pods Manifest.lock */, 68BDCAE523C3F7CB00D9C032 /* Sources */, 68BDCAE623C3F7CB00D9C032 /* Frameworks */, 68BDCAE723C3F7CB00D9C032 /* Resources */, @@ -341,21 +338,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin\n"; - }; - 6F536C27DD48B395A30EBB65 /* [CP] Check Pods Manifest.lock */ = { + 0067CEC0658A36CBFF8074E7 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -370,28 +353,28 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Run Script"; + name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin\n"; }; - AA38EF430495C2FB50F0F114 /* [CP] Check Pods Manifest.lock */ = { + 6F536C27DD48B395A30EBB65 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -406,13 +389,27 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -422,7 +419,6 @@ files = ( 334734012669319100DCC49E /* FLTWebViewTests.m in Sources */, 334734022669319400DCC49E /* FLTWKNavigationDelegateTests.m in Sources */, - E43693B527512C0F00382F85 /* FLTCookieManagerTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -481,7 +477,7 @@ /* Begin XCBuildConfiguration section */ 68BDCAF023C3F7CB00D9C032 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 39B2BDAA45DC06EAB8A6C4E7 /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = C370F140C3A19241FD8C5E64 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -495,7 +491,7 @@ }; 68BDCAF123C3F7CB00D9C032 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2286ACB87EA8CA27E739AD6C /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = 5C776D27D0DDA247ED5EA72B /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTCookieManagerTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTCookieManagerTests.m deleted file mode 100644 index 837c0d892b64..000000000000 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTCookieManagerTests.m +++ /dev/null @@ -1,127 +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. - -@import Flutter; -@import XCTest; -@import webview_flutter_wkwebview; -@import webview_flutter_wkwebview.Test; - -// OCMock library doesn't generate a valid modulemap. -#import - -@interface FLTCookieManagerTests : XCTestCase - -@end - -@implementation FLTCookieManagerTests - -- (void)setUp { - [super setUp]; -} - -- (void)testSetCookieForResultSetsCookieAndReturnsResultOnIOS11 { - if (@available(iOS 11.0, *)) { - // Setup - XCTestExpectation *resultExpectation = [self - expectationWithDescription:@"Should return success result when setting cookie completes."]; - [FLTCookieManager.instance setHttpCookieStore:OCMClassMock(WKHTTPCookieStore.class)]; - NSDictionary *arguments = @{ - @"name" : @"foo", - @"value" : @"bar", - @"domain" : @"flutter.dev", - @"path" : @"/", - }; - NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{ - NSHTTPCookieName : arguments[@"name"], - NSHTTPCookieValue : arguments[@"value"], - NSHTTPCookieDomain : arguments[@"domain"], - NSHTTPCookiePath : arguments[@"path"], - }]; - [OCMStub([FLTCookieManager.instance.httpCookieStore setCookie:[OCMArg isEqual:cookie] - completionHandler:[OCMArg any]]) - andDo:^(NSInvocation *invocation) { - void (^setCookieCompletionHandler)(void); - [invocation getArgument:&setCookieCompletionHandler atIndex:3]; - setCookieCompletionHandler(); - }]; - // Run - [[FLTCookieManager instance] - setCookieForResult:^(id _Nullable result) { - XCTAssertNil(result); - [resultExpectation fulfill]; - } - arguments:arguments]; - // Verify - [self waitForExpectationsWithTimeout:30.0 handler:nil]; - } -} - -- (void)testSetCookieForDataSetsCookieOnIOS11 { - if (@available(iOS 11.0, *)) { - // Setup - WKHTTPCookieStore *mockHttpCookieStore = OCMClassMock(WKHTTPCookieStore.class); - [FLTCookieManager.instance setHttpCookieStore:mockHttpCookieStore]; - NSDictionary *cookieData = @{ - @"name" : @"foo", - @"value" : @"bar", - @"domain" : @"flutter.dev", - @"path" : @"/", - }; - // Run - [[FLTCookieManager instance] setCookieForData:cookieData]; - // Verify - NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{ - NSHTTPCookieName : cookieData[@"name"], - NSHTTPCookieValue : cookieData[@"value"], - NSHTTPCookieDomain : cookieData[@"domain"], - NSHTTPCookiePath : cookieData[@"path"], - }]; - OCMVerify([mockHttpCookieStore setCookie:[OCMArg isEqual:cookie] - completionHandler:[OCMArg any]]); - } -} - -- (void)testSetCookiesForDataSetsCookiesOnIOS11 { - if (@available(iOS 11.0, *)) { - // Setup - WKHTTPCookieStore *mockHttpCookieStore = OCMClassMock(WKHTTPCookieStore.class); - [FLTCookieManager.instance setHttpCookieStore:mockHttpCookieStore]; - NSArray *cookieDatas = @[ - @{ - @"name" : @"foo1", - @"value" : @"bar1", - @"domain" : @"flutter.dev", - @"path" : @"/", - }, - @{ - @"name" : @"foo2", - @"value" : @"bar2", - @"domain" : @"flutter2.dev", - @"path" : @"/2", - } - ]; - // Run - [[FLTCookieManager instance] setCookiesForData:cookieDatas]; - // Verify - NSHTTPCookie *cookie1 = [NSHTTPCookie cookieWithProperties:@{ - NSHTTPCookieName : cookieDatas[0][@"name"], - NSHTTPCookieValue : cookieDatas[0][@"value"], - NSHTTPCookieDomain : cookieDatas[0][@"domain"], - NSHTTPCookiePath : cookieDatas[0][@"path"], - }]; - - OCMVerify([mockHttpCookieStore setCookie:[OCMArg isEqual:cookie1] - completionHandler:[OCMArg any]]); - NSHTTPCookie *cookie2 = [NSHTTPCookie cookieWithProperties:@{ - NSHTTPCookieName : cookieDatas[1][@"name"], - NSHTTPCookieValue : cookieDatas[1][@"value"], - NSHTTPCookieDomain : cookieDatas[1][@"domain"], - NSHTTPCookiePath : cookieDatas[1][@"path"], - }]; - OCMVerify([mockHttpCookieStore setCookie:[OCMArg isEqual:cookie2] - completionHandler:[OCMArg any]]); - } -} - -@end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m index d39a9f203d70..a819a9b53d60 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWKNavigationDelegateTests.m @@ -5,7 +5,6 @@ @import Flutter; @import XCTest; @import webview_flutter_wkwebview; -@import webview_flutter_wkwebview.Test; // OCMock library doesn't generate a valid modulemap. #import diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m index 6c7c6bffbc3f..a3c314a79d2a 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FLTWebViewTests.m @@ -16,8 +16,6 @@ @interface FLTWebViewTests : XCTestCase @property(strong, nonatomic) NSObject *mockBinaryMessenger; -@property(strong, nonatomic) FLTCookieManager *mockCookieManager; - @end @implementation FLTWebViewTests @@ -25,7 +23,6 @@ @implementation FLTWebViewTests - (void)setUp { [super setUp]; self.mockBinaryMessenger = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); - self.mockCookieManager = OCMClassMock(FLTCookieManager.class); } - (void)testCanInitFLTWebViewController { @@ -38,8 +35,8 @@ - (void)testCanInitFLTWebViewController { } - (void)testCanInitFLTWebViewFactory { - FLTWebViewFactory *factory = [[FLTWebViewFactory alloc] initWithMessenger:self.mockBinaryMessenger - cookieManager:self.mockCookieManager]; + FLTWebViewFactory *factory = + [[FLTWebViewFactory alloc] initWithMessenger:self.mockBinaryMessenger]; XCTAssertNotNil(factory); } @@ -651,7 +648,7 @@ - (void)testOnLoadUrlLoadsRequestWithSuccessResult { [self waitForExpectationsWithTimeout:30.0 handler:nil]; } -- (void)testOnLoadRequestReturnsErrorResultForInvalidRequest { +- (void)testOnLoadRequestReturnsErroResultForInvalidRequest { // Setup FLTWebViewController *controller = [[FLTWebViewController alloc] initWithFrame:CGRectMake(0, 0, 300, 400) @@ -700,21 +697,4 @@ - (void)testOnLoadRequestLoadsRequestWithSuccessResult { [self waitForExpectationsWithTimeout:30.0 handler:nil]; } -- (void)testCreateWithFrameShouldSetCookiesOnIOS11 { - if (@available(iOS 11, *)) { - // Setup - FLTWebViewFactory *factory = - [[FLTWebViewFactory alloc] initWithMessenger:self.mockBinaryMessenger - cookieManager:self.mockCookieManager]; - NSArray *cookies = - @[ @{@"name" : @"foo", @"value" : @"bar", @"domain" : @"flutter.dev", @"path" : @"/"} ]; - // Run - [factory createWithFrame:CGRectMake(0, 0, 300, 400) - viewIdentifier:1 - arguments:@{@"cookies" : cookies}]; - // Verify - OCMVerify([_mockCookieManager setCookiesForData:cookies]); - } -} - @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart index f7547aafa0ae..ab4b77336765 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -55,7 +54,6 @@ class WebView extends StatefulWidget { Key? key, this.onWebViewCreated, this.initialUrl, - this.initialCookies = const [], this.javascriptMode = JavascriptMode.disabled, this.javascriptChannels, this.navigationDelegate, @@ -96,9 +94,6 @@ class WebView extends StatefulWidget { /// The initial URL to load. final String? initialUrl; - /// The initial cookies to set. - final List initialCookies; - /// Whether JavaScript execution is enabled. final JavascriptMode javascriptMode; @@ -283,7 +278,6 @@ class _WebViewState extends State { _javascriptChannelRegistry.channels.keys.toSet(), autoMediaPlaybackPolicy: widget.initialMediaPlaybackPolicy, userAgent: widget.userAgent, - cookies: widget.initialCookies, ), javascriptChannelRegistry: _javascriptChannelRegistry, ); @@ -657,30 +651,3 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler { } } } - -class WebViewCookieManager extends WebViewCookieManagerPlatform { - static WebViewCookieManager? _instance; - - static WebViewCookieManager get instance => - _instance ??= WebViewCookieManager._(); - - WebViewCookieManager._(); - - @override - Future clearCookies() async { - if (Platform.isIOS) { - return WebViewIOSCookieManager.instance.clearCookies(); - } else { - return super.clearCookies(); - } - } - - @override - Future setCookie(WebViewCookie cookie) { - if (Platform.isIOS) { - return WebViewIOSCookieManager.instance.setCookie(cookie); - } else { - return super.setCookie(cookie); - } - } -} diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.h index dc5b8f589ade..8fe331875250 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.h @@ -9,12 +9,6 @@ NS_ASSUME_NONNULL_BEGIN @interface FLTCookieManager : NSObject -+ (FLTCookieManager*)instance; - -- (void)setCookiesForData:(NSArray*)cookies; - -- (void)setCookieForData:(NSDictionary*)cookie; - @end NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.m index 39976d11153e..f4783ffb4123 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager.m @@ -3,32 +3,22 @@ // found in the LICENSE file. #import "FLTCookieManager.h" -#import "FLTCookieManager_Test.h" @implementation FLTCookieManager { - WKHTTPCookieStore *_httpCookieStore API_AVAILABLE(macos(10.13), ios(11.0)); -} - -+ (FLTCookieManager *)instance { - static FLTCookieManager *instance = nil; - if (instance == nil) { - instance = [[FLTCookieManager alloc] init]; - } - return instance; } + (void)registerWithRegistrar:(NSObject *)registrar { + FLTCookieManager *instance = [[FLTCookieManager alloc] init]; + FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/cookie_manager" binaryMessenger:[registrar messenger]]; - [registrar addMethodCallDelegate:[self instance] channel:channel]; + [registrar addMethodCallDelegate:instance channel:channel]; } - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { if ([[call method] isEqualToString:@"clearCookies"]) { [self clearCookies:result]; - } else if ([[call method] isEqualToString:@"setCookie"]) { - [self setCookieForResult:result arguments:[call arguments]]; } else { result(FlutterMethodNotImplemented); } @@ -56,50 +46,4 @@ - (void)clearCookies:(FlutterResult)result { } } -- (void)setCookiesForData:(NSArray *)cookies { - for (id cookie in cookies) { - [self setCookieForData:cookie]; - } -} - -- (void)setCookieForData:(NSDictionary *)cookieData { - if (@available(iOS 11.0, *)) { - if (!_httpCookieStore) { - _httpCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore]; - } - NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{ - NSHTTPCookieName : cookieData[@"name"], - NSHTTPCookieValue : cookieData[@"value"], - NSHTTPCookieDomain : cookieData[@"domain"], - NSHTTPCookiePath : cookieData[@"path"], - }]; - [_httpCookieStore setCookie:cookie - completionHandler:^{ - }]; - } else { - NSLog(@"Setting cookies is not supported for Flutter WebViews prior to iOS 11."); - } -} - -- (void)setCookieForResult:(FlutterResult)result arguments:(NSDictionary *)arguments { - if (@available(iOS 11.0, *)) { - if (!_httpCookieStore) { - _httpCookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore]; - } - NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:@{ - NSHTTPCookieName : arguments[@"name"], - NSHTTPCookieValue : arguments[@"value"], - NSHTTPCookieDomain : arguments[@"domain"], - NSHTTPCookiePath : arguments[@"path"], - }]; - [_httpCookieStore setCookie:cookie - completionHandler:^{ - result(nil); - }]; - } else { - NSLog(@"Setting cookies is not supported for Flutter WebViews prior to iOS 11."); - result(nil); - } -} - @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager_Test.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager_Test.h deleted file mode 100644 index fecec4932570..000000000000 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTCookieManager_Test.h +++ /dev/null @@ -1,20 +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. - -// This header is available in the Test module. Import via "@import webview_flutter_wkwebview.Test;" - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface FLTCookieManager () - -@property(nonatomic, strong) - WKHTTPCookieStore *httpCookieStore API_AVAILABLE(macos(10.13), ios(11.0)); - -- (void)setCookieForResult:(FlutterResult)result arguments:(NSDictionary *)arguments; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m index 0d04d6c3a9ee..9f01416acc6a 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m @@ -9,11 +9,10 @@ @implementation FLTWebViewFlutterPlugin + (void)registerWithRegistrar:(NSObject*)registrar { - [FLTCookieManager registerWithRegistrar:registrar]; FLTWebViewFactory* webviewFactory = - [[FLTWebViewFactory alloc] initWithMessenger:registrar.messenger - cookieManager:[FLTCookieManager instance]]; + [[FLTWebViewFactory alloc] initWithMessenger:registrar.messenger]; [registrar registerViewFactory:webviewFactory withId:@"plugins.flutter.io/webview"]; + [FLTCookieManager registerWithRegistrar:registrar]; } @end diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h index 145a772c5015..6d8e463c7b13 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.h @@ -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 #import #import @@ -32,8 +31,7 @@ NS_ASSUME_NONNULL_BEGIN @end @interface FLTWebViewFactory : NSObject -- (instancetype)initWithMessenger:(NSObject*)messenger - cookieManager:(FLTCookieManager*)cookieManager; +- (instancetype)initWithMessenger:(NSObject*)messenger; @end NS_ASSUME_NONNULL_END diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m index 696fde918be9..351d1ae58760 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.m @@ -10,15 +10,12 @@ @implementation FLTWebViewFactory { NSObject* _messenger; - FLTCookieManager* _cookieManager; } -- (instancetype)initWithMessenger:(NSObject*)messenger - cookieManager:(FLTCookieManager*)cookieManager { +- (instancetype)initWithMessenger:(NSObject*)messenger { self = [super init]; if (self) { _messenger = messenger; - _cookieManager = cookieManager; } return self; } @@ -30,10 +27,6 @@ - (instancetype)initWithMessenger:(NSObject*)messenger - (NSObject*)createWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args { - if (@available(iOS 11.0, *)) { - [_cookieManager setCookiesForData:args[@"cookies"]]; - } - FLTWebViewController* webviewController = [[FLTWebViewController alloc] initWithFrame:frame viewIdentifier:viewId arguments:args diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap index 096507557688..fa5143060381 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap +++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FlutterWebView.modulemap @@ -6,6 +6,5 @@ framework module webview_flutter_wkwebview { explicit module Test { header "FlutterWebView_Test.h" - header "FLTCookieManager_Test.h" } } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart deleted file mode 100644 index f6dde177ecf6..000000000000 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart +++ /dev/null @@ -1,38 +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. - -import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; - -/// Handles all cookie operations for the current platform. -class WebViewIOSCookieManager extends WebViewCookieManagerPlatform { - WebViewIOSCookieManager._(); - - static WebViewIOSCookieManager? _instance; - - /// Obtain a singleton instance for [WebViewiOSCookieManager]. - static WebViewIOSCookieManager get instance => - _instance ??= WebViewIOSCookieManager._(); - - @override - Future clearCookies() => MethodChannelWebViewPlatform.clearCookies(); - - @override - Future setCookie(WebViewCookie cookie) { - if (!_isValidPath(cookie.path)) { - throw ArgumentError( - 'The path property for the provided cookie was not given a legal value.'); - } - return MethodChannelWebViewPlatform.setCookie(cookie); - } - - 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_wkwebview/lib/webview_flutter_wkwebview.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart index a976bace2c75..bbec415dccd0 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/webview_flutter_wkwebview.dart @@ -3,4 +3,3 @@ // found in the LICENSE file. export 'src/webview_cupertino.dart'; -export 'src/webview_ios_cookie_manager.dart'; diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index aa52363dadf8..466c1a2a4fcd 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_wkwebview description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control. repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter_wkwebview issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 2.5.0 +version: 2.4.0 environment: sdk: ">=2.14.0 <3.0.0" @@ -18,9 +18,7 @@ flutter: dependencies: flutter: sdk: flutter -# TODO (BeMacized): Update dependency when platform interface has been updated and published. - webview_flutter_platform_interface: - path: ../webview_flutter_platform_interface + webview_flutter_platform_interface: ^1.3.0 dev_dependencies: flutter_driver: diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart deleted file mode 100644 index 10d13e44873e..000000000000 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart +++ /dev/null @@ -1,64 +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. - -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; -import 'package:webview_flutter_wkwebview/src/webview_ios_cookie_manager.dart'; - -main() { - TestWidgetsFlutterBinding.ensureInitialized(); - const MethodChannel cookieChannel = - MethodChannel('plugins.flutter.io/cookie_manager'); - final List log = []; - - cookieChannel.setMockMethodCallHandler((MethodCall methodCall) async { - log.add(methodCall); - - if (methodCall.method == 'clearCookies') { - return true; - } - - // Return null explicitly instead of relying on the implicit null - // returned by the method channel if no return statement is specified. - return null; - }); - - tearDown(() { - log.clear(); - }); - - test('clearCookies should call `clearCookies` on the method channel', - () async { - await WebViewIOSCookieManager.instance.clearCookies(); - expect( - log, - [ - isMethodCall( - 'clearCookies', - arguments: null, - ), - ], - ); - }); - - test('setCookie should call `setCookie` on the method channel', () async { - await WebViewIOSCookieManager.instance.setCookie( - WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev')); - expect( - log, - [ - isMethodCall( - 'setCookie', - arguments: { - 'name': 'foo', - 'value': 'bar', - 'domain': 'flutter.dev', - 'path': '/', - }, - ), - ], - ); - }); -} From 34c680eb1e7d0a5b025248a148c58008c6b97686 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 15:30:45 +0100 Subject: [PATCH 06/25] Update deprecation notice --- .../lib/src/platform_interface/webview_platform.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart index a105adc5fc45..65a02f59c8ad 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart @@ -60,7 +60,7 @@ abstract class WebViewPlatform { /// Clears all cookies for all [WebView] instances. /// /// Returns true if cookies were present before clearing, else false. - @Deprecated('Use `WebViewCookieManager.clearCookies` instead.') + @Deprecated('Use `WebViewCookieManagerPlatform.clearCookies` instead.') Future clearCookies() { throw UnimplementedError( "WebView clearCookies is not implemented on the current platform"); From 0d0f2816ecb78d316628432f34c65f30a8b3de8a Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 16:05:11 +0100 Subject: [PATCH 07/25] Fix analysis issues --- .../webview_method_channel.dart | 5 +++-- .../platform_interface.dart | 2 +- .../platform_interface/webview_platform.dart | 1 - .../lib/src/types/creation_params.dart | 2 +- .../lib/src/types/types.dart | 2 +- .../lib/src/types/webview_cookie.dart | 21 ++++++++++++------- .../webview_method_channel_test.dart | 6 +++--- .../webview_cookie_manager_test.dart | 2 +- .../test/src/types/webview_cookie_test.dart | 2 +- 9 files changed, 24 insertions(+), 19 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart index 45c73cf6f9d1..61e0dd7e247a 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/method_channel/webview_method_channel.dart @@ -266,8 +266,9 @@ class MethodChannelWebViewPlatform implements WebViewPlatformController { 'userAgent': creationParams.userAgent, 'autoMediaPlaybackPolicy': creationParams.autoMediaPlaybackPolicy.index, 'usesHybridComposition': usesHybridComposition, - 'cookies': - creationParams.cookies.map((cookie) => cookie.toJson()).toList() + 'cookies': creationParams.cookies + .map((WebViewCookie cookie) => cookie.toJson()) + .toList() }; } } diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/platform_interface.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/platform_interface.dart index be42dcbf7c54..a6967a5410f4 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/platform_interface.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/platform_interface.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. export 'javascript_channel_registry.dart'; +export 'webview_cookie_manager.dart'; export 'webview_platform.dart'; export 'webview_platform_callbacks_handler.dart'; export 'webview_platform_controller.dart'; -export 'webview_cookie_manager.dart'; diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart index 9af4493d3174..a472f00d4bd2 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_platform.dart @@ -6,7 +6,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; import 'package:webview_flutter_platform_interface/src/platform_interface/javascript_channel_registry.dart'; -import 'package:webview_flutter_platform_interface/src/types/webview_cookie.dart'; import '../types/types.dart'; import 'webview_platform_callbacks_handler.dart'; diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/creation_params.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/creation_params.dart index 477878b16b7b..e9f5ef598b1d 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/creation_params.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/creation_params.dart @@ -61,6 +61,6 @@ class CreationParams { @override String toString() { - return '$runtimeType(initialUrl: $initialUrl, settings: $webSettings, javascriptChannelNames: $javascriptChannelNames, UserAgent: $userAgent, cookies: $cookies)'; + return 'CreationParams(initialUrl: $initialUrl, settings: $webSettings, javascriptChannelNames: $javascriptChannelNames, UserAgent: $userAgent, cookies: $cookies)'; } } diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart index 9956c9250602..f2bcf19f42fd 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/types.dart @@ -10,5 +10,5 @@ export 'javascript_mode.dart'; export 'web_resource_error.dart'; export 'web_resource_error_type.dart'; export 'web_settings.dart'; -export 'webview_request.dart'; export 'webview_cookie.dart'; +export 'webview_request.dart'; diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart index 5725462f5956..c50b3da5b68f 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart @@ -6,6 +6,13 @@ /// /// The `autoMediaPlaybackPolicy` parameter must not be null. class WebViewCookie { + /// Construct a new [WebViewCookie]. + const WebViewCookie( + {required this.name, + required this.value, + required this.domain, + this.path = '/'}); + /// The name of the cookie. /// /// Its value should match "cookie-name" in RFC6265bis: @@ -30,15 +37,13 @@ class WebViewCookie { /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 final String path; - /// Construct a new [WebViewCookie]. - const WebViewCookie( - {required this.name, - required this.value, - required this.domain, - this.path = '/'}); - /// Serialize a [WebViewCookie] to a Map. Map toJson() { - return {'name': name, 'value': value, 'domain': domain, 'path': path}; + return { + 'name': name, + 'value': value, + 'domain': domain, + 'path': path + }; } } diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart index d57366e0455a..0432373fc8ac 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/method_channel/webview_method_channel_test.dart @@ -592,15 +592,15 @@ void main() { }); test('setCookie', () async { - await MethodChannelWebViewPlatform.setCookie( - WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev')); + await MethodChannelWebViewPlatform.setCookie(const WebViewCookie( + name: 'foo', value: 'bar', domain: 'flutter.dev')); expect( log, [ isMethodCall( 'setCookie', - arguments: { + arguments: { 'name': 'foo', 'value': 'bar', 'domain': 'flutter.dev', diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/platform_interface/webview_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/platform_interface/webview_cookie_manager_test.dart index c03b7238415b..e0aae2146abc 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/test/src/platform_interface/webview_cookie_manager_test.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/platform_interface/webview_cookie_manager_test.dart @@ -18,7 +18,7 @@ void main() { }); test('setCookie should throw UnimplementedError', () { - WebViewCookie cookie = + const WebViewCookie cookie = WebViewCookie(domain: 'flutter.dev', name: 'foo', value: 'bar'); expect(() => cookieManager!.setCookie(cookie), throwsUnimplementedError); }); diff --git a/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_cookie_test.dart b/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_cookie_test.dart index 79db8a431dc0..f058b8649b96 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_cookie_test.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/test/src/types/webview_cookie_test.dart @@ -10,7 +10,7 @@ void main() { WebViewCookie cookie; Map serializedCookie; // Test serialization - cookie = WebViewCookie( + cookie = const WebViewCookie( name: 'foo', value: 'bar', domain: 'example.com', path: '/test'); serializedCookie = cookie.toJson(); expect(serializedCookie['name'], 'foo'); From 490da19421cbe9cbef9df584be205db78a0c9e2b Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 19:51:46 +0100 Subject: [PATCH 08/25] Enforce extending class for cookie manager platform interface --- .../webview_cookie_manager.dart | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_cookie_manager.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_cookie_manager.dart index 8fb087d2ac9e..d960926e419c 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_cookie_manager.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/platform_interface/webview_cookie_manager.dart @@ -2,12 +2,38 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:webview_flutter_platform_interface/src/types/webview_cookie.dart'; /// Interface for a platform implementation of a cookie manager. /// -/// This interface should only be extended, not implemented, as more methods may be added later. -abstract class WebViewCookieManagerPlatform { +/// Platform implementations should extend this class rather than implement it as `webview_flutter` +/// does not consider newly added methods to be breaking changes. Extending this class +/// (using `extends`) ensures that the subclass will get the default implementation, while +/// platform implementations that `implements` this interface will be broken by newly added +/// [WebViewCookieManagerPlatform] methods. +abstract class WebViewCookieManagerPlatform extends PlatformInterface { + /// Constructs a WebViewCookieManagerPlatform. + WebViewCookieManagerPlatform() : super(token: _token); + + static final Object _token = Object(); + + static WebViewCookieManagerPlatform? _instance; + + /// The instance of [WebViewCookieManagerPlatform] to use. + static WebViewCookieManagerPlatform? get instance => _instance; + + /// Platform-specific plugins should set this with their own platform-specific + /// class that extends [WebViewCookieManagerPlatform] when they register themselves. + static set instance(WebViewCookieManagerPlatform? instance) { + if (instance == null) { + throw AssertionError( + 'Platform interfaces can only be set to a non-null instance'); + } + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + /// Clears all cookies for all [WebView] instances. /// /// Returns true if cookies were present before clearing, else false. From 8eb7bf5707787dfb342814411f7574126a836897 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 19:52:28 +0100 Subject: [PATCH 09/25] Update to match platform interface changes --- .../CookieManagerHostApiImpl.java | 1 - .../example/lib/web_view.dart | 27 ++++++------------- .../lib/webview_android.dart | 2 +- .../lib/webview_android_cookie_manager.dart | 8 ------ .../lib/webview_android_widget.dart | 2 +- .../webview_android_cookie_manager_test.dart | 6 ++--- 6 files changed, 13 insertions(+), 33 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java index 337301e3453d..09c35d0329fb 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java @@ -3,7 +3,6 @@ import android.os.Build; import android.webkit.CookieManager; - class CookieManagerHostApiImpl implements GeneratedAndroidWebView.CookieManagerHostApi { @Override public void clearCookies(GeneratedAndroidWebView.Result result) { diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart index 1e54ae63c7cf..6b97affed0fe 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart @@ -639,29 +639,18 @@ WebSettings _webSettingsFromWidget(WebView widget) { ); } +/// App-facing cookie manager that exposes the correct platform implementation. class WebViewCookieManager extends WebViewCookieManagerPlatform { - static WebViewCookieManager? _instance; - - static WebViewCookieManager get instance => - _instance ??= WebViewCookieManager._(); - WebViewCookieManager._(); - @override - Future clearCookies() async { - if (Platform.isAndroid) { - return WebViewAndroidCookieManager.instance.clearCookies(); - } else { - return super.clearCookies(); - } - } - - @override - Future setCookie(WebViewCookie cookie) { - if (Platform.isAndroid) { - return WebViewAndroidCookieManager.instance.setCookie(cookie); + /// Returns an instance of the cookie manager for the current platform. + static WebViewCookieManagerPlatform get instance { + if (WebViewCookieManagerPlatform.instance == null && Platform.isAndroid) { + WebViewCookieManagerPlatform.instance = WebViewAndroidCookieManager(); } else { - return super.setCookie(cookie); + throw AssertionError( + 'This platform is currently unsupported for webview_flutter_android.'); } + return WebViewCookieManagerPlatform.instance!; } } diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index 2d1fe1433dca..f1e6551a4109 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -67,5 +67,5 @@ class AndroidWebView implements WebViewPlatform { @override Future clearCookies() => - WebViewAndroidCookieManager.instance.clearCookies(); + WebViewCookieManagerPlatform.instance!.clearCookies(); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart index 62be234dc4db..bba75ff4f613 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android_cookie_manager.dart @@ -8,14 +8,6 @@ import 'package:webview_flutter_platform_interface/webview_flutter_platform_inte /// Handles all cookie operations for the current platform. class WebViewAndroidCookieManager extends WebViewCookieManagerPlatform { - WebViewAndroidCookieManager._(); - - static WebViewAndroidCookieManager? _instance; - - /// Obtain a singleton instance for [WebViewAndroidCookieManager]. - static WebViewAndroidCookieManager get instance => - _instance ??= WebViewAndroidCookieManager._(); - @override Future clearCookies() => android_webview.CookieManager.instance.clearCookies(); 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 a841984d47c3..4b83f54e1566 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 @@ -283,7 +283,7 @@ class WebViewAndroidPlatformController extends WebViewPlatformController { addJavascriptChannels(creationParams.javascriptChannelNames); creationParams.cookies - .forEach(WebViewAndroidCookieManager.instance.setCookie); + .forEach(WebViewCookieManagerPlatform.instance!.setCookie); } Future _setHasProgressTracking(bool hasProgressTracking) async { diff --git a/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart index 5818433ef33f..4f274ff4499f 100644 --- a/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart +++ b/packages/webview_flutter/webview_flutter_android/test/webview_android_cookie_manager_test.dart @@ -23,13 +23,13 @@ void main() { test('clearCookies should call android_webview.clearCookies', () { when(android_webview.CookieManager.instance.clearCookies()) .thenAnswer((_) => Future.value(true)); - WebViewAndroidCookieManager.instance.clearCookies(); + WebViewAndroidCookieManager().clearCookies(); verify(android_webview.CookieManager.instance.clearCookies()); }); test('setCookie should throw ArgumentError for cookie with invalid path', () { expect( - () => WebViewAndroidCookieManager.instance.setCookie(const WebViewCookie( + () => WebViewAndroidCookieManager().setCookie(const WebViewCookie( name: 'foo', value: 'bar', domain: 'flutter.dev', @@ -42,7 +42,7 @@ void main() { test( 'setCookie should call android_webview.csetCookie with properly formatted cookie value', () { - WebViewAndroidCookieManager.instance.setCookie(const WebViewCookie( + WebViewAndroidCookieManager().setCookie(const WebViewCookie( name: 'foo&', value: 'bar@', domain: 'flutter.dev', From 6f9742ad6f127299458552478ac9a280bb992b41 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 30 Nov 2021 14:29:28 +0100 Subject: [PATCH 10/25] Process PR feedback --- .../lib/src/types/webview_cookie.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart index c50b3da5b68f..64142929d04d 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart @@ -2,42 +2,42 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/// Configuration to use when creating a new [WebViewPlatformController]. -/// -/// The `autoMediaPlaybackPolicy` parameter must not be null. +/// A cookie that can be set globally for all web views +/// using [WebViewCookieManagerPlatform]. class WebViewCookie { - /// Construct a new [WebViewCookie]. + /// Constructs a new [WebViewCookie]. const WebViewCookie( {required this.name, required this.value, required this.domain, this.path = '/'}); - /// The name of the cookie. + /// The cookie-name of the cookie. /// /// Its value should match "cookie-name" in RFC6265bis: /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 final String name; - /// The value of the cookie. + /// The cookie-value of the cookie. /// /// Its value should match "cookie-value" in RFC6265bis: /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 final String value; - /// The value of the cookie. + /// The domain-value of the cookie. /// /// Its value should match "domain-value" in RFC6265bis: /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 final String domain; - /// The value of the cookie. + /// The path-value of the cookie. + /// Is set to `/` in the constructor by default. /// /// Its value should match "path-value" in RFC6265bis: /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 final String path; - /// Serialize a [WebViewCookie] to a Map. + /// Serializes a [WebViewCookie] to a Map. Map toJson() { return { 'name': name, From c7067c0565af65cbcda45d86ffbb63e8b07048a6 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 30 Nov 2021 14:33:15 +0100 Subject: [PATCH 11/25] Process PR feedback --- .../lib/src/types/webview_cookie.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart index 64142929d04d..406c510afd4b 100644 --- a/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart +++ b/packages/webview_flutter/webview_flutter_platform_interface/lib/src/types/webview_cookie.dart @@ -37,7 +37,7 @@ class WebViewCookie { /// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-02#section-4.1.1 final String path; - /// Serializes a [WebViewCookie] to a Map. + /// Serializes the [WebViewCookie] to a Map. Map toJson() { return { 'name': name, From 8f5bb778c8af95152a81544c6d1a768ae7e50b8b Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 30 Nov 2021 14:43:53 +0100 Subject: [PATCH 12/25] Fix issue with WebViewCookieManager --- .../example/lib/web_view.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart index 6b97affed0fe..c2d6107b3c7c 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart @@ -645,11 +645,13 @@ class WebViewCookieManager extends WebViewCookieManagerPlatform { /// Returns an instance of the cookie manager for the current platform. static WebViewCookieManagerPlatform get instance { - if (WebViewCookieManagerPlatform.instance == null && Platform.isAndroid) { - WebViewCookieManagerPlatform.instance = WebViewAndroidCookieManager(); - } else { - throw AssertionError( - 'This platform is currently unsupported for webview_flutter_android.'); + if (WebViewCookieManagerPlatform.instance == null) { + if (Platform.isAndroid) { + WebViewCookieManagerPlatform.instance = WebViewAndroidCookieManager(); + } else { + throw AssertionError( + 'This platform is currently unsupported for webview_flutter_android.'); + } } return WebViewCookieManagerPlatform.instance!; } From cdc302e16cc7e85beb41f12c672ffc9449eda8f4 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 1 Dec 2021 10:10:31 +0100 Subject: [PATCH 13/25] Add fix for platform implementation registration. --- .../lib/webview_android_widget.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) 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 4b83f54e1566..7ea4a635661e 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 @@ -276,14 +276,17 @@ class WebViewAndroidPlatformController extends WebViewPlatformController { } webView.settings.setMediaPlaybackRequiresUserGesture( - creationParams.autoMediaPlaybackPolicy != - AutoMediaPlaybackPolicy.always_allow, + creationParams.autoMediaPlaybackPolicy != AutoMediaPlaybackPolicy.always_allow, ); addJavascriptChannels(creationParams.javascriptChannelNames); - creationParams.cookies - .forEach(WebViewCookieManagerPlatform.instance!.setCookie); + /// TODO (BeMacized): Remove once platform implementations + /// are able to register themselves (Flutter >=2.8). + /// https://github.com/flutter/flutter/issues/94224 + WebViewCookieManagerPlatform.instance ??= WebViewAndroidCookieManager(); + + creationParams.cookies.forEach(WebViewCookieManagerPlatform.instance!.setCookie); } Future _setHasProgressTracking(bool hasProgressTracking) async { From 9f98faf40c42d84bd2c492de27532fc03ab34c59 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Thu, 2 Dec 2021 11:59:01 +0100 Subject: [PATCH 14/25] Fix build issue --- .../webview_flutter_android/android/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/android/build.gradle b/packages/webview_flutter/webview_flutter_android/android/build.gradle index c087839d2777..37954b36a834 100644 --- a/packages/webview_flutter/webview_flutter_android/android/build.gradle +++ b/packages/webview_flutter/webview_flutter_android/android/build.gradle @@ -43,8 +43,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } testOptions { From a0c5c761c7d3593a3abba20cf20646b5c25cf403 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Thu, 2 Dec 2021 15:04:11 +0100 Subject: [PATCH 15/25] Fix analysis errors (excl. pubspec) --- .../webview_flutter_android/example/lib/main.dart | 2 +- .../webview_flutter_android/example/lib/web_view.dart | 2 +- .../webview_flutter_android/lib/src/android_webview.dart | 1 + .../webview_flutter_android/lib/webview_android.dart | 1 - .../webview_flutter_android/lib/webview_android_widget.dart | 6 +++--- 5 files changed, 6 insertions(+), 6 deletions(-) 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 bc43c16d4498..17459d6f7b1b 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart @@ -300,7 +300,7 @@ class _SampleMenu extends StatelessWidget { Future _onClearCookies( WebViewController controller, BuildContext context) async { - final bool hadCookies = await WebView.platform.clearCookies(); + final bool hadCookies = await WebViewCookieManager.instance.clearCookies(); String message = 'There were cookies. Now, they are gone!'; if (!hadCookies) { message = 'There are no cookies.'; diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart index fb03cd02146d..ce5fb95f1f60 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart @@ -63,7 +63,7 @@ class WebView extends StatefulWidget { Key? key, this.onWebViewCreated, this.initialUrl, - this.initialCookies = const [], + this.initialCookies = const [], this.javascriptMode = JavascriptMode.disabled, this.javascriptChannels, this.navigationDelegate, 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 4de44f3aa6f9..1ae8bccb2e96 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 @@ -366,6 +366,7 @@ class CookieManager { static CookieManager? _instance; + /// Gets the globally set CookieManager instance. static CookieManager get instance => _instance ??= CookieManager._(); /// Setter for the singleton value, for testing purposes only. diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index f1e6551a4109..9027b0280d19 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; -import 'package:webview_flutter_android/webview_android_cookie_manager.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; import 'src/android_webview.dart'; 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 1ecef37c4ab2..89b76b37674e 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 @@ -299,9 +299,9 @@ class WebViewAndroidPlatformController extends WebViewPlatformController { addJavascriptChannels(creationParams.javascriptChannelNames); - /// TODO (BeMacized): Remove once platform implementations - /// are able to register themselves (Flutter >=2.8). - /// https://github.com/flutter/flutter/issues/94224 + // TODO(BeMacized): Remove once platform implementations + // are able to register themselves (Flutter >=2.8), + // https://github.com/flutter/flutter/issues/94224 WebViewCookieManagerPlatform.instance ??= WebViewAndroidCookieManager(); creationParams.cookies.forEach(WebViewCookieManagerPlatform.instance!.setCookie); From a4e663fd26857aeeada93d02cbb99a391b837522 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Thu, 2 Dec 2021 15:09:46 +0100 Subject: [PATCH 16/25] Format --- .../webview_flutter_android/lib/webview_android_widget.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 89b76b37674e..e6dfb6573cee 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 @@ -294,7 +294,8 @@ class WebViewAndroidPlatformController extends WebViewPlatformController { } webView.settings.setMediaPlaybackRequiresUserGesture( - creationParams.autoMediaPlaybackPolicy != AutoMediaPlaybackPolicy.always_allow, + creationParams.autoMediaPlaybackPolicy != + AutoMediaPlaybackPolicy.always_allow, ); addJavascriptChannels(creationParams.javascriptChannelNames); @@ -304,7 +305,8 @@ class WebViewAndroidPlatformController extends WebViewPlatformController { // https://github.com/flutter/flutter/issues/94224 WebViewCookieManagerPlatform.instance ??= WebViewAndroidCookieManager(); - creationParams.cookies.forEach(WebViewCookieManagerPlatform.instance!.setCookie); + creationParams.cookies + .forEach(WebViewCookieManagerPlatform.instance!.setCookie); } Future _setHasProgressTracking(bool hasProgressTracking) async { From d80dc54abfacac875e00e4d481b38dda6574402a Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Fri, 3 Dec 2021 13:15:36 +0100 Subject: [PATCH 17/25] Updated platform interface dependency --- packages/webview_flutter/webview_flutter_android/pubspec.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 125d2d32130b..e3994a0d98dc 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -19,9 +19,7 @@ flutter: dependencies: flutter: sdk: flutter -# TODO (BeMacized): Update dependency once platform interface has been published. - webview_flutter_platform_interface: - path: ../webview_flutter_platform_interface + webview_flutter_platform_interface: ^1.7.0 dev_dependencies: build_runner: ^2.1.4 From b75cedaa48e2849a2219df2510ce08c43cb1d7dd Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Fri, 3 Dec 2021 13:22:00 +0100 Subject: [PATCH 18/25] Add missing license headers --- .../plugins/webviewflutter/CookieManagerHostApiImpl.java | 4 ++++ .../plugins/webviewflutter/GeneratedAndroidWebView.java | 4 ++++ .../plugins/webviewflutter/CookieManagerHostApiImplTest.java | 4 ++++ .../lib/src/android_webview.pigeon.dart | 4 ++++ .../webview_flutter_android/test/android_webview.pigeon.dart | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java index 09c35d0329fb..9fd970e61866 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java @@ -1,3 +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. + package io.flutter.plugins.webviewflutter; import android.os.Build; 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 591bcc71454a..05a6218c8086 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,3 +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 (v1.0.9), do not edit directly. // See also: https://pub.dev/packages/pigeon diff --git a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImplTest.java b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImplTest.java index 1e2fea4681e3..6daeb1be7f63 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImplTest.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/test/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImplTest.java @@ -1,3 +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. + package io.flutter.plugins.webviewflutter; import static org.mockito.ArgumentMatchers.any; 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 99d12233293d..cc20c8492d6f 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,3 +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 (v1.0.9), 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 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 0f416ae55581..45988a0ae441 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 @@ -1,3 +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 (v1.0.9), 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, avoid_relative_lib_imports, unnecessary_parenthesis From 5a9075d2107eddf54752483102949b81fbad39d7 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Fri, 3 Dec 2021 13:26:40 +0100 Subject: [PATCH 19/25] Updated changelog and pubspec --- .../webview_flutter/webview_flutter_android/CHANGELOG.md | 5 ++++- .../webview_flutter/webview_flutter_android/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 90bc03f6dfe3..308ec62b1b49 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.5.0 + +* Implemented new cookie manager for setting cookies and providing initial cookies. + ## 2.4.0 * Adds support for Android's `WebView.loadData` and `WebView.loadDataWithBaseUrl` methods and implements the `loadFile` and `loadHtmlString` methods from the platform interface. @@ -7,7 +11,6 @@ * Adds explanation on how to generate the pigeon communication layer and mockito mock objects. * Updates compileSdkVersion to 31. -* Implemented new cookie manager for setting cookies and providing initial cookies. ## 2.3.0 diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index e3994a0d98dc..5d9e7bd71f67 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/plugins/tree/master/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.4.0 +version: 2.5.0 environment: sdk: ">=2.14.0 <3.0.0" From 3d5c13f19a443f75c633942668a9774d13081b27 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Fri, 3 Dec 2021 13:38:22 +0100 Subject: [PATCH 20/25] Revert automatic gradle updates --- .../webview_flutter_android/example/android/build.gradle | 2 +- .../example/android/gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/example/android/build.gradle b/packages/webview_flutter/webview_flutter_android/example/android/build.gradle index d21451f63b46..e101ac08df55 100644 --- a/packages/webview_flutter/webview_flutter_android/example/android/build.gradle +++ b/packages/webview_flutter/webview_flutter_android/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.0.3' + classpath 'com.android.tools.build:gradle:3.3.0' } } diff --git a/packages/webview_flutter/webview_flutter_android/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/webview_flutter/webview_flutter_android/example/android/gradle/wrapper/gradle-wrapper.properties index b8793d3c0d69..2819f022f1fd 100644 --- a/packages/webview_flutter/webview_flutter_android/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/webview_flutter/webview_flutter_android/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip From 5d0408f166d2c8ae09e32e2f72c7cc31d5910f2f Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 7 Dec 2021 11:26:14 +0100 Subject: [PATCH 21/25] Implemented PR feedback --- .../webview_flutter_android/CHANGELOG.md | 2 +- .../CookieManagerHostApiImpl.java | 8 +++++--- .../webviewflutter/WebViewFlutterPlugin.java | 5 ++--- .../example/lib/main.dart | 17 +++++++++++++++++ .../lib/src/android_webview.dart | 2 ++ .../lib/webview_android.dart | 9 +++++++-- .../test/android_webview.pigeon.dart | 2 +- 7 files changed, 35 insertions(+), 10 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 308ec62b1b49..7f041d41634f 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,6 +1,6 @@ ## 2.5.0 -* Implemented new cookie manager for setting cookies and providing initial cookies. +* Implements new cookie manager for setting cookies and providing initial cookies. ## 2.4.0 diff --git a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java index 9fd970e61866..3e38ce94b3a5 100644 --- a/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java +++ b/packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/CookieManagerHostApiImpl.java @@ -11,11 +11,13 @@ class CookieManagerHostApiImpl implements GeneratedAndroidWebView.CookieManagerH @Override public void clearCookies(GeneratedAndroidWebView.Result result) { CookieManager cookieManager = CookieManager.getInstance(); - final boolean hasCookies = cookieManager.hasCookies(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - cookieManager.removeAllCookies(value -> result.success(hasCookies)); + cookieManager.removeAllCookies(result::success); } else { - cookieManager.removeAllCookie(); + final boolean hasCookies = cookieManager.hasCookies(); + if (hasCookies) { + cookieManager.removeAllCookie(); + } result.success(hasCookies); } } 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 288c64a69963..4af6b19e338e 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 @@ -13,6 +13,7 @@ import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.platform.PlatformViewRegistry; +import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.CookieManagerHostApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi; import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi; @@ -30,7 +31,6 @@ public class WebViewFlutterPlugin implements FlutterPlugin, ActivityAware { private FlutterPluginBinding pluginBinding; private WebViewHostApiImpl webViewHostApi; - private CookieManagerHostApiImpl cookieManagerHostApi; private JavaScriptChannelHostApiImpl javaScriptChannelHostApi; /** @@ -84,7 +84,6 @@ private void setUp( new JavaScriptChannelHostApiImpl.JavaScriptChannelCreator(), new JavaScriptChannelFlutterApiImpl(binaryMessenger, instanceManager), new Handler(context.getMainLooper())); - cookieManagerHostApi = new CookieManagerHostApiImpl(); WebViewHostApi.setup(binaryMessenger, webViewHostApi); JavaScriptChannelHostApi.setup(binaryMessenger, javaScriptChannelHostApi); @@ -110,7 +109,7 @@ private void setUp( binaryMessenger, new WebSettingsHostApiImpl( instanceManager, new WebSettingsHostApiImpl.WebSettingsCreator())); - GeneratedAndroidWebView.CookieManagerHostApi.setup(binaryMessenger, cookieManagerHostApi); + CookieManagerHostApi.setup(binaryMessenger, new CookieManagerHostApiImpl()); } @Override 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 17459d6f7b1b..d7a75f7cb532 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart @@ -158,6 +158,7 @@ enum _MenuOptions { navigationDelegate, loadLocalFile, loadHtmlString, + setCookie, } class _SampleMenu extends StatelessWidget { @@ -201,6 +202,9 @@ class _SampleMenu extends StatelessWidget { case _MenuOptions.loadHtmlString: _onLoadHtmlStringExample(controller.data!, context); break; + case _MenuOptions.setCookie: + _onSetCookie(controller.data!, context); + break; } }, itemBuilder: (BuildContext context) => >[ @@ -241,6 +245,10 @@ class _SampleMenu extends StatelessWidget { value: _MenuOptions.loadLocalFile, child: Text('Load local file'), ), + const PopupMenuItem<_MenuOptions>( + value: _MenuOptions.setCookie, + child: Text('Set Cookie'), + ), ], ); }, @@ -311,6 +319,15 @@ class _SampleMenu extends StatelessWidget { )); } + Future _onSetCookie( + WebViewController controller, BuildContext context) async { + await WebViewCookieManager.instance.setCookie( + const WebViewCookie( + name: 'foo', value: 'bar', domain: 'httpbin.org', path: '/anything'), + ); + await controller.loadUrl('https://httpbin.org/anything'); + } + Future _onNavigationDelegateExample( WebViewController controller, BuildContext context) async { final String contentBase64 = 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 1ae8bccb2e96..5d061df6ac1f 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 @@ -398,6 +398,8 @@ class CookieManager { Future setCookie(String url, String value) => api.setCookie(url, value); /// Removes all cookies. + /// + /// The returned future resolves to true if any cookies were removed. Future clearCookies() => api.clearCookies(); } diff --git a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart index 9027b0280d19..1f0eb7bd7ded 100644 --- a/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart +++ b/packages/webview_flutter/webview_flutter_android/lib/webview_android.dart @@ -65,6 +65,11 @@ class AndroidWebView implements WebViewPlatform { } @override - Future clearCookies() => - WebViewCookieManagerPlatform.instance!.clearCookies(); + Future clearCookies() { + if (WebViewCookieManagerPlatform.instance == null) { + throw Exception( + 'Could not clear cookies as no implementation for WebViewCookieManagerPlatform has been registered.'); + } + return WebViewCookieManagerPlatform.instance!.clearCookies(); + } } 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 45988a0ae441..cf5dcedad63f 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 @@ -4,7 +4,7 @@ // Autogenerated from Pigeon (v1.0.9), 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, avoid_relative_lib_imports, unnecessary_parenthesis +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import // @dart = 2.12 import 'dart:async'; import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; From b95d8cca10253a6843a99c85803432acb6b156bd Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 7 Dec 2021 12:00:04 +0100 Subject: [PATCH 22/25] Fix mocks --- .../test/android_webview_test.mocks.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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 a9ec635bb6ba..c71bb633facc 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,9 +1,13 @@ +// 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. + // Mocks generated by Mockito 5.0.16 from annotations // in webview_flutter_android/test/android_webview_test.dart. // Do not manually edit this file. import 'dart:async' as _i4; -import 'dart:ui' as _i5; +import 'dart:ui' as _i6; import 'package:mockito/mockito.dart' as _i1; import 'package:webview_flutter_android/src/android_webview.dart' as _i2; @@ -367,7 +371,7 @@ class MockTestWebViewHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestAssetManagerHostApi extends _i1.Mock - implements _i3.TestAssetManagerHostApi { + implements _i5.TestAssetManagerHostApi { MockTestAssetManagerHostApi() { _i1.throwOnMissingStub(this); } @@ -534,7 +538,7 @@ class MockWebView extends _i1.Mock implements _i2.WebView { returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i4.Future setBackgroundColor(_i5.Color? color) => + _i4.Future setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]), returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); From 6d7927470160291d88c4d2c45bffd5aedb20ae43 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 7 Dec 2021 18:35:57 +0100 Subject: [PATCH 23/25] Merge branch 'master' into webview_flutter/set_cookies_android --- .../webview_flutter/CHANGELOG.md | 4 + .../webview_flutter/example/lib/main.dart | 38 +++++++++ .../webview_flutter/lib/src/webview.dart | 8 ++ .../webview_flutter/pubspec.yaml | 8 +- .../test/webview_flutter_test.dart | 28 ++++++ .../webview_flutter_android/CHANGELOG.md | 6 +- .../GeneratedAndroidWebView.java | 35 ++++++++ .../webviewflutter/WebViewHostApiImpl.java | 6 ++ .../plugins/webviewflutter/WebViewTest.java | 6 ++ .../example/lib/main.dart | 19 +++++ .../example/lib/web_view.dart | 5 ++ .../lib/src/android_webview.dart | 8 ++ .../lib/src/android_webview.pigeon.dart | 27 ++++++ .../lib/src/android_webview_api_impls.dart | 11 +++ .../lib/webview_android_widget.dart | 23 +++++ .../pigeons/android_webview.dart | 6 ++ .../webview_flutter_android/pubspec.yaml | 2 +- .../test/android_webview.pigeon.dart | 26 ++++++ .../test/android_webview_test.mocks.dart | 14 ++- .../test/webview_android_widget_test.dart | 76 +++++++++++++++++ .../webview_android_widget_test.mocks.dart | 26 ++++-- script/tool/CHANGELOG.md | 5 ++ script/tool/README.md | 9 +- .../tool/lib/src/common/plugin_command.dart | 67 +++++++++++---- .../tool/test/common/plugin_command_test.dart | 85 +++++++++++++++++-- 25 files changed, 505 insertions(+), 43 deletions(-) diff --git a/packages/webview_flutter/webview_flutter/CHANGELOG.md b/packages/webview_flutter/webview_flutter/CHANGELOG.md index 7b7e112b39fd..1f8a33db4cb4 100644 --- a/packages/webview_flutter/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.5.0 + +* Adds an option to set the background color of the webview. + ## 2.4.0 * Adds support for the `loadFile` and `loadHtmlString` methods. diff --git a/packages/webview_flutter/webview_flutter/example/lib/main.dart b/packages/webview_flutter/webview_flutter/example/lib/main.dart index 5c05e8f7de7d..c870ae9d829d 100644 --- a/packages/webview_flutter/webview_flutter/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter/example/lib/main.dart @@ -48,6 +48,27 @@ const String kLocalExamplePage = ''' '''; +const String kTransparentBackgroundPage = ''' + + + + Transparent background test + + + +
+

Transparent background test

+
+
+ + +'''; + class WebViewExample extends StatefulWidget { @override _WebViewExampleState createState() => _WebViewExampleState(); @@ -68,6 +89,7 @@ class _WebViewExampleState extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: Colors.green, appBar: AppBar( title: const Text('Flutter WebView example'), // This drop down menu demonstrates that Flutter widgets can be shown over the web view. @@ -106,6 +128,7 @@ class _WebViewExampleState extends State { print('Page finished loading: $url'); }, gestureNavigationEnabled: true, + backgroundColor: const Color(0x00000000), ); }), floatingActionButton: favoriteButton(), @@ -155,6 +178,7 @@ enum MenuOptions { navigationDelegate, loadLocalFile, loadHtmlString, + transparentBackground, } class SampleMenu extends StatelessWidget { @@ -170,6 +194,7 @@ class SampleMenu extends StatelessWidget { builder: (BuildContext context, AsyncSnapshot controller) { return PopupMenuButton( + key: const ValueKey('ShowPopupMenu'), onSelected: (MenuOptions value) { switch (value) { case MenuOptions.showUserAgent: @@ -199,6 +224,9 @@ class SampleMenu extends StatelessWidget { case MenuOptions.loadHtmlString: _onLoadHtmlStringExample(controller.data!, context); break; + case MenuOptions.transparentBackground: + _onTransparentBackground(controller.data!, context); + break; } }, itemBuilder: (BuildContext context) => >[ @@ -239,6 +267,11 @@ class SampleMenu extends StatelessWidget { value: MenuOptions.loadLocalFile, child: Text('Load local file'), ), + const PopupMenuItem( + key: ValueKey('ShowTransparentBackgroundExample'), + value: MenuOptions.transparentBackground, + child: Text('Transparent background example'), + ), ], ); }, @@ -327,6 +360,11 @@ class SampleMenu extends StatelessWidget { await controller.loadHtmlString(kLocalExamplePage); } + Future _onTransparentBackground( + WebViewController controller, BuildContext context) async { + await controller.loadHtmlString(kTransparentBackgroundPage); + } + Widget _getCookieList(String cookies) { if (cookies == null || cookies == '""') { return Container(); diff --git a/packages/webview_flutter/webview_flutter/lib/src/webview.dart b/packages/webview_flutter/webview_flutter/lib/src/webview.dart index eb6ee4e09dc2..b2cc69045e5f 100644 --- a/packages/webview_flutter/webview_flutter/lib/src/webview.dart +++ b/packages/webview_flutter/webview_flutter/lib/src/webview.dart @@ -94,6 +94,7 @@ class WebView extends StatefulWidget { this.initialMediaPlaybackPolicy = AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, this.allowsInlineMediaPlayback = false, + this.backgroundColor, }) : assert(javascriptMode != null), assert(initialMediaPlaybackPolicy != null), assert(allowsInlineMediaPlayback != null), @@ -286,6 +287,12 @@ class WebView extends StatefulWidget { /// The default policy is [AutoMediaPlaybackPolicy.require_user_action_for_all_media_types]. final AutoMediaPlaybackPolicy initialMediaPlaybackPolicy; + /// The background color of the [WebView]. + /// + /// When `null` the platform's webview default background color is used. By + /// default [backgroundColor] is `null`. + final Color? backgroundColor; + @override State createState() => _WebViewState(); } @@ -357,6 +364,7 @@ CreationParams _creationParamsfromWidget(WebView widget) { javascriptChannelNames: _extractChannelNames(widget.javascriptChannels), userAgent: widget.userAgent, autoMediaPlaybackPolicy: widget.initialMediaPlaybackPolicy, + backgroundColor: widget.backgroundColor, ); } diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml index 82f790a74478..6c00f65d8022 100644 --- a/packages/webview_flutter/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 2.4.0 +version: 2.5.0 environment: sdk: ">=2.14.0 <3.0.0" @@ -19,9 +19,9 @@ flutter: dependencies: flutter: sdk: flutter - webview_flutter_android: ^2.4.0 - webview_flutter_platform_interface: ^1.5.2 - webview_flutter_wkwebview: ^2.4.0 + webview_flutter_android: ^2.5.0 + webview_flutter_platform_interface: ^1.7.0 + webview_flutter_wkwebview: ^2.5.0 dev_dependencies: build_runner: ^2.1.5 diff --git a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart index b05530272651..da860f0118d4 100644 --- a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart @@ -1020,6 +1020,34 @@ void main() { }); }); + group('Background color', () { + testWidgets('Defaults to null', (WidgetTester tester) async { + await tester.pumpWidget(const WebView()); + + final CreationParams params = captureBuildArgs( + mockWebViewPlatform, + creationParams: true, + ).single as CreationParams; + + expect(params.backgroundColor, null); + }); + + testWidgets('Can be transparent', (WidgetTester tester) async { + const Color transparentColor = Color(0x00000000); + + await tester.pumpWidget(const WebView( + backgroundColor: transparentColor, + )); + + final CreationParams params = captureBuildArgs( + mockWebViewPlatform, + creationParams: true, + ).single as CreationParams; + + expect(params.backgroundColor, transparentColor); + }); + }); + group('Custom platform implementation', () { setUp(() { WebView.platform = MyWebViewPlatform(); diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 2dc9e61cf6bc..7bd33879cd7d 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,7 +1,11 @@ -## 2.7.0 +## 2.8.0 * Implements new cookie manager for setting cookies and providing initial cookies. +## 2.7.0 + +* Adds support for the `loadRequest` method from the platform interface. + ## 2.6.0 * Adds implementation of the `loadFlutterAsset` method from the platform interface. 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 cc68194ffa33..8ef0b8d11f96 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 @@ -274,6 +274,8 @@ void loadDataWithBaseUrl( void loadUrl(Long instanceId, String url, Map headers); + void postUrl(Long instanceId, String url, byte[] data); + String getUrl(Long instanceId); Boolean canGoBack(Long instanceId); @@ -498,6 +500,39 @@ static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.postUrl", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + Map wrapped = new HashMap<>(); + try { + ArrayList args = (ArrayList) message; + Number instanceIdArg = (Number) args.get(0); + if (instanceIdArg == null) { + throw new NullPointerException("instanceIdArg unexpectedly null."); + } + String urlArg = (String) args.get(1); + if (urlArg == null) { + throw new NullPointerException("urlArg unexpectedly null."); + } + byte[] dataArg = (byte[]) args.get(2); + if (dataArg == null) { + throw new NullPointerException("dataArg unexpectedly null."); + } + api.postUrl(instanceIdArg.longValue(), urlArg, dataArg); + wrapped.put("result", null); + } catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( 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 78b06aac90b1..0f3161355dcb 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 @@ -382,6 +382,12 @@ public void loadUrl(Long instanceId, String url, Map headers) { webView.loadUrl(url, headers); } + @Override + public void postUrl(Long instanceId, String url, byte[] data) { + final WebView webView = (WebView) instanceManager.getInstance(instanceId); + webView.postUrl(url, data); + } + @Override public String getUrl(Long instanceId) { final WebView webView = (WebView) instanceManager.getInstance(instanceId); 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 dc58b9b100ff..2312b764342f 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 @@ -208,6 +208,12 @@ public void loadUrl() { verify(mockWebView).loadUrl("https://www.google.com", new HashMap<>()); } + @Test + public void postUrl() { + testHostApiImpl.postUrl(0L, "https://www.google.com", new byte[] {0x01, 0x02}); + verify(mockWebView).postUrl("https://www.google.com", new byte[] {0x01, 0x02}); + } + @Test public void getUrl() { when(mockWebView.getUrl()).thenReturn("https://www.google.com"); 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 675dc8eb05fb..0d0cd59af796 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart @@ -7,6 +7,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_driver/driver_extension.dart'; @@ -189,6 +190,7 @@ enum _MenuOptions { loadLocalFile, loadHtmlString, transparentBackground, + doPostRequest, setCookie, } @@ -240,6 +242,9 @@ class _SampleMenu extends StatelessWidget { case _MenuOptions.transparentBackground: _onTransparentBackground(controller.data!, context); break; + case _MenuOptions.doPostRequest: + _onDoPostRequest(controller.data!, context); + break; case _MenuOptions.setCookie: _onSetCookie(controller.data!, context); break; @@ -292,6 +297,10 @@ class _SampleMenu extends StatelessWidget { 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'), @@ -399,6 +408,16 @@ class _SampleMenu extends StatelessWidget { await controller.loadHtmlString(kExamplePage); } + Future _onDoPostRequest( + WebViewController controller, BuildContext context) async { + final WebViewRequest request = WebViewRequest( + uri: Uri.parse('https://httpbin.org/post'), + method: WebViewRequestMethod.post, + body: Uint8List.fromList('Test Body'.codeUnits), + ); + await controller.loadRequest(request); + } + Widget _getCookieList(String cookies) { if (cookies == null || cookies == '""') { return Container(); diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart index 68931bf61ae5..91ea66376904 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart @@ -425,6 +425,11 @@ class WebViewController { return _webViewPlatformController.loadUrl(url, headers); } + /// Loads a page by making the specified request. + Future loadRequest(WebViewRequest request) async { + return _webViewPlatformController.loadRequest(request); + } + /// Accessor to the current URL that the WebView is displaying. /// /// If [WebView.initialUrl] was never specified, returns `null`. 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 f56b56b1d9af..dfa05cd92ee6 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 @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/foundation.dart'; @@ -169,6 +170,13 @@ class WebView { return api.loadUrlFromInstance(this, url, headers); } + /// Loads the URL with postData using "POST" method into this WebView. + /// + /// If url is not a network URL, it will be loaded with [loadUrl] instead, ignoring the postData param. + Future postUrl(String url, Uint8List data) { + return api.postUrlFromInstance(this, url, data); + } + /// Gets the URL for the current page. /// /// This is not always the same as the URL passed to 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 7f95e8d544e9..810a71732e7b 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 @@ -286,6 +286,33 @@ class WebViewHostApi { } } + Future postUrl( + int arg_instanceId, String arg_url, Uint8List arg_data) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.postUrl', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_instanceId, arg_url, arg_data]) + as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } + Future getUrl(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.WebViewHostApi.getUrl', codec, 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 51efdaadebdc..1db5ed449c56 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 @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:typed_data'; + import 'package:flutter/services.dart'; import 'android_webview.dart'; @@ -152,6 +154,15 @@ class WebViewHostApiImpl extends WebViewHostApi { return loadUrl(instanceManager.getInstanceId(instance)!, url, headers); } + /// Helper method to convert instances ids to objects. + Future postUrlFromInstance( + WebView instance, + String url, + Uint8List data, + ) { + return postUrl(instanceManager.getInstanceId(instance)!, url, data); + } + /// Helper method to convert instances ids to objects. Future getUrlFromInstance(WebView instance) { return getUrl(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 6b62f4540b11..1dec9c105741 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 @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:typed_data'; import 'package:flutter/widgets.dart'; import 'package:webview_flutter_android/webview_android_cookie_manager.dart'; @@ -211,6 +212,28 @@ class WebViewAndroidPlatformController extends WebViewPlatformController { return webView.loadUrl(url, headers ?? {}); } + /// When making a POST request, headers are ignored. As a workaround, make + /// the request manually and load the response data using [loadHTMLString]. + @override + Future loadRequest( + WebViewRequest request, + ) async { + if (!request.uri.hasScheme) { + throw ArgumentError('WebViewRequest#uri is required to have a scheme.'); + } + switch (request.method) { + case WebViewRequestMethod.get: + return webView.loadUrl(request.uri.toString(), request.headers); + case WebViewRequestMethod.post: + return webView.postUrl( + request.uri.toString(), request.body ?? Uint8List(0)); + default: + throw UnimplementedError( + 'This version of webview_android_widget currently has no implementation for HTTP method ${request.method.serialize()} in loadRequest.', + ); + } + } + @override Future currentUrl() => webView.getUrl(); 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 cb38f3885bcc..36862f7cbacc 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -54,6 +54,12 @@ abstract class WebViewHostApi { Map headers, ); + void postUrl( + int instanceId, + String url, + Uint8List data, + ); + String getUrl(int instanceId); bool canGoBack(int instanceId); diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 08bcbb50602e..34bea570ae43 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/plugins/tree/master/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.7.0 +version: 2.8.0 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 90c1474f6c67..1e47c79d32b7 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 @@ -27,6 +27,7 @@ abstract class TestWebViewHostApi { void loadDataWithBaseUrl(int instanceId, String baseUrl, String data, String mimeType, String encoding, String historyUrl); void loadUrl(int instanceId, String url, Map headers); + void postUrl(int instanceId, String url, Uint8List data); String getUrl(int instanceId); bool canGoBack(int instanceId); bool canGoForward(int instanceId); @@ -180,6 +181,31 @@ abstract class TestWebViewHostApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.WebViewHostApi.postUrl', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMockMessageHandler(null); + } else { + channel.setMockMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null.'); + final List args = (message as List?)!; + final int? arg_instanceId = (args[0] as int?); + assert(arg_instanceId != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null int.'); + final String? arg_url = (args[1] as String?); + assert(arg_url != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null String.'); + final Uint8List? arg_data = (args[2] as Uint8List?); + assert(arg_data != null, + 'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null Uint8List.'); + api.postUrl(arg_instanceId!, arg_url!, arg_data!); + return {}; + }); + } + } { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.WebViewHostApi.getUrl', codec, 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 c71bb633facc..d25d2338886b 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 @@ -7,7 +7,8 @@ // Do not manually edit this file. import 'dart:async' as _i4; -import 'dart:ui' as _i6; +import 'dart:typed_data' as _i6; +import 'dart:ui' as _i7; import 'package:mockito/mockito.dart' as _i1; import 'package:webview_flutter_android/src/android_webview.dart' as _i2; @@ -268,6 +269,10 @@ class MockTestWebViewHostApi extends _i1.Mock Invocation.method(#loadUrl, [instanceId, url, headers]), returnValueForMissingStub: null); @override + void postUrl(int? instanceId, String? url, _i6.Uint8List? data) => + super.noSuchMethod(Invocation.method(#postUrl, [instanceId, url, data]), + returnValueForMissingStub: null); + @override String getUrl(int? instanceId) => (super.noSuchMethod(Invocation.method(#getUrl, [instanceId]), returnValue: '') as String); @@ -451,6 +456,11 @@ class MockWebView extends _i1.Mock implements _i2.WebView { returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @override + _i4.Future postUrl(String? url, _i6.Uint8List? data) => + (super.noSuchMethod(Invocation.method(#postUrl, [url, data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i4.Future); + @override _i4.Future getUrl() => (super.noSuchMethod(Invocation.method(#getUrl, []), returnValue: Future.value()) as _i4.Future); @@ -538,7 +548,7 @@ class MockWebView extends _i1.Mock implements _i2.WebView { returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i4.Future setBackgroundColor(_i6.Color? color) => + _i4.Future setBackgroundColor(_i7.Color? color) => (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]), returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); 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 f3867b313d7d..c203ef04a2ce 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 @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:typed_data'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -407,6 +408,81 @@ void main() { )); }); + group('loadRequest', () { + testWidgets('Throws ArgumentError for empty scheme', + (WidgetTester tester) async { + await buildWidget(tester); + + expect( + () async => await testController.loadRequest( + WebViewRequest( + uri: Uri.parse('www.google.com'), + method: WebViewRequestMethod.get, + ), + ), + throwsA(const TypeMatcher())); + }); + + testWidgets('GET without headers', (WidgetTester tester) async { + await buildWidget(tester); + + await testController.loadRequest(WebViewRequest( + uri: Uri.parse('https://www.google.com'), + method: WebViewRequestMethod.get, + )); + + verify(mockWebView.loadUrl( + 'https://www.google.com', + {}, + )); + }); + + testWidgets('GET with headers', (WidgetTester tester) async { + await buildWidget(tester); + + await testController.loadRequest(WebViewRequest( + uri: Uri.parse('https://www.google.com'), + method: WebViewRequestMethod.get, + headers: {'a': 'header'}, + )); + + verify(mockWebView.loadUrl( + 'https://www.google.com', + {'a': 'header'}, + )); + }); + + testWidgets('POST without body', (WidgetTester tester) async { + await buildWidget(tester); + + await testController.loadRequest(WebViewRequest( + uri: Uri.parse('https://www.google.com'), + method: WebViewRequestMethod.post, + )); + + verify(mockWebView.postUrl( + 'https://www.google.com', + Uint8List(0), + )); + }); + + testWidgets('POST with body', (WidgetTester tester) async { + await buildWidget(tester); + + final Uint8List body = Uint8List.fromList('Test Body'.codeUnits); + + await testController.loadRequest(WebViewRequest( + uri: Uri.parse('https://www.google.com'), + method: WebViewRequestMethod.post, + body: body)); + + verify(mockWebView.postUrl( + 'https://www.google.com', + body, + )); + }); + }); + testWidgets('currentUrl', (WidgetTester tester) async { await buildWidget(tester); 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 f3b06ea0a0bb..ece17ad61cb8 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 @@ -1,13 +1,18 @@ +// 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. + // Mocks generated by Mockito 5.0.16 from annotations // in webview_flutter_android/test/webview_android_widget_test.dart. // Do not manually edit this file. import 'dart:async' as _i4; -import 'dart:ui' as _i5; +import 'dart:typed_data' as _i5; +import 'dart:ui' as _i6; 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 _i6; +import 'package:webview_flutter_android/webview_android_widget.dart' as _i7; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart' as _i3; @@ -165,6 +170,11 @@ class MockWebView extends _i1.Mock implements _i2.WebView { returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @override + _i4.Future postUrl(String? url, _i5.Uint8List? data) => + (super.noSuchMethod(Invocation.method(#postUrl, [url, data]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i4.Future); + @override _i4.Future getUrl() => (super.noSuchMethod(Invocation.method(#getUrl, []), returnValue: Future.value()) as _i4.Future); @@ -252,7 +262,7 @@ class MockWebView extends _i1.Mock implements _i2.WebView { returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i4.Future setBackgroundColor(_i5.Color? color) => + _i4.Future setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]), returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @@ -269,7 +279,7 @@ class MockWebView extends _i1.Mock implements _i2.WebView { /// /// See the documentation for Mockito's code generation for more information. class MockWebViewAndroidDownloadListener extends _i1.Mock - implements _i6.WebViewAndroidDownloadListener { + implements _i7.WebViewAndroidDownloadListener { MockWebViewAndroidDownloadListener() { _i1.throwOnMissingStub(this); } @@ -295,7 +305,7 @@ class MockWebViewAndroidDownloadListener extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockWebViewAndroidJavaScriptChannel extends _i1.Mock - implements _i6.WebViewAndroidJavaScriptChannel { + implements _i7.WebViewAndroidJavaScriptChannel { MockWebViewAndroidJavaScriptChannel() { _i1.throwOnMissingStub(this); } @@ -321,7 +331,7 @@ class MockWebViewAndroidJavaScriptChannel extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockWebViewAndroidWebChromeClient extends _i1.Mock - implements _i6.WebViewAndroidWebChromeClient { + implements _i7.WebViewAndroidWebChromeClient { MockWebViewAndroidWebChromeClient() { _i1.throwOnMissingStub(this); } @@ -338,7 +348,7 @@ class MockWebViewAndroidWebChromeClient extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockWebViewAndroidWebViewClient extends _i1.Mock - implements _i6.WebViewAndroidWebViewClient { + implements _i7.WebViewAndroidWebViewClient { MockWebViewAndroidWebViewClient() { _i1.throwOnMissingStub(this); } @@ -470,7 +480,7 @@ class MockWebViewPlatformCallbacksHandler extends _i1.Mock /// A class which mocks [WebViewProxy]. /// /// See the documentation for Mockito's code generation for more information. -class MockWebViewProxy extends _i1.Mock implements _i6.WebViewProxy { +class MockWebViewProxy extends _i1.Mock implements _i7.WebViewProxy { MockWebViewProxy() { _i1.throwOnMissingStub(this); } diff --git a/script/tool/CHANGELOG.md b/script/tool/CHANGELOG.md index dec218e2ba24..72539c24c5fc 100644 --- a/script/tool/CHANGELOG.md +++ b/script/tool/CHANGELOG.md @@ -5,6 +5,11 @@ dependencies to path-based dependencies. - Adds a (hidden) `--run-on-dirty-packages` flag for use with `make-deps-path-based` in CI. +- `--packages` now allows using a federated plugin's package as a target without + fully specifying it (if it is not the same as the plugin's name). E.g., + `--packages=path_provide_ios` now works. +- `--run-on-changed-packages` now includes only the changed packages in a + federated plugin, not all packages in that plugin. - Fix `federation-safety-check` handling of plugin deletion, and of top-level files in unfederated plugins whose names match federated plugin heuristics (e.g., `packages/foo/foo_android.iml`). diff --git a/script/tool/README.md b/script/tool/README.md index 1a87f098757b..613cb5456e0a 100644 --- a/script/tool/README.md +++ b/script/tool/README.md @@ -51,8 +51,13 @@ following shows a number of common commands being run for a specific plugin. All examples assume running from source; see above for running the published version instead. -Note that the `plugins` argument, despite the name, applies to any package. -(It will likely be renamed `packages` in the future.) +Most commands take a `--packages` argument to control which package(s) the +command is targetting. An package name can be any of: +- The name of a package (e.g., `path_provider_android`). +- The name of a federated plugin (e.g., `path_provider`), in which case all + packages that make up that plugin will be targetted. +- A combination federated_plugin_name/package_name (e.g., + `path_provider/path_provider` for the app-facing package). ### Format Code diff --git a/script/tool/lib/src/common/plugin_command.dart b/script/tool/lib/src/common/plugin_command.dart index 7166c754e129..184663568224 100644 --- a/script/tool/lib/src/common/plugin_command.dart +++ b/script/tool/lib/src/common/plugin_command.dart @@ -339,7 +339,7 @@ abstract class PluginCommand extends Command { final List changedFiles = await gitVersionFinder.getChangedFiles(); if (!_changesRequireFullTest(changedFiles)) { - packages = _getChangedPackages(changedFiles); + packages = _getChangedPackageNames(changedFiles); } } else if (getBoolArg(_runOnDirtyPackagesArg)) { final GitVersionFinder gitVersionFinder = @@ -348,7 +348,7 @@ abstract class PluginCommand extends Command { // _changesRequireFullTest is deliberately not used here, as this flag is // intended for use in CI to re-test packages changed by // 'make-deps-path-based'. - packages = _getChangedPackages( + packages = _getChangedPackageNames( await gitVersionFinder.getChangedFiles(includeUncommitted: true)); // For the same reason, empty is not treated as "all packages" as it is // for other flags. @@ -379,21 +379,23 @@ abstract class PluginCommand extends Command { await for (final FileSystemEntity subdir in entity.list(followLinks: false)) { if (_isDartPackage(subdir)) { - // If --plugin=my_plugin is passed, then match all federated - // plugins under 'my_plugin'. Also match if the exact plugin is - // passed. - final String relativePath = - path.relative(subdir.path, from: dir.path); - final String packageName = path.basename(subdir.path); - final String basenamePath = path.basename(entity.path); + // There are three ways for a federated plugin to match: + // - package name (path_provider_android) + // - fully specified name (path_provider/path_provider_android) + // - group name (path_provider), which matches all packages in + // the group + final Set possibleMatches = { + path.basename(subdir.path), // package name + path.basename(entity.path), // group name + path.relative(subdir.path, from: dir.path), // fully specified + }; if (packages.isEmpty || - packages.contains(relativePath) || - packages.contains(basenamePath)) { + packages.intersection(possibleMatches).isNotEmpty) { yield PackageEnumerationEntry( RepositoryPackage(subdir as Directory), - excluded: excludedPluginNames.contains(basenamePath) || - excludedPluginNames.contains(packageName) || - excludedPluginNames.contains(relativePath)); + excluded: excludedPluginNames + .intersection(possibleMatches) + .isNotEmpty); } } } @@ -454,17 +456,48 @@ abstract class PluginCommand extends Command { return gitVersionFinder; } - // Returns packages that have been changed given a list of changed files. + // Returns the names of packages that have been changed given a list of + // changed files. + // + // The names will either be the actual package names, or potentially + // group/name specifiers (for example, path_provider/path_provider) for + // packages in federated plugins. // // The paths must use POSIX separators (e.g., as provided by git output). - Set _getChangedPackages(List changedFiles) { + Set _getChangedPackageNames(List changedFiles) { final Set packages = {}; + + // A helper function that returns true if candidatePackageName looks like an + // implementation package of a plugin called pluginName. Used to determine + // if .../packages/parentName/candidatePackageName/... + // looks like a path in a federated plugin package (candidatePackageName) + // rather than a top-level package (parentName). + bool isFederatedPackage(String candidatePackageName, String parentName) { + return candidatePackageName == parentName || + candidatePackageName.startsWith('${parentName}_'); + } + for (final String path in changedFiles) { final List pathComponents = p.posix.split(path); final int packagesIndex = pathComponents.indexWhere((String element) => element == 'packages'); if (packagesIndex != -1) { - packages.add(pathComponents[packagesIndex + 1]); + // Find the name of the directory directly under packages. This is + // either the name of the package, or a plugin group directory for + // a federated plugin. + final String topLevelName = pathComponents[packagesIndex + 1]; + String packageName = topLevelName; + if (packagesIndex + 2 < pathComponents.length && + isFederatedPackage( + pathComponents[packagesIndex + 2], topLevelName)) { + // This looks like a federated package; use the full specifier if + // the name would be ambiguous (i.e., for the app-facing package). + packageName = pathComponents[packagesIndex + 2]; + if (packageName == topLevelName) { + packageName = '$topLevelName/$packageName'; + } + } + packages.add(packageName); } } if (packages.isEmpty) { diff --git a/script/tool/test/common/plugin_command_test.dart b/script/tool/test/common/plugin_command_test.dart index 222df544f344..28a03c61d59f 100644 --- a/script/tool/test/common/plugin_command_test.dart +++ b/script/tool/test/common/plugin_command_test.dart @@ -180,6 +180,79 @@ void main() { expect(command.plugins, unorderedEquals([])); }); + test( + 'explicitly specifying the plugin (group) name of a federated plugin ' + 'should include all plugins in the group', () async { + processRunner.mockProcessesForExecutable['git-diff'] = [ + MockProcess(stdout: ''' +packages/plugin1/plugin1/plugin1.dart +'''), + ]; + final Directory pluginGroup = packagesDir.childDirectory('plugin1'); + final Directory appFacingPackage = + createFakePlugin('plugin1', pluginGroup); + final Directory platformInterfacePackage = + createFakePlugin('plugin1_platform_interface', pluginGroup); + final Directory implementationPackage = + createFakePlugin('plugin1_web', pluginGroup); + + await runCapturingPrint( + runner, ['sample', '--base-sha=main', '--packages=plugin1']); + + expect( + command.plugins, + unorderedEquals([ + appFacingPackage.path, + platformInterfacePackage.path, + implementationPackage.path + ])); + }); + + test( + 'specifying the app-facing package of a federated plugin using its ' + 'fully qualified name should include only that package', () async { + processRunner.mockProcessesForExecutable['git-diff'] = [ + MockProcess(stdout: ''' +packages/plugin1/plugin1/plugin1.dart +'''), + ]; + final Directory pluginGroup = packagesDir.childDirectory('plugin1'); + final Directory appFacingPackage = + createFakePlugin('plugin1', pluginGroup); + createFakePlugin('plugin1_platform_interface', pluginGroup); + createFakePlugin('plugin1_web', pluginGroup); + + await runCapturingPrint(runner, + ['sample', '--base-sha=main', '--packages=plugin1/plugin1']); + + expect(command.plugins, unorderedEquals([appFacingPackage.path])); + }); + + test( + 'specifying a package of a federated plugin by its name should ' + 'include only that package', () async { + processRunner.mockProcessesForExecutable['git-diff'] = [ + MockProcess(stdout: ''' +packages/plugin1/plugin1/plugin1.dart +'''), + ]; + final Directory pluginGroup = packagesDir.childDirectory('plugin1'); + + createFakePlugin('plugin1', pluginGroup); + final Directory platformInterfacePackage = + createFakePlugin('plugin1_platform_interface', pluginGroup); + createFakePlugin('plugin1_web', pluginGroup); + + await runCapturingPrint(runner, [ + 'sample', + '--base-sha=main', + '--packages=plugin1_platform_interface' + ]); + + expect(command.plugins, + unorderedEquals([platformInterfacePackage.path])); + }); + group('conflicting package selection', () { test('does not allow --packages with --run-on-changed-packages', () async { @@ -442,7 +515,7 @@ packages/plugin1/plugin1_web/plugin1_web.dart }); test( - 'changing one plugin in a federated group should include all plugins in the group', + 'changing one plugin in a federated group should only include that plugin', () async { processRunner.mockProcessesForExecutable['git-diff'] = [ MockProcess(stdout: ''' @@ -451,17 +524,13 @@ packages/plugin1/plugin1/plugin1.dart ]; final Directory plugin1 = createFakePlugin('plugin1', packagesDir.childDirectory('plugin1')); - final Directory plugin2 = createFakePlugin('plugin1_platform_interface', + createFakePlugin('plugin1_platform_interface', packagesDir.childDirectory('plugin1')); - final Directory plugin3 = createFakePlugin( - 'plugin1_web', packagesDir.childDirectory('plugin1')); + createFakePlugin('plugin1_web', packagesDir.childDirectory('plugin1')); await runCapturingPrint(runner, ['sample', '--base-sha=main', '--run-on-changed-packages']); - expect( - command.plugins, - unorderedEquals( - [plugin1.path, plugin2.path, plugin3.path])); + expect(command.plugins, unorderedEquals([plugin1.path])); }); test('--exclude flag works with --run-on-changed-packages', () async { From f201bc1a515d9f90852e3e7e566efd027149da80 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 7 Dec 2021 18:35:57 +0100 Subject: [PATCH 24/25] Revert "Merge branch 'master' into webview_flutter/set_cookies_android" This reverts commit 6d7927470160291d88c4d2c45bffd5aedb20ae43. --- .../webview_flutter/CHANGELOG.md | 4 - .../webview_flutter/example/lib/main.dart | 38 --------- .../webview_flutter/lib/src/webview.dart | 8 -- .../webview_flutter/pubspec.yaml | 8 +- .../test/webview_flutter_test.dart | 28 ------ .../webview_flutter_android/CHANGELOG.md | 6 +- .../GeneratedAndroidWebView.java | 35 -------- .../webviewflutter/WebViewHostApiImpl.java | 6 -- .../plugins/webviewflutter/WebViewTest.java | 6 -- .../example/lib/main.dart | 19 ----- .../example/lib/web_view.dart | 5 -- .../lib/src/android_webview.dart | 8 -- .../lib/src/android_webview.pigeon.dart | 27 ------ .../lib/src/android_webview_api_impls.dart | 11 --- .../lib/webview_android_widget.dart | 23 ----- .../pigeons/android_webview.dart | 6 -- .../webview_flutter_android/pubspec.yaml | 2 +- .../test/android_webview.pigeon.dart | 26 ------ .../test/android_webview_test.mocks.dart | 14 +-- .../test/webview_android_widget_test.dart | 76 ----------------- .../webview_android_widget_test.mocks.dart | 26 ++---- script/tool/CHANGELOG.md | 5 -- script/tool/README.md | 9 +- .../tool/lib/src/common/plugin_command.dart | 67 ++++----------- .../tool/test/common/plugin_command_test.dart | 85 ++----------------- 25 files changed, 43 insertions(+), 505 deletions(-) diff --git a/packages/webview_flutter/webview_flutter/CHANGELOG.md b/packages/webview_flutter/webview_flutter/CHANGELOG.md index 1f8a33db4cb4..7b7e112b39fd 100644 --- a/packages/webview_flutter/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter/CHANGELOG.md @@ -1,7 +1,3 @@ -## 2.5.0 - -* Adds an option to set the background color of the webview. - ## 2.4.0 * Adds support for the `loadFile` and `loadHtmlString` methods. diff --git a/packages/webview_flutter/webview_flutter/example/lib/main.dart b/packages/webview_flutter/webview_flutter/example/lib/main.dart index c870ae9d829d..5c05e8f7de7d 100644 --- a/packages/webview_flutter/webview_flutter/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter/example/lib/main.dart @@ -48,27 +48,6 @@ const String kLocalExamplePage = ''' '''; -const String kTransparentBackgroundPage = ''' - - - - Transparent background test - - - -
-

Transparent background test

-
-
- - -'''; - class WebViewExample extends StatefulWidget { @override _WebViewExampleState createState() => _WebViewExampleState(); @@ -89,7 +68,6 @@ class _WebViewExampleState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.green, appBar: AppBar( title: const Text('Flutter WebView example'), // This drop down menu demonstrates that Flutter widgets can be shown over the web view. @@ -128,7 +106,6 @@ class _WebViewExampleState extends State { print('Page finished loading: $url'); }, gestureNavigationEnabled: true, - backgroundColor: const Color(0x00000000), ); }), floatingActionButton: favoriteButton(), @@ -178,7 +155,6 @@ enum MenuOptions { navigationDelegate, loadLocalFile, loadHtmlString, - transparentBackground, } class SampleMenu extends StatelessWidget { @@ -194,7 +170,6 @@ class SampleMenu extends StatelessWidget { builder: (BuildContext context, AsyncSnapshot controller) { return PopupMenuButton( - key: const ValueKey('ShowPopupMenu'), onSelected: (MenuOptions value) { switch (value) { case MenuOptions.showUserAgent: @@ -224,9 +199,6 @@ class SampleMenu extends StatelessWidget { case MenuOptions.loadHtmlString: _onLoadHtmlStringExample(controller.data!, context); break; - case MenuOptions.transparentBackground: - _onTransparentBackground(controller.data!, context); - break; } }, itemBuilder: (BuildContext context) => >[ @@ -267,11 +239,6 @@ class SampleMenu extends StatelessWidget { value: MenuOptions.loadLocalFile, child: Text('Load local file'), ), - const PopupMenuItem( - key: ValueKey('ShowTransparentBackgroundExample'), - value: MenuOptions.transparentBackground, - child: Text('Transparent background example'), - ), ], ); }, @@ -360,11 +327,6 @@ class SampleMenu extends StatelessWidget { await controller.loadHtmlString(kLocalExamplePage); } - Future _onTransparentBackground( - WebViewController controller, BuildContext context) async { - await controller.loadHtmlString(kTransparentBackgroundPage); - } - Widget _getCookieList(String cookies) { if (cookies == null || cookies == '""') { return Container(); diff --git a/packages/webview_flutter/webview_flutter/lib/src/webview.dart b/packages/webview_flutter/webview_flutter/lib/src/webview.dart index b2cc69045e5f..eb6ee4e09dc2 100644 --- a/packages/webview_flutter/webview_flutter/lib/src/webview.dart +++ b/packages/webview_flutter/webview_flutter/lib/src/webview.dart @@ -94,7 +94,6 @@ class WebView extends StatefulWidget { this.initialMediaPlaybackPolicy = AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, this.allowsInlineMediaPlayback = false, - this.backgroundColor, }) : assert(javascriptMode != null), assert(initialMediaPlaybackPolicy != null), assert(allowsInlineMediaPlayback != null), @@ -287,12 +286,6 @@ class WebView extends StatefulWidget { /// The default policy is [AutoMediaPlaybackPolicy.require_user_action_for_all_media_types]. final AutoMediaPlaybackPolicy initialMediaPlaybackPolicy; - /// The background color of the [WebView]. - /// - /// When `null` the platform's webview default background color is used. By - /// default [backgroundColor] is `null`. - final Color? backgroundColor; - @override State createState() => _WebViewState(); } @@ -364,7 +357,6 @@ CreationParams _creationParamsfromWidget(WebView widget) { javascriptChannelNames: _extractChannelNames(widget.javascriptChannels), userAgent: widget.userAgent, autoMediaPlaybackPolicy: widget.initialMediaPlaybackPolicy, - backgroundColor: widget.backgroundColor, ); } diff --git a/packages/webview_flutter/webview_flutter/pubspec.yaml b/packages/webview_flutter/webview_flutter/pubspec.yaml index 6c00f65d8022..82f790a74478 100644 --- a/packages/webview_flutter/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. repository: https://github.com/flutter/plugins/tree/master/packages/webview_flutter/webview_flutter issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22 -version: 2.5.0 +version: 2.4.0 environment: sdk: ">=2.14.0 <3.0.0" @@ -19,9 +19,9 @@ flutter: dependencies: flutter: sdk: flutter - webview_flutter_android: ^2.5.0 - webview_flutter_platform_interface: ^1.7.0 - webview_flutter_wkwebview: ^2.5.0 + webview_flutter_android: ^2.4.0 + webview_flutter_platform_interface: ^1.5.2 + webview_flutter_wkwebview: ^2.4.0 dev_dependencies: build_runner: ^2.1.5 diff --git a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart index da860f0118d4..b05530272651 100644 --- a/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter/test/webview_flutter_test.dart @@ -1020,34 +1020,6 @@ void main() { }); }); - group('Background color', () { - testWidgets('Defaults to null', (WidgetTester tester) async { - await tester.pumpWidget(const WebView()); - - final CreationParams params = captureBuildArgs( - mockWebViewPlatform, - creationParams: true, - ).single as CreationParams; - - expect(params.backgroundColor, null); - }); - - testWidgets('Can be transparent', (WidgetTester tester) async { - const Color transparentColor = Color(0x00000000); - - await tester.pumpWidget(const WebView( - backgroundColor: transparentColor, - )); - - final CreationParams params = captureBuildArgs( - mockWebViewPlatform, - creationParams: true, - ).single as CreationParams; - - expect(params.backgroundColor, transparentColor); - }); - }); - group('Custom platform implementation', () { setUp(() { WebView.platform = MyWebViewPlatform(); diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 7bd33879cd7d..2dc9e61cf6bc 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,10 +1,6 @@ -## 2.8.0 - -* Implements new cookie manager for setting cookies and providing initial cookies. - ## 2.7.0 -* Adds support for the `loadRequest` method from the platform interface. +* Implements new cookie manager for setting cookies and providing initial cookies. ## 2.6.0 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 8ef0b8d11f96..cc68194ffa33 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 @@ -274,8 +274,6 @@ void loadDataWithBaseUrl( void loadUrl(Long instanceId, String url, Map headers); - void postUrl(Long instanceId, String url, byte[] data); - String getUrl(Long instanceId); Boolean canGoBack(Long instanceId); @@ -500,39 +498,6 @@ static void setup(BinaryMessenger binaryMessenger, WebViewHostApi api) { channel.setMessageHandler(null); } } - { - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, "dev.flutter.pigeon.WebViewHostApi.postUrl", getCodec()); - if (api != null) { - channel.setMessageHandler( - (message, reply) -> { - Map wrapped = new HashMap<>(); - try { - ArrayList args = (ArrayList) message; - Number instanceIdArg = (Number) args.get(0); - if (instanceIdArg == null) { - throw new NullPointerException("instanceIdArg unexpectedly null."); - } - String urlArg = (String) args.get(1); - if (urlArg == null) { - throw new NullPointerException("urlArg unexpectedly null."); - } - byte[] dataArg = (byte[]) args.get(2); - if (dataArg == null) { - throw new NullPointerException("dataArg unexpectedly null."); - } - api.postUrl(instanceIdArg.longValue(), urlArg, dataArg); - wrapped.put("result", null); - } catch (Error | RuntimeException exception) { - wrapped.put("error", wrapError(exception)); - } - reply.reply(wrapped); - }); - } else { - channel.setMessageHandler(null); - } - } { BasicMessageChannel channel = new BasicMessageChannel<>( 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 0f3161355dcb..78b06aac90b1 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 @@ -382,12 +382,6 @@ public void loadUrl(Long instanceId, String url, Map headers) { webView.loadUrl(url, headers); } - @Override - public void postUrl(Long instanceId, String url, byte[] data) { - final WebView webView = (WebView) instanceManager.getInstance(instanceId); - webView.postUrl(url, data); - } - @Override public String getUrl(Long instanceId) { final WebView webView = (WebView) instanceManager.getInstance(instanceId); 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 2312b764342f..dc58b9b100ff 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 @@ -208,12 +208,6 @@ public void loadUrl() { verify(mockWebView).loadUrl("https://www.google.com", new HashMap<>()); } - @Test - public void postUrl() { - testHostApiImpl.postUrl(0L, "https://www.google.com", new byte[] {0x01, 0x02}); - verify(mockWebView).postUrl("https://www.google.com", new byte[] {0x01, 0x02}); - } - @Test public void getUrl() { when(mockWebView.getUrl()).thenReturn("https://www.google.com"); 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 0d0cd59af796..675dc8eb05fb 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/main.dart @@ -7,7 +7,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_driver/driver_extension.dart'; @@ -190,7 +189,6 @@ enum _MenuOptions { loadLocalFile, loadHtmlString, transparentBackground, - doPostRequest, setCookie, } @@ -242,9 +240,6 @@ class _SampleMenu extends StatelessWidget { case _MenuOptions.transparentBackground: _onTransparentBackground(controller.data!, context); break; - case _MenuOptions.doPostRequest: - _onDoPostRequest(controller.data!, context); - break; case _MenuOptions.setCookie: _onSetCookie(controller.data!, context); break; @@ -297,10 +292,6 @@ class _SampleMenu extends StatelessWidget { 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'), @@ -408,16 +399,6 @@ class _SampleMenu extends StatelessWidget { await controller.loadHtmlString(kExamplePage); } - Future _onDoPostRequest( - WebViewController controller, BuildContext context) async { - final WebViewRequest request = WebViewRequest( - uri: Uri.parse('https://httpbin.org/post'), - method: WebViewRequestMethod.post, - body: Uint8List.fromList('Test Body'.codeUnits), - ); - await controller.loadRequest(request); - } - Widget _getCookieList(String cookies) { if (cookies == null || cookies == '""') { return Container(); diff --git a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart index 91ea66376904..68931bf61ae5 100644 --- a/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart +++ b/packages/webview_flutter/webview_flutter_android/example/lib/web_view.dart @@ -425,11 +425,6 @@ class WebViewController { return _webViewPlatformController.loadUrl(url, headers); } - /// Loads a page by making the specified request. - Future loadRequest(WebViewRequest request) async { - return _webViewPlatformController.loadRequest(request); - } - /// Accessor to the current URL that the WebView is displaying. /// /// If [WebView.initialUrl] was never specified, returns `null`. 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 dfa05cd92ee6..f56b56b1d9af 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 @@ -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:typed_data'; import 'dart:ui'; import 'package:flutter/foundation.dart'; @@ -170,13 +169,6 @@ class WebView { return api.loadUrlFromInstance(this, url, headers); } - /// Loads the URL with postData using "POST" method into this WebView. - /// - /// If url is not a network URL, it will be loaded with [loadUrl] instead, ignoring the postData param. - Future postUrl(String url, Uint8List data) { - return api.postUrlFromInstance(this, url, data); - } - /// Gets the URL for the current page. /// /// This is not always the same as the URL passed to 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 810a71732e7b..7f95e8d544e9 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 @@ -286,33 +286,6 @@ class WebViewHostApi { } } - Future postUrl( - int arg_instanceId, String arg_url, Uint8List arg_data) async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.postUrl', codec, - binaryMessenger: _binaryMessenger); - final Map? replyMap = - await channel.send([arg_instanceId, arg_url, arg_data]) - as Map?; - if (replyMap == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - details: null, - ); - } else if (replyMap['error'] != null) { - final Map error = - (replyMap['error'] as Map?)!; - throw PlatformException( - code: (error['code'] as String?)!, - message: error['message'] as String?, - details: error['details'], - ); - } else { - return; - } - } - Future getUrl(int arg_instanceId) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.WebViewHostApi.getUrl', codec, 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 1db5ed449c56..51efdaadebdc 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 @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:typed_data'; - import 'package:flutter/services.dart'; import 'android_webview.dart'; @@ -154,15 +152,6 @@ class WebViewHostApiImpl extends WebViewHostApi { return loadUrl(instanceManager.getInstanceId(instance)!, url, headers); } - /// Helper method to convert instances ids to objects. - Future postUrlFromInstance( - WebView instance, - String url, - Uint8List data, - ) { - return postUrl(instanceManager.getInstanceId(instance)!, url, data); - } - /// Helper method to convert instances ids to objects. Future getUrlFromInstance(WebView instance) { return getUrl(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 1dec9c105741..6b62f4540b11 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 @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:typed_data'; import 'package:flutter/widgets.dart'; import 'package:webview_flutter_android/webview_android_cookie_manager.dart'; @@ -212,28 +211,6 @@ class WebViewAndroidPlatformController extends WebViewPlatformController { return webView.loadUrl(url, headers ?? {}); } - /// When making a POST request, headers are ignored. As a workaround, make - /// the request manually and load the response data using [loadHTMLString]. - @override - Future loadRequest( - WebViewRequest request, - ) async { - if (!request.uri.hasScheme) { - throw ArgumentError('WebViewRequest#uri is required to have a scheme.'); - } - switch (request.method) { - case WebViewRequestMethod.get: - return webView.loadUrl(request.uri.toString(), request.headers); - case WebViewRequestMethod.post: - return webView.postUrl( - request.uri.toString(), request.body ?? Uint8List(0)); - default: - throw UnimplementedError( - 'This version of webview_android_widget currently has no implementation for HTTP method ${request.method.serialize()} in loadRequest.', - ); - } - } - @override Future currentUrl() => webView.getUrl(); 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 36862f7cbacc..cb38f3885bcc 100644 --- a/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart +++ b/packages/webview_flutter/webview_flutter_android/pigeons/android_webview.dart @@ -54,12 +54,6 @@ abstract class WebViewHostApi { Map headers, ); - void postUrl( - int instanceId, - String url, - Uint8List data, - ); - String getUrl(int instanceId); bool canGoBack(int instanceId); diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 34bea570ae43..08bcbb50602e 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/plugins/tree/master/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.0 +version: 2.7.0 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 1e47c79d32b7..90c1474f6c67 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 @@ -27,7 +27,6 @@ abstract class TestWebViewHostApi { void loadDataWithBaseUrl(int instanceId, String baseUrl, String data, String mimeType, String encoding, String historyUrl); void loadUrl(int instanceId, String url, Map headers); - void postUrl(int instanceId, String url, Uint8List data); String getUrl(int instanceId); bool canGoBack(int instanceId); bool canGoForward(int instanceId); @@ -181,31 +180,6 @@ abstract class TestWebViewHostApi { }); } } - { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.WebViewHostApi.postUrl', codec, - binaryMessenger: binaryMessenger); - if (api == null) { - channel.setMockMessageHandler(null); - } else { - channel.setMockMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null.'); - final List args = (message as List?)!; - final int? arg_instanceId = (args[0] as int?); - assert(arg_instanceId != null, - 'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null int.'); - final String? arg_url = (args[1] as String?); - assert(arg_url != null, - 'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null String.'); - final Uint8List? arg_data = (args[2] as Uint8List?); - assert(arg_data != null, - 'Argument for dev.flutter.pigeon.WebViewHostApi.postUrl was null, expected non-null Uint8List.'); - api.postUrl(arg_instanceId!, arg_url!, arg_data!); - return {}; - }); - } - } { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.WebViewHostApi.getUrl', codec, 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 d25d2338886b..c71bb633facc 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 @@ -7,8 +7,7 @@ // Do not manually edit this file. import 'dart:async' as _i4; -import 'dart:typed_data' as _i6; -import 'dart:ui' as _i7; +import 'dart:ui' as _i6; import 'package:mockito/mockito.dart' as _i1; import 'package:webview_flutter_android/src/android_webview.dart' as _i2; @@ -269,10 +268,6 @@ class MockTestWebViewHostApi extends _i1.Mock Invocation.method(#loadUrl, [instanceId, url, headers]), returnValueForMissingStub: null); @override - void postUrl(int? instanceId, String? url, _i6.Uint8List? data) => - super.noSuchMethod(Invocation.method(#postUrl, [instanceId, url, data]), - returnValueForMissingStub: null); - @override String getUrl(int? instanceId) => (super.noSuchMethod(Invocation.method(#getUrl, [instanceId]), returnValue: '') as String); @@ -456,11 +451,6 @@ class MockWebView extends _i1.Mock implements _i2.WebView { returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i4.Future postUrl(String? url, _i6.Uint8List? data) => - (super.noSuchMethod(Invocation.method(#postUrl, [url, data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i4.Future); - @override _i4.Future getUrl() => (super.noSuchMethod(Invocation.method(#getUrl, []), returnValue: Future.value()) as _i4.Future); @@ -548,7 +538,7 @@ class MockWebView extends _i1.Mock implements _i2.WebView { returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i4.Future setBackgroundColor(_i7.Color? color) => + _i4.Future setBackgroundColor(_i6.Color? color) => (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]), returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); 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 c203ef04a2ce..f3867b313d7d 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 @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:typed_data'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -408,81 +407,6 @@ void main() { )); }); - group('loadRequest', () { - testWidgets('Throws ArgumentError for empty scheme', - (WidgetTester tester) async { - await buildWidget(tester); - - expect( - () async => await testController.loadRequest( - WebViewRequest( - uri: Uri.parse('www.google.com'), - method: WebViewRequestMethod.get, - ), - ), - throwsA(const TypeMatcher())); - }); - - testWidgets('GET without headers', (WidgetTester tester) async { - await buildWidget(tester); - - await testController.loadRequest(WebViewRequest( - uri: Uri.parse('https://www.google.com'), - method: WebViewRequestMethod.get, - )); - - verify(mockWebView.loadUrl( - 'https://www.google.com', - {}, - )); - }); - - testWidgets('GET with headers', (WidgetTester tester) async { - await buildWidget(tester); - - await testController.loadRequest(WebViewRequest( - uri: Uri.parse('https://www.google.com'), - method: WebViewRequestMethod.get, - headers: {'a': 'header'}, - )); - - verify(mockWebView.loadUrl( - 'https://www.google.com', - {'a': 'header'}, - )); - }); - - testWidgets('POST without body', (WidgetTester tester) async { - await buildWidget(tester); - - await testController.loadRequest(WebViewRequest( - uri: Uri.parse('https://www.google.com'), - method: WebViewRequestMethod.post, - )); - - verify(mockWebView.postUrl( - 'https://www.google.com', - Uint8List(0), - )); - }); - - testWidgets('POST with body', (WidgetTester tester) async { - await buildWidget(tester); - - final Uint8List body = Uint8List.fromList('Test Body'.codeUnits); - - await testController.loadRequest(WebViewRequest( - uri: Uri.parse('https://www.google.com'), - method: WebViewRequestMethod.post, - body: body)); - - verify(mockWebView.postUrl( - 'https://www.google.com', - body, - )); - }); - }); - testWidgets('currentUrl', (WidgetTester tester) async { await buildWidget(tester); 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 ece17ad61cb8..f3b06ea0a0bb 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 @@ -1,18 +1,13 @@ -// 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. - // Mocks generated by Mockito 5.0.16 from annotations // in webview_flutter_android/test/webview_android_widget_test.dart. // Do not manually edit this file. import 'dart:async' as _i4; -import 'dart:typed_data' as _i5; -import 'dart:ui' as _i6; +import 'dart:ui' as _i5; 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_android/webview_android_widget.dart' as _i6; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart' as _i3; @@ -170,11 +165,6 @@ class MockWebView extends _i1.Mock implements _i2.WebView { returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i4.Future postUrl(String? url, _i5.Uint8List? data) => - (super.noSuchMethod(Invocation.method(#postUrl, [url, data]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i4.Future); - @override _i4.Future getUrl() => (super.noSuchMethod(Invocation.method(#getUrl, []), returnValue: Future.value()) as _i4.Future); @@ -262,7 +252,7 @@ class MockWebView extends _i1.Mock implements _i2.WebView { returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i4.Future setBackgroundColor(_i6.Color? color) => + _i4.Future setBackgroundColor(_i5.Color? color) => (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]), returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i4.Future); @@ -279,7 +269,7 @@ class MockWebView extends _i1.Mock implements _i2.WebView { /// /// See the documentation for Mockito's code generation for more information. class MockWebViewAndroidDownloadListener extends _i1.Mock - implements _i7.WebViewAndroidDownloadListener { + implements _i6.WebViewAndroidDownloadListener { MockWebViewAndroidDownloadListener() { _i1.throwOnMissingStub(this); } @@ -305,7 +295,7 @@ class MockWebViewAndroidDownloadListener extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockWebViewAndroidJavaScriptChannel extends _i1.Mock - implements _i7.WebViewAndroidJavaScriptChannel { + implements _i6.WebViewAndroidJavaScriptChannel { MockWebViewAndroidJavaScriptChannel() { _i1.throwOnMissingStub(this); } @@ -331,7 +321,7 @@ class MockWebViewAndroidJavaScriptChannel extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockWebViewAndroidWebChromeClient extends _i1.Mock - implements _i7.WebViewAndroidWebChromeClient { + implements _i6.WebViewAndroidWebChromeClient { MockWebViewAndroidWebChromeClient() { _i1.throwOnMissingStub(this); } @@ -348,7 +338,7 @@ class MockWebViewAndroidWebChromeClient extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockWebViewAndroidWebViewClient extends _i1.Mock - implements _i7.WebViewAndroidWebViewClient { + implements _i6.WebViewAndroidWebViewClient { MockWebViewAndroidWebViewClient() { _i1.throwOnMissingStub(this); } @@ -480,7 +470,7 @@ class MockWebViewPlatformCallbacksHandler extends _i1.Mock /// A class which mocks [WebViewProxy]. /// /// See the documentation for Mockito's code generation for more information. -class MockWebViewProxy extends _i1.Mock implements _i7.WebViewProxy { +class MockWebViewProxy extends _i1.Mock implements _i6.WebViewProxy { MockWebViewProxy() { _i1.throwOnMissingStub(this); } diff --git a/script/tool/CHANGELOG.md b/script/tool/CHANGELOG.md index 72539c24c5fc..dec218e2ba24 100644 --- a/script/tool/CHANGELOG.md +++ b/script/tool/CHANGELOG.md @@ -5,11 +5,6 @@ dependencies to path-based dependencies. - Adds a (hidden) `--run-on-dirty-packages` flag for use with `make-deps-path-based` in CI. -- `--packages` now allows using a federated plugin's package as a target without - fully specifying it (if it is not the same as the plugin's name). E.g., - `--packages=path_provide_ios` now works. -- `--run-on-changed-packages` now includes only the changed packages in a - federated plugin, not all packages in that plugin. - Fix `federation-safety-check` handling of plugin deletion, and of top-level files in unfederated plugins whose names match federated plugin heuristics (e.g., `packages/foo/foo_android.iml`). diff --git a/script/tool/README.md b/script/tool/README.md index 613cb5456e0a..1a87f098757b 100644 --- a/script/tool/README.md +++ b/script/tool/README.md @@ -51,13 +51,8 @@ following shows a number of common commands being run for a specific plugin. All examples assume running from source; see above for running the published version instead. -Most commands take a `--packages` argument to control which package(s) the -command is targetting. An package name can be any of: -- The name of a package (e.g., `path_provider_android`). -- The name of a federated plugin (e.g., `path_provider`), in which case all - packages that make up that plugin will be targetted. -- A combination federated_plugin_name/package_name (e.g., - `path_provider/path_provider` for the app-facing package). +Note that the `plugins` argument, despite the name, applies to any package. +(It will likely be renamed `packages` in the future.) ### Format Code diff --git a/script/tool/lib/src/common/plugin_command.dart b/script/tool/lib/src/common/plugin_command.dart index 184663568224..7166c754e129 100644 --- a/script/tool/lib/src/common/plugin_command.dart +++ b/script/tool/lib/src/common/plugin_command.dart @@ -339,7 +339,7 @@ abstract class PluginCommand extends Command { final List changedFiles = await gitVersionFinder.getChangedFiles(); if (!_changesRequireFullTest(changedFiles)) { - packages = _getChangedPackageNames(changedFiles); + packages = _getChangedPackages(changedFiles); } } else if (getBoolArg(_runOnDirtyPackagesArg)) { final GitVersionFinder gitVersionFinder = @@ -348,7 +348,7 @@ abstract class PluginCommand extends Command { // _changesRequireFullTest is deliberately not used here, as this flag is // intended for use in CI to re-test packages changed by // 'make-deps-path-based'. - packages = _getChangedPackageNames( + packages = _getChangedPackages( await gitVersionFinder.getChangedFiles(includeUncommitted: true)); // For the same reason, empty is not treated as "all packages" as it is // for other flags. @@ -379,23 +379,21 @@ abstract class PluginCommand extends Command { await for (final FileSystemEntity subdir in entity.list(followLinks: false)) { if (_isDartPackage(subdir)) { - // There are three ways for a federated plugin to match: - // - package name (path_provider_android) - // - fully specified name (path_provider/path_provider_android) - // - group name (path_provider), which matches all packages in - // the group - final Set possibleMatches = { - path.basename(subdir.path), // package name - path.basename(entity.path), // group name - path.relative(subdir.path, from: dir.path), // fully specified - }; + // If --plugin=my_plugin is passed, then match all federated + // plugins under 'my_plugin'. Also match if the exact plugin is + // passed. + final String relativePath = + path.relative(subdir.path, from: dir.path); + final String packageName = path.basename(subdir.path); + final String basenamePath = path.basename(entity.path); if (packages.isEmpty || - packages.intersection(possibleMatches).isNotEmpty) { + packages.contains(relativePath) || + packages.contains(basenamePath)) { yield PackageEnumerationEntry( RepositoryPackage(subdir as Directory), - excluded: excludedPluginNames - .intersection(possibleMatches) - .isNotEmpty); + excluded: excludedPluginNames.contains(basenamePath) || + excludedPluginNames.contains(packageName) || + excludedPluginNames.contains(relativePath)); } } } @@ -456,48 +454,17 @@ abstract class PluginCommand extends Command { return gitVersionFinder; } - // Returns the names of packages that have been changed given a list of - // changed files. - // - // The names will either be the actual package names, or potentially - // group/name specifiers (for example, path_provider/path_provider) for - // packages in federated plugins. + // Returns packages that have been changed given a list of changed files. // // The paths must use POSIX separators (e.g., as provided by git output). - Set _getChangedPackageNames(List changedFiles) { + Set _getChangedPackages(List changedFiles) { final Set packages = {}; - - // A helper function that returns true if candidatePackageName looks like an - // implementation package of a plugin called pluginName. Used to determine - // if .../packages/parentName/candidatePackageName/... - // looks like a path in a federated plugin package (candidatePackageName) - // rather than a top-level package (parentName). - bool isFederatedPackage(String candidatePackageName, String parentName) { - return candidatePackageName == parentName || - candidatePackageName.startsWith('${parentName}_'); - } - for (final String path in changedFiles) { final List pathComponents = p.posix.split(path); final int packagesIndex = pathComponents.indexWhere((String element) => element == 'packages'); if (packagesIndex != -1) { - // Find the name of the directory directly under packages. This is - // either the name of the package, or a plugin group directory for - // a federated plugin. - final String topLevelName = pathComponents[packagesIndex + 1]; - String packageName = topLevelName; - if (packagesIndex + 2 < pathComponents.length && - isFederatedPackage( - pathComponents[packagesIndex + 2], topLevelName)) { - // This looks like a federated package; use the full specifier if - // the name would be ambiguous (i.e., for the app-facing package). - packageName = pathComponents[packagesIndex + 2]; - if (packageName == topLevelName) { - packageName = '$topLevelName/$packageName'; - } - } - packages.add(packageName); + packages.add(pathComponents[packagesIndex + 1]); } } if (packages.isEmpty) { diff --git a/script/tool/test/common/plugin_command_test.dart b/script/tool/test/common/plugin_command_test.dart index 28a03c61d59f..222df544f344 100644 --- a/script/tool/test/common/plugin_command_test.dart +++ b/script/tool/test/common/plugin_command_test.dart @@ -180,79 +180,6 @@ void main() { expect(command.plugins, unorderedEquals([])); }); - test( - 'explicitly specifying the plugin (group) name of a federated plugin ' - 'should include all plugins in the group', () async { - processRunner.mockProcessesForExecutable['git-diff'] = [ - MockProcess(stdout: ''' -packages/plugin1/plugin1/plugin1.dart -'''), - ]; - final Directory pluginGroup = packagesDir.childDirectory('plugin1'); - final Directory appFacingPackage = - createFakePlugin('plugin1', pluginGroup); - final Directory platformInterfacePackage = - createFakePlugin('plugin1_platform_interface', pluginGroup); - final Directory implementationPackage = - createFakePlugin('plugin1_web', pluginGroup); - - await runCapturingPrint( - runner, ['sample', '--base-sha=main', '--packages=plugin1']); - - expect( - command.plugins, - unorderedEquals([ - appFacingPackage.path, - platformInterfacePackage.path, - implementationPackage.path - ])); - }); - - test( - 'specifying the app-facing package of a federated plugin using its ' - 'fully qualified name should include only that package', () async { - processRunner.mockProcessesForExecutable['git-diff'] = [ - MockProcess(stdout: ''' -packages/plugin1/plugin1/plugin1.dart -'''), - ]; - final Directory pluginGroup = packagesDir.childDirectory('plugin1'); - final Directory appFacingPackage = - createFakePlugin('plugin1', pluginGroup); - createFakePlugin('plugin1_platform_interface', pluginGroup); - createFakePlugin('plugin1_web', pluginGroup); - - await runCapturingPrint(runner, - ['sample', '--base-sha=main', '--packages=plugin1/plugin1']); - - expect(command.plugins, unorderedEquals([appFacingPackage.path])); - }); - - test( - 'specifying a package of a federated plugin by its name should ' - 'include only that package', () async { - processRunner.mockProcessesForExecutable['git-diff'] = [ - MockProcess(stdout: ''' -packages/plugin1/plugin1/plugin1.dart -'''), - ]; - final Directory pluginGroup = packagesDir.childDirectory('plugin1'); - - createFakePlugin('plugin1', pluginGroup); - final Directory platformInterfacePackage = - createFakePlugin('plugin1_platform_interface', pluginGroup); - createFakePlugin('plugin1_web', pluginGroup); - - await runCapturingPrint(runner, [ - 'sample', - '--base-sha=main', - '--packages=plugin1_platform_interface' - ]); - - expect(command.plugins, - unorderedEquals([platformInterfacePackage.path])); - }); - group('conflicting package selection', () { test('does not allow --packages with --run-on-changed-packages', () async { @@ -515,7 +442,7 @@ packages/plugin1/plugin1_web/plugin1_web.dart }); test( - 'changing one plugin in a federated group should only include that plugin', + 'changing one plugin in a federated group should include all plugins in the group', () async { processRunner.mockProcessesForExecutable['git-diff'] = [ MockProcess(stdout: ''' @@ -524,13 +451,17 @@ packages/plugin1/plugin1/plugin1.dart ]; final Directory plugin1 = createFakePlugin('plugin1', packagesDir.childDirectory('plugin1')); - createFakePlugin('plugin1_platform_interface', + final Directory plugin2 = createFakePlugin('plugin1_platform_interface', packagesDir.childDirectory('plugin1')); - createFakePlugin('plugin1_web', packagesDir.childDirectory('plugin1')); + final Directory plugin3 = createFakePlugin( + 'plugin1_web', packagesDir.childDirectory('plugin1')); await runCapturingPrint(runner, ['sample', '--base-sha=main', '--run-on-changed-packages']); - expect(command.plugins, unorderedEquals([plugin1.path])); + expect( + command.plugins, + unorderedEquals( + [plugin1.path, plugin2.path, plugin3.path])); }); test('--exclude flag works with --run-on-changed-packages', () async { From 3bfbe9ea1656780abea7ed11f3e2ec7119277907 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 7 Dec 2021 18:41:37 +0100 Subject: [PATCH 25/25] Update changelog, pubspec version and mocks. --- .../webview_flutter_android/CHANGELOG.md | 2 +- .../webview_flutter_android/pubspec.yaml | 2 +- .../test/android_webview_test.mocks.dart | 114 ++++++++---------- 3 files changed, 55 insertions(+), 63 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md index 7effcc3cc81a..7bd33879cd7d 100644 --- a/packages/webview_flutter/webview_flutter_android/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_android/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.7.0 +## 2.8.0 * Implements new cookie manager for setting cookies and providing initial cookies. diff --git a/packages/webview_flutter/webview_flutter_android/pubspec.yaml b/packages/webview_flutter/webview_flutter_android/pubspec.yaml index 08bcbb50602e..34bea570ae43 100644 --- a/packages/webview_flutter/webview_flutter_android/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: webview_flutter_android description: A Flutter plugin that provides a WebView widget on Android. repository: https://github.com/flutter/plugins/tree/master/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.7.0 +version: 2.8.0 environment: sdk: ">=2.14.0 <3.0.0" 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 95f90447fb36..d25d2338886b 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 @@ -6,13 +6,9 @@ // in webview_flutter_android/test/android_webview_test.dart. // Do not manually edit this file. -<<<<<<< HEAD import 'dart:async' as _i4; -======= -import 'dart:async' as _i5; -import 'dart:typed_data' as _i4; ->>>>>>> master -import 'dart:ui' as _i6; +import 'dart:typed_data' as _i6; +import 'dart:ui' as _i7; import 'package:mockito/mockito.dart' as _i1; import 'package:webview_flutter_android/src/android_webview.dart' as _i2; @@ -273,7 +269,7 @@ class MockTestWebViewHostApi extends _i1.Mock Invocation.method(#loadUrl, [instanceId, url, headers]), returnValueForMissingStub: null); @override - void postUrl(int? instanceId, String? url, _i4.Uint8List? data) => + void postUrl(int? instanceId, String? url, _i6.Uint8List? data) => super.noSuchMethod(Invocation.method(#postUrl, [instanceId, url, data]), returnValueForMissingStub: null); @override @@ -306,12 +302,12 @@ class MockTestWebViewHostApi extends _i1.Mock Invocation.method(#clearCache, [instanceId, includeDiskFiles]), returnValueForMissingStub: null); @override - _i5.Future evaluateJavascript( + _i4.Future evaluateJavascript( int? instanceId, String? javascriptString) => (super.noSuchMethod( Invocation.method( #evaluateJavascript, [instanceId, javascriptString]), - returnValue: Future.value('')) as _i5.Future); + returnValue: Future.value('')) as _i4.Future); @override String getTitle(int? instanceId) => (super.noSuchMethod(Invocation.method(#getTitle, [instanceId]), @@ -430,15 +426,15 @@ class MockWebView extends _i1.Mock implements _i2.WebView { (super.noSuchMethod(Invocation.getter(#settings), returnValue: _FakeWebSettings_0()) as _i2.WebSettings); @override - _i5.Future loadData( + _i4.Future loadData( {String? data, String? mimeType, String? encoding}) => (super.noSuchMethod( Invocation.method(#loadData, [], {#data: data, #mimeType: mimeType, #encoding: encoding}), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future loadDataWithBaseUrl( + _i4.Future loadDataWithBaseUrl( {String? baseUrl, String? data, String? mimeType, @@ -453,118 +449,114 @@ class MockWebView extends _i1.Mock implements _i2.WebView { #historyUrl: historyUrl }), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future loadUrl(String? url, Map? headers) => + _i4.Future loadUrl(String? url, Map? headers) => (super.noSuchMethod(Invocation.method(#loadUrl, [url, headers]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future postUrl(String? url, _i4.Uint8List? data) => + _i4.Future postUrl(String? url, _i6.Uint8List? data) => (super.noSuchMethod(Invocation.method(#postUrl, [url, data]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future getUrl() => + _i4.Future getUrl() => (super.noSuchMethod(Invocation.method(#getUrl, []), - returnValue: Future.value()) as _i5.Future); + returnValue: Future.value()) as _i4.Future); @override - _i5.Future canGoBack() => + _i4.Future canGoBack() => (super.noSuchMethod(Invocation.method(#canGoBack, []), - returnValue: Future.value(false)) as _i5.Future); + returnValue: Future.value(false)) as _i4.Future); @override - _i5.Future canGoForward() => + _i4.Future canGoForward() => (super.noSuchMethod(Invocation.method(#canGoForward, []), - returnValue: Future.value(false)) as _i5.Future); + returnValue: Future.value(false)) as _i4.Future); @override - _i5.Future goBack() => + _i4.Future goBack() => (super.noSuchMethod(Invocation.method(#goBack, []), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future goForward() => + _i4.Future goForward() => (super.noSuchMethod(Invocation.method(#goForward, []), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future reload() => + _i4.Future reload() => (super.noSuchMethod(Invocation.method(#reload, []), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future clearCache(bool? includeDiskFiles) => + _i4.Future clearCache(bool? includeDiskFiles) => (super.noSuchMethod(Invocation.method(#clearCache, [includeDiskFiles]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future evaluateJavascript(String? javascriptString) => (super + _i4.Future evaluateJavascript(String? javascriptString) => (super .noSuchMethod(Invocation.method(#evaluateJavascript, [javascriptString]), - returnValue: Future.value()) as _i5.Future); + returnValue: Future.value()) as _i4.Future); @override - _i5.Future getTitle() => + _i4.Future getTitle() => (super.noSuchMethod(Invocation.method(#getTitle, []), - returnValue: Future.value()) as _i5.Future); + returnValue: Future.value()) as _i4.Future); @override - _i5.Future scrollTo(int? x, int? y) => + _i4.Future scrollTo(int? x, int? y) => (super.noSuchMethod(Invocation.method(#scrollTo, [x, y]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future scrollBy(int? x, int? y) => + _i4.Future scrollBy(int? x, int? y) => (super.noSuchMethod(Invocation.method(#scrollBy, [x, y]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future getScrollX() => + _i4.Future getScrollX() => (super.noSuchMethod(Invocation.method(#getScrollX, []), - returnValue: Future.value(0)) as _i5.Future); + returnValue: Future.value(0)) as _i4.Future); @override - _i5.Future getScrollY() => + _i4.Future getScrollY() => (super.noSuchMethod(Invocation.method(#getScrollY, []), - returnValue: Future.value(0)) as _i5.Future); + returnValue: Future.value(0)) as _i4.Future); @override - _i5.Future setWebViewClient(_i2.WebViewClient? webViewClient) => + _i4.Future setWebViewClient(_i2.WebViewClient? webViewClient) => (super.noSuchMethod(Invocation.method(#setWebViewClient, [webViewClient]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future addJavaScriptChannel( + _i4.Future addJavaScriptChannel( _i2.JavaScriptChannel? javaScriptChannel) => (super.noSuchMethod( Invocation.method(#addJavaScriptChannel, [javaScriptChannel]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future removeJavaScriptChannel( + _i4.Future removeJavaScriptChannel( _i2.JavaScriptChannel? javaScriptChannel) => (super.noSuchMethod( Invocation.method(#removeJavaScriptChannel, [javaScriptChannel]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future setDownloadListener(_i2.DownloadListener? listener) => + _i4.Future setDownloadListener(_i2.DownloadListener? listener) => (super.noSuchMethod(Invocation.method(#setDownloadListener, [listener]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future setWebChromeClient(_i2.WebChromeClient? client) => + _i4.Future setWebChromeClient(_i2.WebChromeClient? client) => (super.noSuchMethod(Invocation.method(#setWebChromeClient, [client]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override -<<<<<<< HEAD - _i4.Future setBackgroundColor(_i6.Color? color) => -======= - _i5.Future setBackgroundColor(_i6.Color? color) => ->>>>>>> master + _i4.Future setBackgroundColor(_i7.Color? color) => (super.noSuchMethod(Invocation.method(#setBackgroundColor, [color]), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override - _i5.Future release() => + _i4.Future release() => (super.noSuchMethod(Invocation.method(#release, []), returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i5.Future); + returnValueForMissingStub: Future.value()) as _i4.Future); @override String toString() => super.toString(); }