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/18] 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 05778158d44494b21e2779872cf09577f191f05f Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 15:15:24 +0100 Subject: [PATCH 02/18] 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 03/18] 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 04/18] 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 05/18] 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 555ed5cec972ab4965d904de1f4dd6eeb52906a6 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 15:40:18 +0100 Subject: [PATCH 06/18] Added iOS implementations for new CookieManager --- .../webview_flutter_wkwebview/CHANGELOG.md | 5 +- .../analysis_options.yaml | 1 + .../webview_flutter_test.dart | 42 +++--- .../ios/Runner.xcodeproj/project.pbxproj | 73 +++++----- .../ios/RunnerTests/FLTCookieManagerTests.m | 127 ++++++++++++++++++ .../FLTWKNavigationDelegateTests.m | 1 + .../example/ios/RunnerTests/FLTWebViewTests.m | 26 +++- .../example/lib/main.dart | 54 ++++---- .../example/lib/navigation_request.dart | 2 +- .../example/lib/web_view.dart | 50 +++++-- .../example/pubspec.yaml | 4 +- .../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 +++++++++ 22 files changed, 493 insertions(+), 108 deletions(-) create mode 100644 packages/webview_flutter/webview_flutter_wkwebview/analysis_options.yaml 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 e9c59c26c3ce..c01cfc8e51e3 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,8 +1,7 @@ -## NEXT +## 2.5.0 -* Migrates from `analysis_options_legacy.yaml` to `analysis_options.yaml`. * Integration test fixes. -* Updates to webview_flutter_platform_interface version 1.5.2. +* Implemented new cookie manager for setting cookies and providing initial cookies. ## 2.4.0 diff --git a/packages/webview_flutter/webview_flutter_wkwebview/analysis_options.yaml b/packages/webview_flutter/webview_flutter_wkwebview/analysis_options.yaml new file mode 100644 index 000000000000..5aeb4e7c5e21 --- /dev/null +++ b/packages/webview_flutter/webview_flutter_wkwebview/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../../analysis_options_legacy.yaml diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart index 8806495e629c..00c7e998edc8 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart @@ -191,7 +191,7 @@ void main() { await onPageFinished.future; resizeButtonTapped = true; - await tester.tap(find.byKey(const ValueKey('resizeButton'))); + await tester.tap(find.byKey(const ValueKey('resizeButton'))); await tester.pumpAndSettle(); expect(buttonTapResizeCompleter.future, completes); }); @@ -446,10 +446,10 @@ void main() { testWidgets('Video plays inline when allowsInlineMediaPlayback is true', (WidgetTester tester) async { - final Completer controllerCompleter = + Completer controllerCompleter = Completer(); - final Completer pageLoaded = Completer(); - final Completer videoPlaying = Completer(); + Completer pageLoaded = Completer(); + Completer videoPlaying = Completer(); await tester.pumpWidget( Directionality( @@ -480,7 +480,7 @@ void main() { ), ), ); - final WebViewController controller = await controllerCompleter.future; + WebViewController controller = await controllerCompleter.future; await pageLoaded.future; // Pump once to trigger the video play. @@ -489,7 +489,7 @@ void main() { // Makes sure we get the correct event that indicates the video is actually playing. await videoPlaying.future; - final String fullScreen = + String fullScreen = await controller.runJavascriptReturningResult('isFullScreen();'); expect(fullScreen, _webviewBool(false)); }); @@ -497,10 +497,10 @@ void main() { testWidgets( 'Video plays full screen when allowsInlineMediaPlayback is false', (WidgetTester tester) async { - final Completer controllerCompleter = + Completer controllerCompleter = Completer(); - final Completer pageLoaded = Completer(); - final Completer videoPlaying = Completer(); + Completer pageLoaded = Completer(); + Completer videoPlaying = Completer(); await tester.pumpWidget( Directionality( @@ -531,7 +531,7 @@ void main() { ), ), ); - final WebViewController controller = await controllerCompleter.future; + WebViewController controller = await controllerCompleter.future; await pageLoaded.future; // Pump once to trigger the video play. @@ -540,7 +540,7 @@ void main() { // Makes sure we get the correct event that indicates the video is actually playing. await videoPlaying.future; - final String fullScreen = + String fullScreen = await controller.runJavascriptReturningResult('isFullScreen();'); expect(fullScreen, _webviewBool(true)); }); @@ -718,7 +718,7 @@ void main() { }); testWidgets('getTitle', (WidgetTester tester) async { - const String getTitleTest = ''' + final String getTitleTest = ''' Some title @@ -768,7 +768,7 @@ void main() { group('Programmatic Scroll', () { testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - const String scrollTestPage = ''' + final String scrollTestPage = ''' @@ -815,7 +815,7 @@ void main() { final WebViewController controller = await controllerCompleter.future; await pageLoaded.future; - await tester.pumpAndSettle(const Duration(seconds: 3)); + await tester.pumpAndSettle(Duration(seconds: 3)); int scrollPosX = await controller.getScrollX(); int scrollPosY = await controller.getScrollY(); @@ -845,7 +845,7 @@ void main() { }); group('NavigationDelegate', () { - const String blankPage = ''; + final String blankPage = ""; final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + base64Encode(const Utf8Encoder().convert(blankPage)); @@ -941,7 +941,7 @@ void main() { testWidgets( 'onWebResourceError only called for main frame', (WidgetTester tester) async { - const String iframeTest = ''' + final String iframeTest = ''' @@ -1169,13 +1169,11 @@ Future _runJavascriptReturningResult( if (defaultTargetPlatform == TargetPlatform.iOS) { return await controller.runJavascriptReturningResult(js); } - return jsonDecode(await controller.runJavascriptReturningResult(js)) - as String; + return jsonDecode(await controller.runJavascriptReturningResult(js)); } class ResizableWebView extends StatefulWidget { - const ResizableWebView( - {required this.onResize, required this.onPageFinished}); + ResizableWebView({required this.onResize, required this.onPageFinished}); final JavascriptMessageHandler onResize; final VoidCallback onPageFinished; @@ -1230,14 +1228,14 @@ class ResizableWebViewState extends State { ), ), TextButton( - key: const Key('resizeButton'), + key: Key('resizeButton'), onPressed: () { setState(() { webViewWidth += 100.0; webViewHeight += 100.0; }); }, - child: const Text('ResizeButton'), + child: Text('ResizeButton'), ), ], ), 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..b681c4704ddd 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 */, @@ -277,13 +280,16 @@ ORGANIZATIONNAME = "The Flutter Authors"; TargetAttributes = { 68BDCAE823C3F7CB00D9C032 = { + DevelopmentTeam = 7624MWN53C; ProvisioningStyle = Automatic; }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = 7624MWN53C; }; F7151F73266057800028CB91 = { CreatedOnToolsVersion = 12.5; + DevelopmentTeam = 7624MWN53C; ProvisioningStyle = Automatic; TestTargetID = 97C146ED1CF9000F007C117D; }; @@ -338,7 +344,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 +373,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 +409,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 +425,7 @@ files = ( 334734012669319100DCC49E /* FLTWebViewTests.m in Sources */, 334734022669319400DCC49E /* FLTWKNavigationDelegateTests.m in Sources */, + E43693B527512C0F00382F85 /* FLTCookieManagerTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -477,7 +484,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 +498,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/main.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart index df85d42bea8f..068087c5222e 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart @@ -19,7 +19,7 @@ import 'navigation_request.dart'; import 'web_view.dart'; void main() { - runApp(const MaterialApp(home: _WebViewExample())); + runApp(MaterialApp(home: _WebViewExample())); } const String kNavigationExamplePage = ''' @@ -67,6 +67,11 @@ class _WebViewExampleState extends State<_WebViewExample> { final Completer _controller = Completer(); + @override + void initState() { + super.initState(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -80,9 +85,9 @@ class _WebViewExampleState extends State<_WebViewExample> { ), // We're using a Builder here so we have a context that is below the Scaffold // to allow calling Scaffold.of(context) so we can show a snackbar. - body: Builder(builder: (BuildContext context) { + body: Builder(builder: (context) { return WebView( - initialUrl: 'https://flutter.dev', + initialUrl: 'https://httpbin.org/anything', onWebViewCreated: (WebViewController controller) { _controller.complete(controller); }, @@ -125,7 +130,7 @@ class _WebViewExampleState extends State<_WebViewExample> { } Set _createJavascriptChannels(BuildContext context) { - return { + return { JavascriptChannel( name: 'Snackbar', onMessageReceived: (JavascriptMessage message) { @@ -149,7 +154,7 @@ enum _MenuOptions { } class _SampleMenu extends StatelessWidget { - const _SampleMenu(this.controller); + _SampleMenu(this.controller); final Future controller; @@ -242,7 +247,7 @@ class _SampleMenu extends StatelessWidget { ); } - Future _onShowUserAgent( + void _onShowUserAgent( WebViewController controller, BuildContext context) async { // Send a message with the user agent string to the Snackbar JavaScript channel we registered // with the WebView. @@ -250,7 +255,7 @@ class _SampleMenu extends StatelessWidget { 'Snackbar.postMessage("User Agent: " + navigator.userAgent);'); } - Future _onListCookies( + void _onListCookies( WebViewController controller, BuildContext context) async { final String cookies = await controller.runJavascriptReturningResult('document.cookie'); @@ -266,8 +271,7 @@ class _SampleMenu extends StatelessWidget { )); } - Future _onAddToCache( - WebViewController controller, BuildContext context) async { + void _onAddToCache(WebViewController controller, BuildContext context) async { await controller.runJavascript( 'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";'); ScaffoldMessenger.of(context).showSnackBar(const SnackBar( @@ -275,22 +279,20 @@ class _SampleMenu extends StatelessWidget { )); } - Future _onListCache( - WebViewController controller, BuildContext context) async { + void _onListCache(WebViewController controller, BuildContext context) async { await controller.runJavascript('caches.keys()' '.then((cacheKeys) => JSON.stringify({"cacheKeys" : cacheKeys, "localStorage" : localStorage}))' '.then((caches) => Snackbar.postMessage(caches))'); } - Future _onClearCache( - WebViewController controller, BuildContext context) async { + void _onClearCache(WebViewController controller, BuildContext context) async { await controller.clearCache(); ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('Cache cleared.'), + content: Text("Cache cleared."), )); } - Future _onClearCookies( + void _onClearCookies( WebViewController controller, BuildContext context) async { final bool hadCookies = await WebView.platform.clearCookies(); String message = 'There were cookies. Now, they are gone!'; @@ -302,31 +304,31 @@ class _SampleMenu extends StatelessWidget { )); } - Future _onNavigationDelegateExample( + void _onNavigationDelegateExample( WebViewController controller, BuildContext context) async { final String contentBase64 = base64Encode(const Utf8Encoder().convert(kNavigationExamplePage)); await controller.loadUrl('data:text/html;base64,$contentBase64'); } - Future _onLoadLocalFileExample( + void _onLoadLocalFileExample( WebViewController controller, BuildContext context) async { - final String pathToIndex = await _prepareLocalFile(); + String pathToIndex = await _prepareLocalFile(); await controller.loadFile(pathToIndex); } - Future _onLoadHtmlStringExample( + void _onLoadHtmlStringExample( WebViewController controller, BuildContext context) async { await controller.loadHtmlString(kLocalFileExamplePage); } - Future _onDoPostRequest( + void _onDoPostRequest( WebViewController controller, BuildContext context) async { - final WebViewRequest request = WebViewRequest( + WebViewRequest request = WebViewRequest( uri: Uri.parse('https://httpbin.org/post'), method: WebViewRequestMethod.post, - headers: {'foo': 'bar', 'Content-Type': 'text/plain'}, + headers: {'foo': 'bar', 'Content-Type': 'text/plain'}, body: Uint8List.fromList('Test Body'.codeUnits), ); await controller.loadRequest(request); @@ -348,7 +350,7 @@ class _SampleMenu extends StatelessWidget { static Future _prepareLocalFile() async { final String tmpDir = (await getTemporaryDirectory()).path; - final File indexFile = File('$tmpDir/www/index.html'); + File indexFile = File('$tmpDir/www/index.html'); await Directory('$tmpDir/www').create(recursive: true); await indexFile.writeAsString(kLocalFileExamplePage); @@ -385,7 +387,7 @@ class _NavigationControls extends StatelessWidget { } else { // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( - const SnackBar(content: Text('No back history item')), + const SnackBar(content: Text("No back history item")), ); return; } @@ -402,7 +404,7 @@ class _NavigationControls extends StatelessWidget { // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( const SnackBar( - content: Text('No forward history item')), + content: Text("No forward history item")), ); return; } @@ -424,4 +426,4 @@ class _NavigationControls extends StatelessWidget { } /// Callback type for handling messages sent from JavaScript running in a web view. -typedef JavascriptMessageHandler = void Function(JavascriptMessage message); +typedef void JavascriptMessageHandler(JavascriptMessage message); diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart index 2f6d7c9f8cdd..c1ff8dc5a690 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart @@ -14,6 +14,6 @@ class NavigationRequest { @override String toString() { - return 'NavigationRequest(url: $url, isForMainFrame: $isForMainFrame)'; + return '$runtimeType(url: $url, isForMainFrame: $isForMainFrame)'; } } 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 ae540ae23c2d..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'; @@ -15,7 +16,7 @@ import 'navigation_request.dart'; /// Optional callback invoked when a web view is first created. [controller] is /// the [WebViewController] for the created web view. -typedef WebViewCreatedCallback = void Function(WebViewController controller); +typedef void WebViewCreatedCallback(WebViewController controller); /// Decides how to handle a specific navigation request. /// @@ -23,20 +24,20 @@ typedef WebViewCreatedCallback = void Function(WebViewController controller); /// `navigation` should be handled. /// /// See also: [WebView.navigationDelegate]. -typedef NavigationDelegate = FutureOr Function( +typedef FutureOr NavigationDelegate( NavigationRequest navigation); /// Signature for when a [WebView] has started loading a page. -typedef PageStartedCallback = void Function(String url); +typedef void PageStartedCallback(String url); /// Signature for when a [WebView] has finished loading a page. -typedef PageFinishedCallback = void Function(String url); +typedef void PageFinishedCallback(String url); /// Signature for when a [WebView] is loading a page. -typedef PageLoadingCallback = void Function(int progress); +typedef void PageLoadingCallback(int progress); /// Signature for when a [WebView] has failed to load a resource. -typedef WebResourceErrorCallback = void Function(WebResourceError error); +typedef void WebResourceErrorCallback(WebResourceError error); /// A web view widget for showing html content. /// @@ -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; @@ -259,7 +264,7 @@ class _WebViewState extends State { context: context, onWebViewPlatformCreated: (WebViewPlatformController? webViewPlatformController) { - final WebViewController controller = WebViewController._( + WebViewController controller = WebViewController._( widget, webViewPlatformController!, _javascriptChannelRegistry, @@ -278,6 +283,7 @@ class _WebViewState extends State { _javascriptChannelRegistry.channels.keys.toSet(), autoMediaPlaybackPolicy: widget.initialMediaPlaybackPolicy, userAgent: widget.userAgent, + cookies: widget.initialCookies, ), javascriptChannelRegistry: _javascriptChannelRegistry, ); @@ -547,7 +553,7 @@ class WebViewController { bool? hasNavigationDelegate; bool? hasProgressTracking; bool? debuggingEnabled; - WebSetting userAgent = const WebSetting.absent(); + WebSetting userAgent = WebSetting.absent(); if (currentValue.javascriptMode != newValue.javascriptMode) { javascriptMode = newValue.javascriptMode; } @@ -645,10 +651,36 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler { } } - @override void onWebResourceError(WebResourceError error) { if (_webView.onWebResourceError != null) { _webView.onWebResourceError!(error); } } } + +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/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml index 2888cddac552..c8001c8ffde4 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml @@ -21,10 +21,10 @@ dependencies: dev_dependencies: espresso: ^0.1.0+2 - flutter_driver: - sdk: flutter flutter_test: sdk: flutter + flutter_driver: + sdk: flutter integration_test: sdk: flutter pedantic: ^1.10.0 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 a152e2ba2882..f6da86ddb636 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,9 @@ flutter: dependencies: flutter: sdk: flutter - webview_flutter_platform_interface: ^1.5.2 +# TODO (BeMacized): Update dependency when changes have been merged and published. + 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 0d0f2816ecb78d316628432f34c65f30a8b3de8a Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 16:05:11 +0100 Subject: [PATCH 07/18] 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 cbdba1ca40b2ff1ace32ca9795faf6d446d39bbf Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 16:09:02 +0100 Subject: [PATCH 08/18] Partially fix merge error --- .../webview_flutter_wkwebview/analysis_options.yaml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 packages/webview_flutter/webview_flutter_wkwebview/analysis_options.yaml diff --git a/packages/webview_flutter/webview_flutter_wkwebview/analysis_options.yaml b/packages/webview_flutter/webview_flutter_wkwebview/analysis_options.yaml deleted file mode 100644 index 5aeb4e7c5e21..000000000000 --- a/packages/webview_flutter/webview_flutter_wkwebview/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: ../../../analysis_options_legacy.yaml From 490da19421cbe9cbef9df584be205db78a0c9e2b Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 19:51:46 +0100 Subject: [PATCH 09/18] 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 eb66b7a4268e3637137edf7c293b7a84ee52d26d Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 29 Nov 2021 19:53:08 +0100 Subject: [PATCH 10/18] Update to match platform interface changes --- .../example/lib/main.dart | 18 ++++++++++++- .../example/lib/web_view.dart | 27 ++++++------------- .../lib/src/webview_cupertino.dart | 3 ++- ...ger.dart => wkwebview_cookie_manager.dart} | 10 +------ .../lib/webview_flutter_wkwebview.dart | 2 +- ...art => wkwebview_cookie_manager_test.dart} | 9 ++++--- 6 files changed, 34 insertions(+), 35 deletions(-) rename packages/webview_flutter/webview_flutter_wkwebview/lib/src/{webview_ios_cookie_manager.dart => wkwebview_cookie_manager.dart} (76%) rename packages/webview_flutter/webview_flutter_wkwebview/test/src/{webview_ios_cookie_manager_test.dart => wkwebview_cookie_manager_test.dart} (85%) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart index 068087c5222e..46d1954fff8a 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart @@ -87,7 +87,7 @@ class _WebViewExampleState extends State<_WebViewExample> { // to allow calling Scaffold.of(context) so we can show a snackbar. body: Builder(builder: (context) { return WebView( - initialUrl: 'https://httpbin.org/anything', + initialUrl: 'https://flutter.dev/', onWebViewCreated: (WebViewController controller) { _controller.complete(controller); }, @@ -151,6 +151,7 @@ enum _MenuOptions { loadLocalFile, loadHtmlString, doPostRequest, + setCookie, } class _SampleMenu extends StatelessWidget { @@ -197,6 +198,9 @@ class _SampleMenu extends StatelessWidget { case _MenuOptions.doPostRequest: _onDoPostRequest(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.doPostRequest, child: Text('Post Request'), ), + const PopupMenuItem<_MenuOptions>( + value: _MenuOptions.setCookie, + child: Text('Set Cookie'), + ), ], ); }, @@ -334,6 +342,14 @@ class _SampleMenu extends StatelessWidget { await controller.loadRequest(request); } + void _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'); + } + Widget _getCookieList(String cookies) { if (cookies == null || cookies == '""') { return Container(); 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..6299f6b34821 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 @@ -658,29 +658,18 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler { } } +/// 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.isIOS) { - return WebViewIOSCookieManager.instance.clearCookies(); - } else { - return super.clearCookies(); - } - } - - @override - Future setCookie(WebViewCookie cookie) { - if (Platform.isIOS) { - return WebViewIOSCookieManager.instance.setCookie(cookie); + /// Returns an instance of the cookie manager for the current platform. + static WebViewCookieManagerPlatform get instance { + if (WebViewCookieManagerPlatform.instance == null && Platform.isIOS) { + WebViewCookieManagerPlatform.instance = WKWebViewCookieManager(); } else { - return super.setCookie(cookie); + throw AssertionError( + 'This platform is currently unsupported for webview_flutter_wkwebview.'); } + return WebViewCookieManagerPlatform.instance!; } } diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart index 05b79d0a72e4..e4292e28e50e 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart @@ -45,5 +45,6 @@ class CupertinoWebView implements WebViewPlatform { } @override - Future clearCookies() => MethodChannelWebViewPlatform.clearCookies(); + Future clearCookies() => + WebViewCookieManagerPlatform.instance!.clearCookies(); } 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/wkwebview_cookie_manager.dart similarity index 76% rename from packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart rename to packages/webview_flutter/webview_flutter_wkwebview/lib/src/wkwebview_cookie_manager.dart index f6dde177ecf6..d460ce02ab68 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_ios_cookie_manager.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/wkwebview_cookie_manager.dart @@ -5,15 +5,7 @@ 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._(); - +class WKWebViewCookieManager extends WebViewCookieManagerPlatform { @override Future clearCookies() => MethodChannelWebViewPlatform.clearCookies(); 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..f647ab38a41b 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,4 @@ // found in the LICENSE file. export 'src/webview_cupertino.dart'; -export 'src/webview_ios_cookie_manager.dart'; +export 'src/wkwebview_cookie_manager.dart'; 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/wkwebview_cookie_manager_test.dart similarity index 85% rename from packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart rename to packages/webview_flutter/webview_flutter_wkwebview/test/src/wkwebview_cookie_manager_test.dart index 10d13e44873e..a6e5d5243005 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/webview_ios_cookie_manager_test.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/wkwebview_cookie_manager_test.dart @@ -5,7 +5,7 @@ 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'; +import 'package:webview_flutter_wkwebview/src/wkwebview_cookie_manager.dart'; main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -31,7 +31,7 @@ main() { test('clearCookies should call `clearCookies` on the method channel', () async { - await WebViewIOSCookieManager.instance.clearCookies(); + await WKWebViewCookieManager().clearCookies(); expect( log, [ @@ -44,8 +44,9 @@ main() { }); test('setCookie should call `setCookie` on the method channel', () async { - await WebViewIOSCookieManager.instance.setCookie( - WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev')); + await WKWebViewCookieManager().setCookie( + const WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev'), + ); expect( log, [ From 6f9742ad6f127299458552478ac9a280bb992b41 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 30 Nov 2021 14:29:28 +0100 Subject: [PATCH 11/18] 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 12/18] 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 4b2d0b9bdb2cf50f8295027e2583797781deb5d4 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 30 Nov 2021 14:43:14 +0100 Subject: [PATCH 13/18] 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_wkwebview/example/lib/web_view.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/web_view.dart index 6299f6b34821..97f869858304 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 @@ -664,11 +664,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.isIOS) { - WebViewCookieManagerPlatform.instance = WKWebViewCookieManager(); - } else { - throw AssertionError( - 'This platform is currently unsupported for webview_flutter_wkwebview.'); + if (WebViewCookieManagerPlatform.instance == null) { + if (Platform.isIOS) { + WebViewCookieManagerPlatform.instance = WKWebViewCookieManager(); + } else { + throw AssertionError( + 'This platform is currently unsupported for webview_flutter_wkwebview.'); + } } return WebViewCookieManagerPlatform.instance!; } From a1de612aebd6ce9b31f8b9835767bc41d45d9453 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Thu, 2 Dec 2021 15:53:35 +0100 Subject: [PATCH 14/18] Fix analysis errors (excl. pubspec) --- .../webview_flutter_test.dart | 49 ++++++++---------- .../example/lib/main.dart | 50 ++++++++++--------- .../example/lib/navigation_request.dart | 2 +- .../example/lib/web_view.dart | 19 +++---- .../example/pubspec.yaml | 4 +- .../src/wkwebview_cookie_manager_test.dart | 4 +- 6 files changed, 63 insertions(+), 65 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart index 00c7e998edc8..1e4adb9f7de0 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart @@ -191,7 +191,7 @@ void main() { await onPageFinished.future; resizeButtonTapped = true; - await tester.tap(find.byKey(const ValueKey('resizeButton'))); + await tester.tap(find.byKey(const ValueKey('resizeButton'))); await tester.pumpAndSettle(); expect(buttonTapResizeCompleter.future, completes); }); @@ -446,10 +446,10 @@ void main() { testWidgets('Video plays inline when allowsInlineMediaPlayback is true', (WidgetTester tester) async { - Completer controllerCompleter = + final Completer controllerCompleter = Completer(); - Completer pageLoaded = Completer(); - Completer videoPlaying = Completer(); + final Completer pageLoaded = Completer(); + final Completer videoPlaying = Completer(); await tester.pumpWidget( Directionality( @@ -480,7 +480,7 @@ void main() { ), ), ); - WebViewController controller = await controllerCompleter.future; + final WebViewController controller = await controllerCompleter.future; await pageLoaded.future; // Pump once to trigger the video play. @@ -489,7 +489,7 @@ void main() { // Makes sure we get the correct event that indicates the video is actually playing. await videoPlaying.future; - String fullScreen = + final String fullScreen = await controller.runJavascriptReturningResult('isFullScreen();'); expect(fullScreen, _webviewBool(false)); }); @@ -497,10 +497,10 @@ void main() { testWidgets( 'Video plays full screen when allowsInlineMediaPlayback is false', (WidgetTester tester) async { - Completer controllerCompleter = + final Completer controllerCompleter = Completer(); - Completer pageLoaded = Completer(); - Completer videoPlaying = Completer(); + final Completer pageLoaded = Completer(); + final Completer videoPlaying = Completer(); await tester.pumpWidget( Directionality( @@ -531,7 +531,7 @@ void main() { ), ), ); - WebViewController controller = await controllerCompleter.future; + final WebViewController controller = await controllerCompleter.future; await pageLoaded.future; // Pump once to trigger the video play. @@ -540,7 +540,7 @@ void main() { // Makes sure we get the correct event that indicates the video is actually playing. await videoPlaying.future; - String fullScreen = + final String fullScreen = await controller.runJavascriptReturningResult('isFullScreen();'); expect(fullScreen, _webviewBool(true)); }); @@ -718,7 +718,7 @@ void main() { }); testWidgets('getTitle', (WidgetTester tester) async { - final String getTitleTest = ''' + const String getTitleTest = ''' Some title @@ -768,7 +768,7 @@ void main() { group('Programmatic Scroll', () { testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - final String scrollTestPage = ''' + const String scrollTestPage = ''' @@ -815,7 +815,7 @@ void main() { final WebViewController controller = await controllerCompleter.future; await pageLoaded.future; - await tester.pumpAndSettle(Duration(seconds: 3)); + await tester.pumpAndSettle(const Duration(seconds: 3)); int scrollPosX = await controller.getScrollX(); int scrollPosY = await controller.getScrollY(); @@ -845,7 +845,7 @@ void main() { }); group('NavigationDelegate', () { - final String blankPage = ""; + const String blankPage = ''; final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + base64Encode(const Utf8Encoder().convert(blankPage)); @@ -941,7 +941,7 @@ void main() { testWidgets( 'onWebResourceError only called for main frame', (WidgetTester tester) async { - final String iframeTest = ''' + const String iframeTest = ''' @@ -1161,19 +1161,12 @@ String _webviewBool(bool value) { /// Returns the value used for the HTTP User-Agent: request header in subsequent HTTP requests. Future _getUserAgent(WebViewController controller) async { - return _runJavascriptReturningResult(controller, 'navigator.userAgent;'); -} - -Future _runJavascriptReturningResult( - WebViewController controller, String js) async { - if (defaultTargetPlatform == TargetPlatform.iOS) { - return await controller.runJavascriptReturningResult(js); - } - return jsonDecode(await controller.runJavascriptReturningResult(js)); + return await controller.runJavascriptReturningResult('navigator.userAgent;'); } class ResizableWebView extends StatefulWidget { - ResizableWebView({required this.onResize, required this.onPageFinished}); + const ResizableWebView( + {required this.onResize, required this.onPageFinished}); final JavascriptMessageHandler onResize; final VoidCallback onPageFinished; @@ -1228,14 +1221,14 @@ class ResizableWebViewState extends State { ), ), TextButton( - key: Key('resizeButton'), + key: const Key('resizeButton'), onPressed: () { setState(() { webViewWidth += 100.0; webViewHeight += 100.0; }); }, - child: Text('ResizeButton'), + child: const Text('ResizeButton'), ), ], ), diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart index 46d1954fff8a..3110450e88bb 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart @@ -19,7 +19,7 @@ import 'navigation_request.dart'; import 'web_view.dart'; void main() { - runApp(MaterialApp(home: _WebViewExample())); + runApp(const MaterialApp(home: _WebViewExample())); } const String kNavigationExamplePage = ''' @@ -85,7 +85,7 @@ class _WebViewExampleState extends State<_WebViewExample> { ), // We're using a Builder here so we have a context that is below the Scaffold // to allow calling Scaffold.of(context) so we can show a snackbar. - body: Builder(builder: (context) { + body: Builder(builder: (BuildContext context) { return WebView( initialUrl: 'https://flutter.dev/', onWebViewCreated: (WebViewController controller) { @@ -130,7 +130,7 @@ class _WebViewExampleState extends State<_WebViewExample> { } Set _createJavascriptChannels(BuildContext context) { - return { + return { JavascriptChannel( name: 'Snackbar', onMessageReceived: (JavascriptMessage message) { @@ -155,7 +155,7 @@ enum _MenuOptions { } class _SampleMenu extends StatelessWidget { - _SampleMenu(this.controller); + const _SampleMenu(this.controller); final Future controller; @@ -255,7 +255,7 @@ class _SampleMenu extends StatelessWidget { ); } - void _onShowUserAgent( + Future _onShowUserAgent( WebViewController controller, BuildContext context) async { // Send a message with the user agent string to the Snackbar JavaScript channel we registered // with the WebView. @@ -263,7 +263,7 @@ class _SampleMenu extends StatelessWidget { 'Snackbar.postMessage("User Agent: " + navigator.userAgent);'); } - void _onListCookies( + Future _onListCookies( WebViewController controller, BuildContext context) async { final String cookies = await controller.runJavascriptReturningResult('document.cookie'); @@ -279,7 +279,8 @@ class _SampleMenu extends StatelessWidget { )); } - void _onAddToCache(WebViewController controller, BuildContext context) async { + Future _onAddToCache( + WebViewController controller, BuildContext context) async { await controller.runJavascript( 'caches.open("test_caches_entry"); localStorage["test_localStorage"] = "dummy_entry";'); ScaffoldMessenger.of(context).showSnackBar(const SnackBar( @@ -287,20 +288,22 @@ class _SampleMenu extends StatelessWidget { )); } - void _onListCache(WebViewController controller, BuildContext context) async { + Future _onListCache( + WebViewController controller, BuildContext context) async { await controller.runJavascript('caches.keys()' '.then((cacheKeys) => JSON.stringify({"cacheKeys" : cacheKeys, "localStorage" : localStorage}))' '.then((caches) => Snackbar.postMessage(caches))'); } - void _onClearCache(WebViewController controller, BuildContext context) async { + Future _onClearCache( + WebViewController controller, BuildContext context) async { await controller.clearCache(); ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text("Cache cleared."), + content: Text('Cache cleared.'), )); } - void _onClearCookies( + Future _onClearCookies( WebViewController controller, BuildContext context) async { final bool hadCookies = await WebView.platform.clearCookies(); String message = 'There were cookies. Now, they are gone!'; @@ -312,37 +315,38 @@ class _SampleMenu extends StatelessWidget { )); } - void _onNavigationDelegateExample( + Future _onNavigationDelegateExample( WebViewController controller, BuildContext context) async { final String contentBase64 = base64Encode(const Utf8Encoder().convert(kNavigationExamplePage)); await controller.loadUrl('data:text/html;base64,$contentBase64'); } - void _onLoadLocalFileExample( + Future _onLoadLocalFileExample( WebViewController controller, BuildContext context) async { - String pathToIndex = await _prepareLocalFile(); + final String pathToIndex = await _prepareLocalFile(); await controller.loadFile(pathToIndex); } - void _onLoadHtmlStringExample( + Future _onLoadHtmlStringExample( WebViewController controller, BuildContext context) async { await controller.loadHtmlString(kLocalFileExamplePage); } - void _onDoPostRequest( + Future _onDoPostRequest( WebViewController controller, BuildContext context) async { - WebViewRequest request = WebViewRequest( + final WebViewRequest request = WebViewRequest( uri: Uri.parse('https://httpbin.org/post'), method: WebViewRequestMethod.post, - headers: {'foo': 'bar', 'Content-Type': 'text/plain'}, + headers: {'foo': 'bar', 'Content-Type': 'text/plain'}, body: Uint8List.fromList('Test Body'.codeUnits), ); await controller.loadRequest(request); } - void _onSetCookie(WebViewController controller, BuildContext context) async { + Future _onSetCookie( + WebViewController controller, BuildContext context) async { await WebViewCookieManager.instance.setCookie( const WebViewCookie( name: 'foo', value: 'bar', domain: 'httpbin.org', path: '/anything'), @@ -366,7 +370,7 @@ class _SampleMenu extends StatelessWidget { static Future _prepareLocalFile() async { final String tmpDir = (await getTemporaryDirectory()).path; - File indexFile = File('$tmpDir/www/index.html'); + final File indexFile = File('$tmpDir/www/index.html'); await Directory('$tmpDir/www').create(recursive: true); await indexFile.writeAsString(kLocalFileExamplePage); @@ -403,7 +407,7 @@ class _NavigationControls extends StatelessWidget { } else { // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( - const SnackBar(content: Text("No back history item")), + const SnackBar(content: Text('No back history item')), ); return; } @@ -420,7 +424,7 @@ class _NavigationControls extends StatelessWidget { // ignore: deprecated_member_use Scaffold.of(context).showSnackBar( const SnackBar( - content: Text("No forward history item")), + content: Text('No forward history item')), ); return; } @@ -442,4 +446,4 @@ class _NavigationControls extends StatelessWidget { } /// Callback type for handling messages sent from JavaScript running in a web view. -typedef void JavascriptMessageHandler(JavascriptMessage message); +typedef JavascriptMessageHandler = void Function(JavascriptMessage message); diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart index c1ff8dc5a690..2f6d7c9f8cdd 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/navigation_request.dart @@ -14,6 +14,6 @@ class NavigationRequest { @override String toString() { - return '$runtimeType(url: $url, isForMainFrame: $isForMainFrame)'; + return 'NavigationRequest(url: $url, isForMainFrame: $isForMainFrame)'; } } 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 97f869858304..12fac59dbb73 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 @@ -16,7 +16,7 @@ import 'navigation_request.dart'; /// Optional callback invoked when a web view is first created. [controller] is /// the [WebViewController] for the created web view. -typedef void WebViewCreatedCallback(WebViewController controller); +typedef WebViewCreatedCallback = void Function(WebViewController controller); /// Decides how to handle a specific navigation request. /// @@ -24,20 +24,20 @@ typedef void WebViewCreatedCallback(WebViewController controller); /// `navigation` should be handled. /// /// See also: [WebView.navigationDelegate]. -typedef FutureOr NavigationDelegate( +typedef NavigationDelegate = FutureOr Function( NavigationRequest navigation); /// Signature for when a [WebView] has started loading a page. -typedef void PageStartedCallback(String url); +typedef PageStartedCallback = void Function(String url); /// Signature for when a [WebView] has finished loading a page. -typedef void PageFinishedCallback(String url); +typedef PageFinishedCallback = void Function(String url); /// Signature for when a [WebView] is loading a page. -typedef void PageLoadingCallback(int progress); +typedef PageLoadingCallback = void Function(int progress); /// Signature for when a [WebView] has failed to load a resource. -typedef void WebResourceErrorCallback(WebResourceError error); +typedef WebResourceErrorCallback = void Function(WebResourceError error); /// A web view widget for showing html content. /// @@ -55,7 +55,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, @@ -264,7 +264,7 @@ class _WebViewState extends State { context: context, onWebViewPlatformCreated: (WebViewPlatformController? webViewPlatformController) { - WebViewController controller = WebViewController._( + final WebViewController controller = WebViewController._( widget, webViewPlatformController!, _javascriptChannelRegistry, @@ -553,7 +553,7 @@ class WebViewController { bool? hasNavigationDelegate; bool? hasProgressTracking; bool? debuggingEnabled; - WebSetting userAgent = WebSetting.absent(); + WebSetting userAgent = const WebSetting.absent(); if (currentValue.javascriptMode != newValue.javascriptMode) { javascriptMode = newValue.javascriptMode; } @@ -651,6 +651,7 @@ class _PlatformCallbacksHandler implements WebViewPlatformCallbacksHandler { } } + @override void onWebResourceError(WebResourceError error) { if (_webView.onWebResourceError != null) { _webView.onWebResourceError!(error); diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml index c8001c8ffde4..2888cddac552 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml @@ -21,10 +21,10 @@ dependencies: dev_dependencies: espresso: ^0.1.0+2 - flutter_test: - sdk: flutter flutter_driver: sdk: flutter + flutter_test: + sdk: flutter integration_test: sdk: flutter pedantic: ^1.10.0 diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/wkwebview_cookie_manager_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/wkwebview_cookie_manager_test.dart index a6e5d5243005..54b1921583b9 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/wkwebview_cookie_manager_test.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/wkwebview_cookie_manager_test.dart @@ -7,7 +7,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; import 'package:webview_flutter_wkwebview/src/wkwebview_cookie_manager.dart'; -main() { +void main() { TestWidgetsFlutterBinding.ensureInitialized(); const MethodChannel cookieChannel = MethodChannel('plugins.flutter.io/cookie_manager'); @@ -52,7 +52,7 @@ main() { [ isMethodCall( 'setCookie', - arguments: { + arguments: { 'name': 'foo', 'value': 'bar', 'domain': 'flutter.dev', From d58f74905b783391cecb350d1bb0ad2351db6199 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Fri, 3 Dec 2021 13:11:10 +0100 Subject: [PATCH 15/18] Updated platform interface dependency --- .../webview_flutter/webview_flutter_wkwebview/pubspec.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml index f6da86ddb636..8dd87f19ac1f 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml +++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml @@ -18,9 +18,7 @@ flutter: dependencies: flutter: sdk: flutter -# TODO (BeMacized): Update dependency when changes have been merged and published. - webview_flutter_platform_interface: - path: ../webview_flutter_platform_interface + webview_flutter_platform_interface: ^1.7.0 dev_dependencies: flutter_driver: From 658e03920fc2eeb37710260d35fc816b9f315f4c Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 7 Dec 2021 10:46:45 +0100 Subject: [PATCH 16/18] Process PR feedback --- .../webview_flutter_wkwebview/CHANGELOG.md | 2 +- .../lib/src/webview_cupertino.dart | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index c01cfc8e51e3..b7baade1a25a 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -1,7 +1,7 @@ ## 2.5.0 * Integration test fixes. -* 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_wkwebview/lib/src/webview_cupertino.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart index e4292e28e50e..f28602d0315f 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart @@ -45,6 +45,11 @@ class CupertinoWebView implements WebViewPlatform { } @override - Future clearCookies() => - WebViewCookieManagerPlatform.instance!.clearCookies(); + Future clearCookies() { + if (WebViewCookieManagerPlatform.instance == null) { + throw Exception( + 'Could not clear cookies as no implementation for the WebViewCookieManagerPlatform has been registered.'); + } + return WebViewCookieManagerPlatform.instance!.clearCookies(); + } } From e084f975a98fe18e5ee172bc89637dc69476e5ce Mon Sep 17 00:00:00 2001 From: BeMacized Date: Tue, 7 Dec 2021 10:58:01 +0100 Subject: [PATCH 17/18] Update error description --- .../webview_flutter_wkwebview/lib/src/webview_cupertino.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart index f28602d0315f..cd00d9a7d14b 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart +++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webview_cupertino.dart @@ -48,7 +48,7 @@ class CupertinoWebView implements WebViewPlatform { Future clearCookies() { if (WebViewCookieManagerPlatform.instance == null) { throw Exception( - 'Could not clear cookies as no implementation for the WebViewCookieManagerPlatform has been registered.'); + 'Could not clear cookies as no implementation for WebViewCookieManagerPlatform has been registered.'); } return WebViewCookieManagerPlatform.instance!.clearCookies(); } From 3effc36a7fbde2bb57468edd52cc0f1152baa16a Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 7 Dec 2021 18:45:50 +0100 Subject: [PATCH 18/18] Remove unnecessary changelog change --- packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md index 8f409df55996..c1d27121f9ee 100644 --- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md +++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md @@ -7,6 +7,7 @@ * Adds an option to set the background color of the webview. * Migrates from `analysis_options_legacy.yaml` to `analysis_options.yaml`. * Integration test fixes. +* Updates to webview_flutter_platform_interface version 1.5.2. ## 2.4.0