From 7da9cb264366466eaac2cf15aa3e552efa7300c9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 28 Jan 2024 00:41:48 +0100 Subject: [PATCH] windows: updated webview environment docs, updated cookie manager to support webview environment --- .../lib/src/cookie_manager.dart | 19 +- .../platform_in_app_browser.dart | 2 +- .../platform_headless_in_app_webview.dart | 2 +- .../platform_inappwebview_widget.dart | 2 +- .../lib/src/platform_cookie_manager.dart | 9 +- .../platform_webview_environment.dart | 8 +- .../webview_environment_settings.dart | 66 +++++++ .../webview_environment_settings.g.dart | 70 +++++++ .../lib/src/cookie_manager.dart | 38 +++- .../windows/cookie_manager.cpp | 174 ++++++++++-------- .../windows/cookie_manager.h | 12 +- .../windows/in_app_webview/in_app_webview.cpp | 6 +- .../windows/in_app_webview/in_app_webview.h | 2 +- .../webview_environment.cpp | 43 ++++- .../webview_environment/webview_environment.h | 20 +- .../webview_environment_manager.cpp | 41 ++++- .../webview_environment_manager.h | 10 + 17 files changed, 407 insertions(+), 117 deletions(-) diff --git a/flutter_inappwebview/lib/src/cookie_manager.dart b/flutter_inappwebview/lib/src/cookie_manager.dart index 19afa277..11247bfe 100755 --- a/flutter_inappwebview/lib/src/cookie_manager.dart +++ b/flutter_inappwebview/lib/src/cookie_manager.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; import 'in_app_webview/in_app_webview_controller.dart'; +import 'webview_environment/webview_environment.dart'; ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager} class CookieManager { @@ -31,12 +32,22 @@ class CookieManager { static CookieManager? _instance; + WebViewEnvironment? _webViewEnvironment; + ///Gets the [CookieManager] shared instance. - static CookieManager instance() { - if (_instance == null) { - _instance = CookieManager(); + /// + ///[webViewEnvironment] (Supported only on Windows) - Used to create the [CookieManager] using the specified environment. + static CookieManager instance({WebViewEnvironment? webViewEnvironment}) { + if (webViewEnvironment == null) { + if (_instance == null) { + _instance = CookieManager(); + } + return _instance!; + } else { + return CookieManager.fromPlatformCreationParams( + PlatformCookieManagerCreationParams(webViewEnvironment: webViewEnvironment.platform) + ); } - return _instance!; } ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.setCookie} diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.dart index c1ebeefe..45c29bb6 100755 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/platform_in_app_browser.dart @@ -56,7 +56,7 @@ class PlatformInAppBrowserCreationParams { ///{@macro flutter_inappwebview_platform_interface.PlatformInAppBrowser.windowId} final int? windowId; - ///Used create the [PlatformInAppBrowser] using the specified environment. + ///Used to create the [PlatformInAppBrowser] using the specified environment. /// ///**Officially Supported Platforms/Implementations**: ///- Windows diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_headless_in_app_webview.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_headless_in_app_webview.dart index 9fd5c7ab..99ea3b4f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_headless_in_app_webview.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_headless_in_app_webview.dart @@ -144,7 +144,7 @@ class PlatformHeadlessInAppWebViewCreationParams ///- MacOS final Size initialSize; - ///Used create the [PlatformHeadlessInAppWebView] using the specified environment. + ///Used to create the [PlatformHeadlessInAppWebView] using the specified environment. /// ///**Officially Supported Platforms/Implementations**: ///- Windows diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_inappwebview_widget.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_inappwebview_widget.dart index 0f3aa670..e8194a92 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_inappwebview_widget.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_inappwebview_widget.dart @@ -184,7 +184,7 @@ class PlatformInAppWebViewWidgetCreationParams ///- iOS final bool? preventGestureDelay; - ///Used create the [PlatformInAppWebViewWidget] using the specified environment. + ///Used to create the [PlatformInAppWebViewWidget] using the specified environment. /// ///**Officially Supported Platforms/Implementations**: ///- Windows diff --git a/flutter_inappwebview_platform_interface/lib/src/platform_cookie_manager.dart b/flutter_inappwebview_platform_interface/lib/src/platform_cookie_manager.dart index a3e98c5e..81bbb37a 100755 --- a/flutter_inappwebview_platform_interface/lib/src/platform_cookie_manager.dart +++ b/flutter_inappwebview_platform_interface/lib/src/platform_cookie_manager.dart @@ -8,6 +8,7 @@ import 'types/main.dart'; import 'web_uri.dart'; import 'inappwebview_platform.dart'; import 'in_app_webview/platform_headless_in_app_webview.dart'; +import 'webview_environment/platform_webview_environment.dart'; /// Object specifying creation parameters for creating a [PlatformCookieManager]. /// @@ -16,7 +17,13 @@ import 'in_app_webview/platform_headless_in_app_webview.dart'; @immutable class PlatformCookieManagerCreationParams { /// Used by the platform implementation to create a new [PlatformCookieManager]. - const PlatformCookieManagerCreationParams(); + const PlatformCookieManagerCreationParams({this.webViewEnvironment}); + + ///Used to create the [PlatformCookieManager] using the specified environment. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + final PlatformWebViewEnvironment? webViewEnvironment; } ///{@template flutter_inappwebview_platform_interface.PlatformCookieManager} diff --git a/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.dart b/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.dart index 9bbe5bb5..d5c156c9 100644 --- a/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.dart +++ b/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.dart @@ -88,7 +88,13 @@ abstract class PlatformWebViewEnvironment extends PlatformInterface WebViewEnvironmentSettings? get settings => params.settings; ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.create} - ///Initializes the [PlatformWebViewEnvironment] using [settings]. + ///Creates the [PlatformWebViewEnvironment] using [settings]. + /// + ///Check https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions + ///for more info. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - CreateCoreWebView2EnvironmentWithOptions](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions)) ///{@endtemplate} Future create( {WebViewEnvironmentSettings? settings}) { diff --git a/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.dart b/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.dart index 6c14a6d4..0a7ee483 100644 --- a/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.dart @@ -5,13 +5,79 @@ import 'platform_webview_environment.dart'; part 'webview_environment_settings.g.dart'; ///This class represents all the [PlatformWebViewEnvironment] settings available. +/// +///The [browserExecutableFolder], [userDataFolder] and [additionalBrowserArguments] +///may be overridden by values either specified in environment variables or in the registry. +@SupportedPlatforms(platforms: [ + WindowsPlatform() +]) @ExchangeableObject(copyMethod: true) class WebViewEnvironmentSettings_ { + ///Use [browserExecutableFolder] to specify whether WebView2 controls use a fixed + ///or installed version of the WebView2 Runtime that exists on a user machine. + ///To use a fixed version of the WebView2 Runtime, pass the folder path that contains + ///the fixed version of the WebView2 Runtime to [browserExecutableFolder]. + ///BrowserExecutableFolder supports both relative (to the application's executable) and absolute files paths. + ///To create WebView2 controls that use the installed version of the WebView2 Runtime that exists on user machines, + ///pass a `null` or empty string to [browserExecutableFolder]. + ///In this scenario, the API tries to find a compatible version of the WebView2 Runtime + ///that is installed on the user machine (first at the machine level, and then per user) using the selected channel preference. + ///The path of fixed version of the WebView2 Runtime should not contain `\Edge\Application\`. + ///When such a path is used, the API fails with `HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)`. + /// + ///The default channel search order is the WebView2 Runtime, Beta, Dev, and Canary. + ///When an override `WEBVIEW2_RELEASE_CHANNEL_PREFERENCE` environment variable or + ///applicable `releaseChannelPreference` registry value is set to `1`, the channel search order is reversed. + @SupportedPlatforms(platforms: [ + WindowsPlatform(apiName: 'CreateCoreWebView2EnvironmentWithOptions.browserExecutableFolder', apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions') + ]) final String? browserExecutableFolder; + + ///You may specify the [userDataFolder] to change the default user data folder location for WebView2. + ///The path is either an absolute file path or a relative file path that is interpreted as relative + ///to the compiled code for the current process. + ///For UWP apps, the default user data folder is the app data folder for the package. + ///For non-UWP apps, the default user data (`{Executable File Name}.WebView2`) folder + ///is created in the same directory next to the compiled code for the app. + ///WebView2 creation fails if the compiled code is running in a directory in which the + ///process does not have permission to create a new directory. + ///The app is responsible to clean up the associated user data folder when it is done. + /// + ///**NOTE**: As a browser process may be shared among WebViews, + ///WebView creation fails with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)` if the specified + ///options does not match the options of the WebViews that are currently + ///running in the shared browser process. + @SupportedPlatforms(platforms: [ + WindowsPlatform(apiName: 'CreateCoreWebView2EnvironmentWithOptions.userDataFolder', apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions') + ]) final String? userDataFolder; + + ///If there are multiple switches, there should be a space in between them. + ///The one exception is if multiple features are being enabled/disabled for a single switch, + ///in which case the features should be comma-seperated. + ///Example: `"--disable-features=feature1,feature2 --some-other-switch --do-something"` + @SupportedPlatforms(platforms: [ + WindowsPlatform(apiName: 'ICoreWebView2EnvironmentOptions.put_AdditionalBrowserArguments', apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_additionalbrowserarguments') + ]) final String? additionalBrowserArguments; + + ///This property is used to enable single sign on with Azure Active Directory (AAD) + ///and personal Microsoft Account (MSA) resources inside WebView. + @SupportedPlatforms(platforms: [ + WindowsPlatform(apiName: 'ICoreWebView2EnvironmentOptions.put_AllowSingleSignOnUsingOSPrimaryAccount', apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_allowsinglesignonusingosprimaryaccount') + ]) final bool? allowSingleSignOnUsingOSPrimaryAccount; + + ///The default display language for WebView. + @SupportedPlatforms(platforms: [ + WindowsPlatform(apiName: 'ICoreWebView2EnvironmentOptions.put_Language', apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_language') + ]) final String? language; + + ///Specifies the version of the WebView2 Runtime binaries required to be compatible with your app. + @SupportedPlatforms(platforms: [ + WindowsPlatform(apiName: 'ICoreWebView2EnvironmentOptions.put_TargetCompatibleBrowserVersion', apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_targetcompatiblebrowserversion') + ]) final String? targetCompatibleBrowserVersion; WebViewEnvironmentSettings_({ diff --git a/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.g.dart index c89b9f53..eb62b39f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.g.dart @@ -7,13 +7,83 @@ part of 'webview_environment_settings.dart'; // ************************************************************************** ///This class represents all the [PlatformWebViewEnvironment] settings available. +/// +///The [browserExecutableFolder], [userDataFolder] and [additionalBrowserArguments] +///may be overridden by values either specified in environment variables or in the registry. +/// +///**Officially Supported Platforms/Implementations**: +///- Windows class WebViewEnvironmentSettings { + ///If there are multiple switches, there should be a space in between them. + ///The one exception is if multiple features are being enabled/disabled for a single switch, + ///in which case the features should be comma-seperated. + ///Example: `"--disable-features=feature1,feature2 --some-other-switch --do-something"` + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - ICoreWebView2EnvironmentOptions.put_AdditionalBrowserArguments](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_additionalbrowserarguments)) final String? additionalBrowserArguments; + + ///This property is used to enable single sign on with Azure Active Directory (AAD) + ///and personal Microsoft Account (MSA) resources inside WebView. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - ICoreWebView2EnvironmentOptions.put_AllowSingleSignOnUsingOSPrimaryAccount](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_allowsinglesignonusingosprimaryaccount)) final bool? allowSingleSignOnUsingOSPrimaryAccount; + + ///Use [browserExecutableFolder] to specify whether WebView2 controls use a fixed + ///or installed version of the WebView2 Runtime that exists on a user machine. + ///To use a fixed version of the WebView2 Runtime, pass the folder path that contains + ///the fixed version of the WebView2 Runtime to [browserExecutableFolder]. + ///BrowserExecutableFolder supports both relative (to the application's executable) and absolute files paths. + ///To create WebView2 controls that use the installed version of the WebView2 Runtime that exists on user machines, + ///pass a `null` or empty string to [browserExecutableFolder]. + ///In this scenario, the API tries to find a compatible version of the WebView2 Runtime + ///that is installed on the user machine (first at the machine level, and then per user) using the selected channel preference. + ///The path of fixed version of the WebView2 Runtime should not contain `\Edge\Application\`. + ///When such a path is used, the API fails with `HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)`. + /// + ///The default channel search order is the WebView2 Runtime, Beta, Dev, and Canary. + ///When an override `WEBVIEW2_RELEASE_CHANNEL_PREFERENCE` environment variable or + ///applicable `releaseChannelPreference` registry value is set to `1`, the channel search order is reversed. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - CreateCoreWebView2EnvironmentWithOptions.browserExecutableFolder](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions)) final String? browserExecutableFolder; + + ///The default display language for WebView. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - ICoreWebView2EnvironmentOptions.put_Language](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_language)) final String? language; + + ///Specifies the version of the WebView2 Runtime binaries required to be compatible with your app. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - ICoreWebView2EnvironmentOptions.put_TargetCompatibleBrowserVersion](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_targetcompatiblebrowserversion)) final String? targetCompatibleBrowserVersion; + + ///You may specify the [userDataFolder] to change the default user data folder location for WebView2. + ///The path is either an absolute file path or a relative file path that is interpreted as relative + ///to the compiled code for the current process. + ///For UWP apps, the default user data folder is the app data folder for the package. + ///For non-UWP apps, the default user data (`{Executable File Name}.WebView2`) folder + ///is created in the same directory next to the compiled code for the app. + ///WebView2 creation fails if the compiled code is running in a directory in which the + ///process does not have permission to create a new directory. + ///The app is responsible to clean up the associated user data folder when it is done. + /// + ///**NOTE**: As a browser process may be shared among WebViews, + ///WebView creation fails with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)` if the specified + ///options does not match the options of the WebViews that are currently + ///running in the shared browser process. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - CreateCoreWebView2EnvironmentWithOptions.userDataFolder](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions)) final String? userDataFolder; + + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebViewEnvironmentSettings( {this.additionalBrowserArguments, this.allowSingleSignOnUsingOSPrimaryAccount, diff --git a/flutter_inappwebview_windows/lib/src/cookie_manager.dart b/flutter_inappwebview_windows/lib/src/cookie_manager.dart index 81903ca7..10882604 100644 --- a/flutter_inappwebview_windows/lib/src/cookie_manager.dart +++ b/flutter_inappwebview_windows/lib/src/cookie_manager.dart @@ -5,6 +5,8 @@ import 'package:flutter/services.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; +import 'webview_environment/webview_environment.dart'; + /// Object specifying creation parameters for creating a [WindowsCookieManager]. /// /// When adding additional fields make sure they can be null or have a default @@ -15,16 +17,19 @@ class WindowsCookieManagerCreationParams extends PlatformCookieManagerCreationParams { /// Creates a new [WindowsCookieManagerCreationParams] instance. const WindowsCookieManagerCreationParams( - // This parameter prevents breaking changes later. - // ignore: avoid_unused_constructor_parameters - PlatformCookieManagerCreationParams params, - ) : super(); + {this.webViewEnvironment}); /// Creates a [WindowsCookieManagerCreationParams] instance based on [PlatformCookieManagerCreationParams]. factory WindowsCookieManagerCreationParams.fromPlatformCookieManagerCreationParams( + // Recommended placeholder to prevent being broken by platform interface. + // ignore: avoid_unused_constructor_parameters PlatformCookieManagerCreationParams params) { - return WindowsCookieManagerCreationParams(params); + return WindowsCookieManagerCreationParams( + webViewEnvironment: params.webViewEnvironment as WindowsWebViewEnvironment?); } + + @override + final WindowsWebViewEnvironment? webViewEnvironment; } ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager} @@ -47,13 +52,21 @@ class WindowsCookieManager extends PlatformCookieManager static WindowsCookieManager? _instance; ///Gets the [WindowsCookieManager] shared instance. - static WindowsCookieManager instance() { - return (_instance != null) ? _instance! : _init(); + static WindowsCookieManager instance({WindowsWebViewEnvironment? webViewEnvironment}) { + if (webViewEnvironment == null) { + if (_instance == null) { + _instance = _init(); + } + return _instance!; + } else { + return WindowsCookieManager( + WindowsCookieManagerCreationParams(webViewEnvironment: webViewEnvironment) + ); + } } static WindowsCookieManager _init() { - _instance = WindowsCookieManager(WindowsCookieManagerCreationParams( - const PlatformCookieManagerCreationParams())); + _instance = WindowsCookieManager(WindowsCookieManagerCreationParams()); return _instance!; } @@ -90,6 +103,7 @@ class WindowsCookieManager extends PlatformCookieManager args.putIfAbsent('isSecure', () => isSecure); args.putIfAbsent('isHttpOnly', () => isHttpOnly); args.putIfAbsent('sameSite', () => sameSite?.toNativeValue()); + args.putIfAbsent('webViewEnvironmentId', () => params.webViewEnvironment?.id); return await channel?.invokeMethod('setCookie', args) ?? false; } @@ -106,6 +120,7 @@ class WindowsCookieManager extends PlatformCookieManager Map args = {}; args.putIfAbsent('url', () => url.toString()); + args.putIfAbsent('webViewEnvironmentId', () => params.webViewEnvironment?.id); List cookieListMap = await channel?.invokeMethod('getCookies', args) ?? []; cookieListMap = cookieListMap.cast>(); @@ -138,6 +153,7 @@ class WindowsCookieManager extends PlatformCookieManager Map args = {}; args.putIfAbsent('url', () => url.toString()); + args.putIfAbsent('webViewEnvironmentId', () => params.webViewEnvironment?.id); List cookies = await channel?.invokeMethod('getCookies', args) ?? []; cookies = cookies.cast>(); @@ -176,6 +192,7 @@ class WindowsCookieManager extends PlatformCookieManager args.putIfAbsent('name', () => name); args.putIfAbsent('domain', () => domain); args.putIfAbsent('path', () => path); + args.putIfAbsent('webViewEnvironmentId', () => params.webViewEnvironment?.id); return await channel?.invokeMethod('deleteCookie', args) ?? false; } @@ -193,18 +210,21 @@ class WindowsCookieManager extends PlatformCookieManager args.putIfAbsent('url', () => url.toString()); args.putIfAbsent('domain', () => domain); args.putIfAbsent('path', () => path); + args.putIfAbsent('webViewEnvironmentId', () => params.webViewEnvironment?.id); return await channel?.invokeMethod('deleteCookies', args) ?? false; } @override Future deleteAllCookies() async { Map args = {}; + args.putIfAbsent('webViewEnvironmentId', () => params.webViewEnvironment?.id); return await channel?.invokeMethod('deleteAllCookies', args) ?? false; } @override Future removeSessionCookies() async { Map args = {}; + args.putIfAbsent('webViewEnvironmentId', () => params.webViewEnvironment?.id); return await channel?.invokeMethod('removeSessionCookies', args) ?? false; } diff --git a/flutter_inappwebview_windows/windows/cookie_manager.cpp b/flutter_inappwebview_windows/windows/cookie_manager.cpp index 23500931..9ab62069 100644 --- a/flutter_inappwebview_windows/windows/cookie_manager.cpp +++ b/flutter_inappwebview_windows/windows/cookie_manager.cpp @@ -1,11 +1,11 @@ +#include #include #include -#include #include #include #include "cookie_manager.h" -#include "in_app_webview/in_app_webview.h" +#include "utils/flutter.h" #include "utils/log.h" namespace flutter_inappwebview_plugin @@ -13,32 +13,8 @@ namespace flutter_inappwebview_plugin using namespace Microsoft::WRL; CookieManager::CookieManager(const FlutterInappwebviewWindowsPlugin* plugin) - : ChannelDelegate(plugin->registrar->messenger(), CookieManager::METHOD_CHANNEL_NAME_PREFIX) - { - windowClass_.lpszClassName = CookieManager::CLASS_NAME; - windowClass_.lpfnWndProc = &DefWindowProc; - - RegisterClass(&windowClass_); - - auto hwnd = CreateWindowEx(0, windowClass_.lpszClassName, L"", 0, 0, - 0, 0, 0, - plugin->registrar->GetView()->GetNativeWindow(), - nullptr, - windowClass_.hInstance, nullptr); - - InAppWebView::createInAppWebViewEnv(hwnd, false, nullptr, - [=](wil::com_ptr webViewEnv, - wil::com_ptr webViewController, - wil::com_ptr webViewCompositionController) - { - if (webViewEnv && webViewController) { - webViewEnv_ = std::move(webViewEnv); - webViewController_ = std::move(webViewController); - webViewController_->get_CoreWebView2(&webView_); - webViewController_->put_IsVisible(false); - } - }); - } + : plugin(plugin), ChannelDelegate(plugin->registrar->messenger(), CookieManager::METHOD_CHANNEL_NAME_PREFIX) + {} void CookieManager::HandleMethodCall(const flutter::MethodCall& method_call, std::unique_ptr> result) @@ -46,69 +22,105 @@ namespace flutter_inappwebview_plugin auto& arguments = std::get(*method_call.arguments()); auto& methodName = method_call.method_name(); - if (string_equals(methodName, "setCookie")) { - if (!webView_) { - result->Success(false); - return; - } + auto webViewEnvironmentId = get_optional_fl_map_value(arguments, "webViewEnvironmentId"); - auto url = get_fl_map_value(arguments, "url"); - auto name = get_fl_map_value(arguments, "name"); - auto value = get_fl_map_value(arguments, "value"); - auto path = get_fl_map_value(arguments, "path"); - auto domain = get_optional_fl_map_value(arguments, "domain"); - auto expiresDate = get_optional_fl_map_value(arguments, "expiresDate"); - auto maxAge = get_optional_fl_map_value(arguments, "maxAge"); - auto isSecure = get_optional_fl_map_value(arguments, "isSecure"); - auto isHttpOnly = get_optional_fl_map_value(arguments, "isHttpOnly"); - auto sameSite = get_optional_fl_map_value(arguments, "sameSite"); + auto webViewEnvironment = webViewEnvironmentId.has_value() && map_contains(plugin->webViewEnvironmentManager->webViewEnvironments, webViewEnvironmentId.value()) + ? plugin->webViewEnvironmentManager->webViewEnvironments.at(webViewEnvironmentId.value()).get() : nullptr; - nlohmann::json parameters = { - {"url", url}, - {"name", name}, - {"value", value}, - {"path", path} - }; - if (domain.has_value()) { - parameters["domain"] = domain.value(); - } - if (expiresDate.has_value()) { - parameters["expires"] = expiresDate.value() / 1000; - } - if (maxAge.has_value()) { - // time(NULL) represents the current unix timestamp in seconds - parameters["expires"] = time(NULL) + maxAge.value(); - } - if (isSecure.has_value()) { - parameters["secure"] = isSecure.value(); - } - if (isHttpOnly.has_value()) { - parameters["httpOnly"] = isHttpOnly.value(); - } - if (sameSite.has_value()) { - parameters["sameSite"] = sameSite.value(); - } - - auto result_ = std::shared_ptr>(std::move(result)); - auto hr = webView_->CallDevToolsProtocolMethod(L"Network.setCookie", utf8_to_wide(parameters.dump()).c_str(), Callback( - [this, result_](HRESULT errorCode, LPCWSTR returnObjectAsJson) - { - result_->Success(succeededOrLog(errorCode)); - return S_OK; + auto result_ = std::shared_ptr>(std::move(result)); + auto callback = [this, result_, methodName, arguments](WebViewEnvironment* webViewEnvironment) + { + if (!webViewEnvironment) { + result_->Error("0", "Cannot obtain the WebViewEnvironment!"); + return; } - ).Get()); - if (failedAndLog(hr)) { - result_->Success(false); - } + if (string_equals(methodName, "setCookie")) { + setCookie(webViewEnvironment, arguments, [result_](const bool& created) + { + result_->Success(created); + }); + } + else { + result_->NotImplemented(); + } + }; + + if (webViewEnvironment) { + callback(webViewEnvironment); } else { - result->NotImplemented(); + plugin->webViewEnvironmentManager->createOrGetDefaultWebViewEnvironment([callback](WebViewEnvironment* webViewEnvironment) + { + callback(webViewEnvironment); + }); + } + } + + void CookieManager::setCookie(WebViewEnvironment* webViewEnvironment, const flutter::EncodableMap& map, std::function completionHandler) const + { + if (!plugin || !plugin->webViewEnvironmentManager) { + if (completionHandler) { + completionHandler(false); + } + return; + } + + auto url = get_fl_map_value(map, "url"); + auto name = get_fl_map_value(map, "name"); + auto value = get_fl_map_value(map, "value"); + auto path = get_fl_map_value(map, "path"); + auto domain = get_optional_fl_map_value(map, "domain"); + auto expiresDate = get_optional_fl_map_value(map, "expiresDate"); + auto maxAge = get_optional_fl_map_value(map, "maxAge"); + auto isSecure = get_optional_fl_map_value(map, "isSecure"); + auto isHttpOnly = get_optional_fl_map_value(map, "isHttpOnly"); + auto sameSite = get_optional_fl_map_value(map, "sameSite"); + + nlohmann::json parameters = { + {"url", url}, + {"name", name}, + {"value", value}, + {"path", path} + }; + if (domain.has_value()) { + parameters["domain"] = domain.value(); + } + if (expiresDate.has_value()) { + parameters["expires"] = expiresDate.value() / 1000; + } + if (maxAge.has_value()) { + // time(NULL) represents the current unix timestamp in seconds + parameters["expires"] = time(NULL) + maxAge.value(); + } + if (isSecure.has_value()) { + parameters["secure"] = isSecure.value(); + } + if (isHttpOnly.has_value()) { + parameters["httpOnly"] = isHttpOnly.value(); + } + if (sameSite.has_value()) { + parameters["sameSite"] = sameSite.value(); + } + + auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.setCookie", utf8_to_wide(parameters.dump()).c_str(), Callback( + [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) + { + if (completionHandler) { + completionHandler(succeededOrLog(errorCode)); + } + return S_OK; + } + ).Get()); + + if (failedAndLog(hr) && completionHandler) { + completionHandler(false); } } CookieManager::~CookieManager() { debugLog("dealloc CookieManager"); + plugin = nullptr; } -} \ No newline at end of file +} diff --git a/flutter_inappwebview_windows/windows/cookie_manager.h b/flutter_inappwebview_windows/windows/cookie_manager.h index 6d3d3daa..b6f596d7 100644 --- a/flutter_inappwebview_windows/windows/cookie_manager.h +++ b/flutter_inappwebview_windows/windows/cookie_manager.h @@ -3,18 +3,17 @@ #include #include -#include -#include +#include #include "flutter_inappwebview_windows_plugin.h" #include "types/channel_delegate.h" +#include "webview_environment/webview_environment_manager.h" namespace flutter_inappwebview_plugin { class CookieManager : public ChannelDelegate { public: - static inline const wchar_t* CLASS_NAME = L"CookieManager"; static inline const std::string METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_cookiemanager"; const FlutterInappwebviewWindowsPlugin* plugin; @@ -25,11 +24,8 @@ namespace flutter_inappwebview_plugin void HandleMethodCall( const flutter::MethodCall& method_call, std::unique_ptr> result); - private: - wil::com_ptr webViewEnv_; - wil::com_ptr webViewController_; - wil::com_ptr webView_; - WNDCLASS windowClass_ = {}; + + void setCookie(WebViewEnvironment* webViewEnvironment, const flutter::EncodableMap& map, std::function completionHandler) const; }; } diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp index 9540048b..f85e6be9 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp @@ -57,7 +57,7 @@ namespace flutter_inappwebview_plugin this->inAppBrowser = inAppBrowser; } - void InAppWebView::createInAppWebViewEnv(const HWND parentWindow, const bool& willBeSurface, const WebViewEnvironment* webViewEnvironment, std::function webViewEnv, + void InAppWebView::createInAppWebViewEnv(const HWND parentWindow, const bool& willBeSurface, WebViewEnvironment* webViewEnvironment, std::function webViewEnv, wil::com_ptr webViewController, wil::com_ptr webViewCompositionController)> completionHandler) { @@ -109,8 +109,8 @@ namespace flutter_inappwebview_plugin }; HRESULT hr; - if (webViewEnvironment && webViewEnvironment->env) { - hr = callback(S_OK, webViewEnvironment->env); + if (webViewEnvironment && webViewEnvironment->getEnvironment()) { + hr = callback(S_OK, webViewEnvironment->getEnvironment()); } else { hr = CreateCoreWebView2EnvironmentWithOptions( diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h index 3caf70ca..95dfa6a4 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h @@ -109,7 +109,7 @@ namespace flutter_inappwebview_plugin wil::com_ptr webViewCompositionController); ~InAppWebView(); - static void createInAppWebViewEnv(const HWND parentWindow, const bool& willBeSurface, const WebViewEnvironment* webViewEnvironment, std::function webViewEnv, + static void createInAppWebViewEnv(const HWND parentWindow, const bool& willBeSurface, WebViewEnvironment* webViewEnvironment, std::function webViewEnv, wil::com_ptr webViewController, wil::com_ptr webViewCompositionController)> completionHandler); diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp index 575f0d33..e8ae3933 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp @@ -4,6 +4,8 @@ #include "../utils/log.h" #include "webview_environment.h" +#include "webview_environment_manager.h" + namespace flutter_inappwebview_plugin { using namespace Microsoft::WRL; @@ -15,6 +17,21 @@ namespace flutter_inappwebview_plugin void WebViewEnvironment::create(const std::unique_ptr settings, const std::function completionHandler) { + if (!plugin) { + if (completionHandler) { + completionHandler(E_FAIL); + } + return; + } + + auto hwnd = plugin->webViewEnvironmentManager->getHWND(); + if (!hwnd) { + if (completionHandler) { + completionHandler(E_FAIL); + } + return; + } + auto options = Make(); if (settings) { if (settings->additionalBrowserArguments.has_value()) { @@ -36,12 +53,30 @@ namespace flutter_inappwebview_plugin settings && settings->userDataFolder.has_value() ? utf8_to_wide(settings->userDataFolder.value()).c_str() : nullptr, options.Get(), Callback( - [this, completionHandler](HRESULT result, wil::com_ptr environment) -> HRESULT + [this, hwnd, completionHandler](HRESULT result, wil::com_ptr environment) -> HRESULT { if (succeededOrLog(result)) { - env = std::move(environment); + environment_ = std::move(environment); + + auto hr = environment_->CreateCoreWebView2Controller(hwnd, Callback( + [this, completionHandler](HRESULT result, wil::com_ptr controller) -> HRESULT + { + if (succeededOrLog(result)) { + webViewController_ = std::move(controller); + webViewController_->get_CoreWebView2(&webView_); + webViewController_->put_IsVisible(false); + } + if (completionHandler) { + completionHandler(result); + } + return S_OK; + }).Get()); + + if (failedAndLog(hr) && completionHandler) { + completionHandler(hr); + } } - if (completionHandler) { + else if (completionHandler) { completionHandler(result); } return S_OK; @@ -56,4 +91,4 @@ namespace flutter_inappwebview_plugin { debugLog("dealloc WebViewEnvironment"); } -} \ No newline at end of file +} diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.h b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.h index 849b48ba..615442d4 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.h +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.h @@ -14,17 +14,35 @@ namespace flutter_inappwebview_plugin class WebViewEnvironment { public: + static inline const wchar_t* CLASS_NAME = L"WebViewEnvironment"; static inline const std::string METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_webview_environment_"; const FlutterInappwebviewWindowsPlugin* plugin; std::string id; - wil::com_ptr env; + std::unique_ptr channelDelegate; WebViewEnvironment(const FlutterInappwebviewWindowsPlugin* plugin, const std::string& id); ~WebViewEnvironment(); void create(const std::unique_ptr settings, const std::function completionHandler); + wil::com_ptr getEnvironment() + { + return environment_; + } + wil::com_ptr getWebViewController() + { + return webViewController_; + } + wil::com_ptr getWebView() + { + return webView_; + } + private: + wil::com_ptr environment_; + wil::com_ptr webViewController_; + wil::com_ptr webView_; + WNDCLASS windowClass_ = {}; }; } #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_ENVIRONMENT_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_manager.cpp b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_manager.cpp index b0b492b4..81e07fd8 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_manager.cpp +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_manager.cpp @@ -14,7 +14,18 @@ namespace flutter_inappwebview_plugin WebViewEnvironmentManager::WebViewEnvironmentManager(const FlutterInappwebviewWindowsPlugin* plugin) : plugin(plugin), ChannelDelegate(plugin->registrar->messenger(), WebViewEnvironmentManager::METHOD_CHANNEL_NAME) - {} + { + windowClass_.lpszClassName = WebViewEnvironmentManager::CLASS_NAME; + windowClass_.lpfnWndProc = &DefWindowProc; + + RegisterClass(&windowClass_); + + hwnd_ = CreateWindowEx(0, windowClass_.lpszClassName, L"", 0, 0, + 0, 0, 0, + plugin->registrar->GetView()->GetNativeWindow(), + nullptr, + windowClass_.hInstance, nullptr); + } void WebViewEnvironmentManager::HandleMethodCall(const flutter::MethodCall& method_call, std::unique_ptr> result) @@ -54,10 +65,38 @@ namespace flutter_inappwebview_plugin webViewEnvironments.insert({ id, std::move(webViewEnvironment) }); } + void WebViewEnvironmentManager::createOrGetDefaultWebViewEnvironment(const std::function completionHandler) + { + if (defaultEnvironment_) { + if (completionHandler) { + completionHandler(defaultEnvironment_.get()); + } + return; + } + + defaultEnvironment_ = std::make_unique(plugin, "-1"); + defaultEnvironment_->create(nullptr, [this, completionHandler](HRESULT errorCode) + { + if (succeededOrLog(errorCode)) { + if (completionHandler) { + completionHandler(defaultEnvironment_.get()); + } + } + else if (completionHandler) { + defaultEnvironment_ = nullptr; + completionHandler(nullptr); + } + }); + } + WebViewEnvironmentManager::~WebViewEnvironmentManager() { debugLog("dealloc WebViewEnvironmentManager"); webViewEnvironments.clear(); plugin = nullptr; + defaultEnvironment_ = nullptr; + if (hwnd_) { + DestroyWindow(hwnd_); + } } } \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_manager.h b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_manager.h index 59c25b50..a8bc82fa 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_manager.h +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_manager.h @@ -15,6 +15,7 @@ namespace flutter_inappwebview_plugin class WebViewEnvironmentManager : public ChannelDelegate { public: + static inline const wchar_t* CLASS_NAME = L"WebViewEnvironmentManager"; static inline const std::string METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_webview_environment"; const FlutterInappwebviewWindowsPlugin* plugin; @@ -28,6 +29,15 @@ namespace flutter_inappwebview_plugin std::unique_ptr> result); void createWebViewEnvironment(const std::string& id, std::unique_ptr settings, std::unique_ptr> result); + void createOrGetDefaultWebViewEnvironment(const std::function completionHandler); + HWND getHWND() + { + return hwnd_; + } + private: + std::unique_ptr defaultEnvironment_; + WNDCLASS windowClass_ = {}; + HWND hwnd_ = nullptr; }; } #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_ENVIRONMENT_MANAGER_H_ \ No newline at end of file