From 43a79806704c18e20269dfc9403fdc1af293937f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 2 Oct 2024 03:12:49 +0200 Subject: [PATCH] windows: Implemented shouldInterceptRequest, onLoadResourceWithCustomScheme WebView events, platform interface: Added WebViewEnvironment.customSchemeRegistrations parameter for Windows, Added CustomSchemeRegistration type --- flutter_inappwebview/example/lib/main.dart | 9 +-- .../CHANGELOG.md | 6 ++ .../platform_in_app_browser.dart | 2 + .../in_app_webview_settings.g.dart | 1 + .../src/in_app_webview/platform_webview.dart | 2 + .../src/types/custom_scheme_registration.dart | 26 ++++++ .../types/custom_scheme_registration.g.dart | 72 +++++++++++++++++ .../lib/src/types/main.dart | 2 + .../webview_environment_settings.dart | 14 +++- .../webview_environment_settings.g.dart | 16 +++- .../pubspec.yaml | 2 +- flutter_inappwebview_windows/CHANGELOG.md | 5 ++ flutter_inappwebview_windows/pubspec.yaml | 2 +- .../windows/CMakeLists.txt | 18 ++++- .../windows/in_app_webview/in_app_webview.cpp | 79 ++++++++++++++++++- .../windows/in_app_webview/in_app_webview.h | 2 + .../in_app_webview_settings.cpp | 4 +- .../in_app_webview/in_app_webview_settings.h | 2 +- .../webview_channel_delegate.cpp | 40 ++++++++++ .../in_app_webview/webview_channel_delegate.h | 15 ++++ .../types/custom_scheme_registration.cpp | 55 +++++++++++++ .../types/custom_scheme_registration.h | 28 +++++++ .../windows/types/custom_scheme_response.cpp | 62 +++++++++++++++ .../windows/types/custom_scheme_response.h | 26 ++++++ .../windows/types/url_request.h | 2 - .../windows/types/web_resource_request.cpp | 32 ++++++++ .../windows/types/web_resource_request.h | 11 ++- .../windows/types/web_resource_response.cpp | 70 ++++++++++++++-- .../windows/types/web_resource_response.h | 15 +++- .../webview_environment.cpp | 8 ++ .../webview_environment_settings.cpp | 6 +- .../webview_environment_settings.h | 2 + 32 files changed, 607 insertions(+), 29 deletions(-) create mode 100644 flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_registration.dart create mode 100644 flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_registration.g.dart create mode 100644 flutter_inappwebview_windows/windows/types/custom_scheme_registration.cpp create mode 100644 flutter_inappwebview_windows/windows/types/custom_scheme_registration.h create mode 100644 flutter_inappwebview_windows/windows/types/custom_scheme_response.cpp create mode 100644 flutter_inappwebview_windows/windows/types/custom_scheme_response.h diff --git a/flutter_inappwebview/example/lib/main.dart b/flutter_inappwebview/example/lib/main.dart index 544e86225..ebb77618f 100755 --- a/flutter_inappwebview/example/lib/main.dart +++ b/flutter_inappwebview/example/lib/main.dart @@ -25,12 +25,11 @@ Future main() async { if (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows) { final availableVersion = await WebViewEnvironment.getAvailableVersion(); - assert(availableVersion != null, 'Failed to find an installed WebView2 runtime or non-stable Microsoft Edge installation.'); + assert(availableVersion != null, + 'Failed to find an installed WebView2 runtime or non-stable Microsoft Edge installation.'); - webViewEnvironment = await WebViewEnvironment.create(settings: - WebViewEnvironmentSettings( - userDataFolder: 'custom_path' - )); + webViewEnvironment = await WebViewEnvironment.create( + settings: WebViewEnvironmentSettings(userDataFolder: 'custom_path')); } if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { diff --git a/flutter_inappwebview_platform_interface/CHANGELOG.md b/flutter_inappwebview_platform_interface/CHANGELOG.md index 7d4d2ed24..0ae7e77ba 100644 --- a/flutter_inappwebview_platform_interface/CHANGELOG.md +++ b/flutter_inappwebview_platform_interface/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.3.0 + +- Added `WebViewEnvironment.customSchemeRegistrations` parameter for Windows +- Added `CustomSchemeRegistration` type +- Updated docs + ## 1.2.0 - Updated `Uint8List` conversion inside `fromMap` methods 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 febcba258..6c14c7180 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 @@ -698,6 +698,7 @@ abstract class PlatformInAppBrowserEvents { ///- Android native WebView ///- iOS ([Official API - WKURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkurlschemehandler)) ///- MacOS ([Official API - WKURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkurlschemehandler)) + ///- Windows Future? onLoadResourceWithCustomScheme( WebResourceRequest request) { return null; @@ -1149,6 +1150,7 @@ abstract class PlatformInAppBrowserEvents { /// ///**Officially Supported Platforms/Implementations**: ///- Android native WebView ([Official API - WebViewClient.shouldInterceptRequest](https://developer.android.com/reference/android/webkit/WebViewClient#shouldInterceptRequest(android.webkit.WebView,%20android.webkit.WebResourceRequest))) + ///- Windows ([ICoreWebView2.add_WebResourceRequested](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2478.35#add_webresourcerequested)) Future? shouldInterceptRequest( WebResourceRequest request) { return null; diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart index 7a49a8ff4..2a3bfea5c 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart @@ -579,6 +579,7 @@ class InAppWebViewSettings { ///- Android native WebView ///- iOS ///- MacOS + ///- Windows ([Official API - ICoreWebView2ControllerOptions.put_IsInPrivateModeEnabled](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controlleroptions?view=webview2-1.0.2792.45#put_isinprivatemodeenabled)) bool? incognito; ///Sets the initial scale for this WebView. 0 means default. The behavior for the default scale depends on the state of [useWideViewPort] and [loadWithOverviewMode]. diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_webview.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_webview.dart index 8de1e0b76..838911d2d 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_webview.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_webview.dart @@ -229,6 +229,7 @@ class PlatformWebViewCreationParams { ///- Android native WebView ///- iOS ([Official API - WKURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkurlschemehandler)) ///- MacOS ([Official API - WKURLSchemeHandler](https://developer.apple.com/documentation/webkit/wkurlschemehandler)) + ///- Windows ///{@endtemplate} final Future Function( T controller, WebResourceRequest request)? onLoadResourceWithCustomScheme; @@ -745,6 +746,7 @@ class PlatformWebViewCreationParams { /// ///**Officially Supported Platforms/Implementations**: ///- Android native WebView ([Official API - WebViewClient.shouldInterceptRequest](https://developer.android.com/reference/android/webkit/WebViewClient#shouldInterceptRequest(android.webkit.WebView,%20android.webkit.WebResourceRequest))) + ///- Windows ([ICoreWebView2.add_WebResourceRequested](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2478.35#add_webresourcerequested)) ///{@endtemplate} final Future Function( T controller, WebResourceRequest request)? shouldInterceptRequest; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_registration.dart b/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_registration.dart new file mode 100644 index 000000000..46493dbc9 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_registration.dart @@ -0,0 +1,26 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import '../webview_environment/webview_environment_settings.dart'; + +part 'custom_scheme_registration.g.dart'; + +///Class that represents the registration of a custom scheme for [WebViewEnvironmentSettings] method. +@SupportedPlatforms(platforms: [WindowsPlatform()]) +@ExchangeableObject() +class CustomSchemeRegistration_ { + ///The name of the custom scheme to register. + String scheme; + + ///List of origins that are allowed to issue requests with the custom scheme, such as XHRs and subresource requests that have an Origin header. + List? allowedOrigins; + + ///Whether the sites with this scheme will be treated as a Secure Context like an HTTPS site. + ///This flag is only effective when [hasAuthorityComponent] is also set to `true`. `false` by default. + bool? treatAsSecure; + + ///Set this property to `true` if the URIs with this custom scheme will have an authority component (a host for custom schemes). + ///Specifically, if you have a URI of the following form you should set the HasAuthorityComponent value as listed. + bool? hasAuthorityComponent; + + CustomSchemeRegistration_({required this.scheme, this.allowedOrigins, this.treatAsSecure, this.hasAuthorityComponent}); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_registration.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_registration.g.dart new file mode 100644 index 000000000..269915ea9 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_registration.g.dart @@ -0,0 +1,72 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'custom_scheme_registration.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents the registration of a custom scheme for [WebViewEnvironmentSettings] method. +/// +///**Officially Supported Platforms/Implementations**: +///- Windows +class CustomSchemeRegistration { + ///List of origins that are allowed to issue requests with the custom scheme, such as XHRs and subresource requests that have an Origin header. + List? allowedOrigins; + + ///Set this property to `true` if the URIs with this custom scheme will have an authority component (a host for custom schemes). + ///Specifically, if you have a URI of the following form you should set the HasAuthorityComponent value as listed. + bool? hasAuthorityComponent; + + ///The name of the custom scheme to register. + String scheme; + + ///Whether the sites with this scheme will be treated as a Secure Context like an HTTPS site. + ///This flag is only effective when [hasAuthorityComponent] is also set to `true`. `false` by default. + bool? treatAsSecure; + + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + CustomSchemeRegistration( + {this.allowedOrigins, + this.hasAuthorityComponent, + required this.scheme, + this.treatAsSecure}); + + ///Gets a possible [CustomSchemeRegistration] instance from a [Map] value. + static CustomSchemeRegistration? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = CustomSchemeRegistration( + allowedOrigins: map['allowedOrigins'] != null + ? List.from(map['allowedOrigins']!.cast()) + : null, + hasAuthorityComponent: map['hasAuthorityComponent'], + scheme: map['scheme'], + treatAsSecure: map['treatAsSecure'], + ); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "allowedOrigins": allowedOrigins, + "hasAuthorityComponent": hasAuthorityComponent, + "scheme": scheme, + "treatAsSecure": treatAsSecure, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'CustomSchemeRegistration{allowedOrigins: $allowedOrigins, hasAuthorityComponent: $hasAuthorityComponent, scheme: $scheme, treatAsSecure: $treatAsSecure}'; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/main.dart b/flutter_inappwebview_platform_interface/lib/src/types/main.dart index 927193331..199ebfb6a 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/main.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/main.dart @@ -225,4 +225,6 @@ export 'tracing_mode.dart' show TracingMode; export 'tracing_category.dart' show TracingCategory; export 'custom_tabs_post_message_result_type.dart' show CustomTabsPostMessageResultType; +export 'custom_scheme_registration.dart' + show CustomSchemeRegistration; export 'disposable.dart'; 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 51734bf75..244cdeeb9 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 @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'platform_webview_environment.dart'; +import '../types/custom_scheme_registration.dart'; part 'webview_environment_settings.g.dart'; @@ -100,11 +101,22 @@ class WebViewEnvironmentSettings_ { ]) final String? targetCompatibleBrowserVersion; + ///Set the array of custom scheme registrations to be used. + @SupportedPlatforms(platforms: [ + WindowsPlatform( + apiName: + 'ICoreWebView2EnvironmentOptions4.SetCustomSchemeRegistrations', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions4?view=webview2-1.0.2739.15#setcustomschemeregistrations') + ]) + final List? customSchemeRegistrations; + WebViewEnvironmentSettings_( {this.browserExecutableFolder, this.userDataFolder, this.additionalBrowserArguments, this.allowSingleSignOnUsingOSPrimaryAccount, this.language, - this.targetCompatibleBrowserVersion}); + this.targetCompatibleBrowserVersion, + this.customSchemeRegistrations}); } 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 eb62b39fb..322058d8b 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 @@ -50,6 +50,12 @@ class WebViewEnvironmentSettings { ///- 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; + ///Set the array of custom scheme registrations to be used. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - ICoreWebView2EnvironmentOptions4.SetCustomSchemeRegistrations](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions4?view=webview2-1.0.2739.15#setcustomschemeregistrations)) + final List? customSchemeRegistrations; + ///The default display language for WebView. /// ///**Officially Supported Platforms/Implementations**: @@ -88,6 +94,7 @@ class WebViewEnvironmentSettings { {this.additionalBrowserArguments, this.allowSingleSignOnUsingOSPrimaryAccount, this.browserExecutableFolder, + this.customSchemeRegistrations, this.language, this.targetCompatibleBrowserVersion, this.userDataFolder}); @@ -102,6 +109,11 @@ class WebViewEnvironmentSettings { allowSingleSignOnUsingOSPrimaryAccount: map['allowSingleSignOnUsingOSPrimaryAccount'], browserExecutableFolder: map['browserExecutableFolder'], + customSchemeRegistrations: map['customSchemeRegistrations'] != null + ? List.from(map['customSchemeRegistrations'] + .map((e) => CustomSchemeRegistration.fromMap( + e?.cast())!)) + : null, language: map['language'], targetCompatibleBrowserVersion: map['targetCompatibleBrowserVersion'], userDataFolder: map['userDataFolder'], @@ -116,6 +128,8 @@ class WebViewEnvironmentSettings { "allowSingleSignOnUsingOSPrimaryAccount": allowSingleSignOnUsingOSPrimaryAccount, "browserExecutableFolder": browserExecutableFolder, + "customSchemeRegistrations": + customSchemeRegistrations?.map((e) => e.toMap()).toList(), "language": language, "targetCompatibleBrowserVersion": targetCompatibleBrowserVersion, "userDataFolder": userDataFolder, @@ -135,6 +149,6 @@ class WebViewEnvironmentSettings { @override String toString() { - return 'WebViewEnvironmentSettings{additionalBrowserArguments: $additionalBrowserArguments, allowSingleSignOnUsingOSPrimaryAccount: $allowSingleSignOnUsingOSPrimaryAccount, browserExecutableFolder: $browserExecutableFolder, language: $language, targetCompatibleBrowserVersion: $targetCompatibleBrowserVersion, userDataFolder: $userDataFolder}'; + return 'WebViewEnvironmentSettings{additionalBrowserArguments: $additionalBrowserArguments, allowSingleSignOnUsingOSPrimaryAccount: $allowSingleSignOnUsingOSPrimaryAccount, browserExecutableFolder: $browserExecutableFolder, customSchemeRegistrations: $customSchemeRegistrations, language: $language, targetCompatibleBrowserVersion: $targetCompatibleBrowserVersion, userDataFolder: $userDataFolder}'; } } diff --git a/flutter_inappwebview_platform_interface/pubspec.yaml b/flutter_inappwebview_platform_interface/pubspec.yaml index ffce8c177..d256e08f8 100644 --- a/flutter_inappwebview_platform_interface/pubspec.yaml +++ b/flutter_inappwebview_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_platform_interface description: A common platform interface for the flutter_inappwebview plugin. -version: 1.2.0 +version: 1.3.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_platform_interface issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues diff --git a/flutter_inappwebview_windows/CHANGELOG.md b/flutter_inappwebview_windows/CHANGELOG.md index d6efcff2c..1ae159dc5 100644 --- a/flutter_inappwebview_windows/CHANGELOG.md +++ b/flutter_inappwebview_windows/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.5.0 + +- Implemented `shouldInterceptRequest`, `onLoadResourceWithCustomScheme` WebView events +- Updated flutter_inappwebview_platform_interface version to ^1.3.0 + ## 0.4.1 - Implemented `incognito` for `InAppWebViewSettings` diff --git a/flutter_inappwebview_windows/pubspec.yaml b/flutter_inappwebview_windows/pubspec.yaml index 486c44fc6..fc90198b6 100644 --- a/flutter_inappwebview_windows/pubspec.yaml +++ b/flutter_inappwebview_windows/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_windows description: Windows implementation of the flutter_inappwebview plugin. -version: 0.4.1 +version: 0.5.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_windows issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues diff --git a/flutter_inappwebview_windows/windows/CMakeLists.txt b/flutter_inappwebview_windows/windows/CMakeLists.txt index 045437101..adfbbf787 100644 --- a/flutter_inappwebview_windows/windows/CMakeLists.txt +++ b/flutter_inappwebview_windows/windows/CMakeLists.txt @@ -89,6 +89,10 @@ list(APPEND PLUGIN_SOURCES "types/ssl_certificate.h" "types/permission_response.cpp" "types/permission_response.h" + "types/custom_scheme_response.cpp" + "types/custom_scheme_response.h" + "types/custom_scheme_registration.cpp" + "types/custom_scheme_registration.h" "custom_platform_view/custom_platform_view.cc" "custom_platform_view/custom_platform_view.h" "custom_platform_view/texture_bridge.cc" @@ -175,7 +179,19 @@ endif() # Apply a standard set of build settings that are configured in the # application-level CMakeLists.txt. This can be removed for plugins that want # full control over build settings. -apply_standard_settings(${PLUGIN_NAME}) +# apply_standard_settings(${PLUGIN_NAME}) +# +# IMPORTANT: The apply_standard_settings function is not used here because it +# is causing the plugin to fail to compile because of the usage of /WX flag. +# So, creating here a custom function to apply the standard settings without the /WX flag. +function(FLUTTER_INAPPWEBVIEW_WINDOWS_APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() +flutter_inappwebview_windows_apply_standard_settings(${PLUGIN_NAME}) target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Web.WebView2/build/native/Microsoft.Web.WebView2.targets) target_link_libraries(${PLUGIN_NAME} PRIVATE ${CMAKE_BINARY_DIR}/packages/Microsoft.Windows.ImplementationLibrary/build/native/Microsoft.Windows.ImplementationLibrary.targets) 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 2f907f05b..8ef518b03 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 @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "../custom_platform_view/util/composition.desktop.interop.h" @@ -565,7 +564,12 @@ namespace flutter_inappwebview_plugin int httpStatusCode = 0; wil::com_ptr args2; if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2))) && SUCCEEDED(args2->get_HttpStatusCode(&httpStatusCode)) && httpStatusCode >= 400) { - auto webResourceResponse = std::make_unique(httpStatusCode); + auto webResourceResponse = std::make_unique(std::optional{}, + std::optional{}, + httpStatusCode, + std::optional{}, + std::optional>{}, + std::optional>{}); channelDelegate->onReceivedHttpError(std::move(webResourceRequest), std::move(webResourceResponse)); } else if (httpStatusCode < 400) { @@ -820,6 +824,77 @@ namespace flutter_inappwebview_plugin } ).Get(), nullptr)); + failedLog(webView->AddWebResourceRequestedFilter(L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)); + failedLog(webView->add_WebResourceRequested( + Callback( + [this]( + ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args) + { + wil::com_ptr deferral; + wil::com_ptr webResourceRequest; + if (channelDelegate && succeededOrLog(args->get_Request(&webResourceRequest)) && succeededOrLog(args->GetDeferral(&deferral))) { + auto request = std::make_shared(webResourceRequest); + + auto onLoadResourceWithCustomSchemeCallback = [this, deferral, request, args]() + { + if (channelDelegate) { + auto callback = std::make_unique(); + auto defaultBehaviour = [this, deferral, args](const std::optional> response) + { + failedLog(deferral->Complete()); + }; + callback->nonNullSuccess = [this, deferral, args](const std::shared_ptr response) + { + args->put_Response(response->toWebView2Response(webViewEnv)); + failedLog(deferral->Complete()); + return false; + }; + callback->defaultBehaviour = defaultBehaviour; + callback->error = [this, defaultBehaviour](const std::string& error_code, const std::string& error_message, const flutter::EncodableValue* error_details) + { + debugLog(error_code + ", " + error_message); + defaultBehaviour(std::nullopt); + }; + channelDelegate->onLoadResourceWithCustomScheme(request, std::move(callback)); + } + else { + failedLog(deferral->Complete()); + } + }; + + if (settings->useShouldInterceptRequest) { + auto callback = std::make_unique(); + auto defaultBehaviour = [this, deferral, args](const std::optional> response) + { + failedLog(deferral->Complete()); + }; + callback->nonNullSuccess = [this, deferral, args](const std::shared_ptr response) + { + args->put_Response(response->toWebView2Response(webViewEnv)); + failedLog(deferral->Complete()); + return false; + }; + callback->nullSuccess = [this, deferral, args, onLoadResourceWithCustomSchemeCallback]() + { + onLoadResourceWithCustomSchemeCallback(); + return false; + }; + callback->defaultBehaviour = defaultBehaviour; + callback->error = [this, defaultBehaviour](const std::string& error_code, const std::string& error_message, const flutter::EncodableValue* error_details) + { + debugLog(error_code + ", " + error_message); + defaultBehaviour(std::nullopt); + }; + channelDelegate->shouldInterceptRequest(request, std::move(callback)); + } + else { + onLoadResourceWithCustomSchemeCallback(); + } + } + return S_OK; + } + ).Get(), nullptr)); + wil::com_ptr webView2; if (SUCCEEDED(webView->QueryInterface(IID_PPV_ARGS(&webView2)))) { failedLog(webView2->add_DOMContentLoaded( 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 1b1ba1460..6c3c3a73e 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 @@ -21,6 +21,8 @@ #include "user_content_controller.h" #include "webview_channel_delegate.h" +#include + namespace flutter_inappwebview_plugin { class InAppBrowser; diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.cpp b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.cpp index 91e96a22b..387c919d1 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.cpp @@ -17,9 +17,9 @@ namespace flutter_inappwebview_plugin useShouldOverrideUrlLoading = get_fl_map_value(encodableMap, "useShouldOverrideUrlLoading", useShouldOverrideUrlLoading); useOnLoadResource = get_fl_map_value(encodableMap, "useOnLoadResource", useOnLoadResource); useOnDownloadStart = get_fl_map_value(encodableMap, "useOnDownloadStart", useOnDownloadStart); + useShouldInterceptRequest = get_fl_map_value(encodableMap, "useShouldInterceptRequest", useShouldInterceptRequest); userAgent = get_fl_map_value(encodableMap, "userAgent", userAgent); javaScriptEnabled = get_fl_map_value(encodableMap, "javaScriptEnabled", javaScriptEnabled); - resourceCustomSchemes = get_fl_map_value(encodableMap, "resourceCustomSchemes", resourceCustomSchemes); transparentBackground = get_fl_map_value(encodableMap, "transparentBackground", transparentBackground); supportZoom = get_fl_map_value(encodableMap, "supportZoom", supportZoom); isInspectable = get_fl_map_value(encodableMap, "isInspectable", isInspectable); @@ -33,9 +33,9 @@ namespace flutter_inappwebview_plugin {"useShouldOverrideUrlLoading", useShouldOverrideUrlLoading}, {"useOnLoadResource", useOnLoadResource}, {"useOnDownloadStart", useOnDownloadStart}, + {"useShouldInterceptRequest", useShouldInterceptRequest}, {"userAgent", userAgent}, {"javaScriptEnabled", javaScriptEnabled}, - {"resourceCustomSchemes", make_fl_value(resourceCustomSchemes)}, {"transparentBackground", transparentBackground}, {"supportZoom", supportZoom}, {"isInspectable", isInspectable}, diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.h b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.h index 0fe5d6ed0..92c9db08e 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.h @@ -13,9 +13,9 @@ namespace flutter_inappwebview_plugin bool useShouldOverrideUrlLoading = false; bool useOnLoadResource = false; bool useOnDownloadStart = false; + bool useShouldInterceptRequest = false; std::string userAgent; bool javaScriptEnabled = true; - std::vector resourceCustomSchemes; bool transparentBackground = false; bool supportZoom = true; bool isInspectable = true; diff --git a/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.cpp b/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.cpp index 74af60f7e..df6a4bc8a 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.cpp @@ -58,6 +58,22 @@ namespace flutter_inappwebview_plugin }; } + WebViewChannelDelegate::ShouldInterceptRequestCallback::ShouldInterceptRequestCallback() + { + decodeResult = [](const flutter::EncodableValue* value) + { + return value == nullptr || value->IsNull() ? std::optional>{} : std::make_shared(std::get(*value)); + }; + } + + WebViewChannelDelegate::LoadResourceWithCustomSchemeCallback::LoadResourceWithCustomSchemeCallback() + { + decodeResult = [](const flutter::EncodableValue* value) + { + return value == nullptr || value->IsNull() ? std::optional>{} : std::make_shared(std::get(*value)); + }; + } + void WebViewChannelDelegate::HandleMethodCall(const flutter::MethodCall& method_call, std::unique_ptr> result) { @@ -448,6 +464,30 @@ namespace flutter_inappwebview_plugin channel->InvokeMethod("onPermissionRequest", std::move(arguments), std::move(callback)); } + void WebViewChannelDelegate::shouldInterceptRequest(std::shared_ptr request, std::unique_ptr callback) const + { + if (!channel) { + callback->defaultBehaviour(std::nullopt); + return; + } + + auto arguments = std::make_unique(make_fl_value(request->toEncodableMap())); + channel->InvokeMethod("shouldInterceptRequest", std::move(arguments), std::move(callback)); + } + + void WebViewChannelDelegate::onLoadResourceWithCustomScheme(std::shared_ptr request, std::unique_ptr callback) const + { + if (!channel) { + callback->defaultBehaviour(std::nullopt); + return; + } + + auto arguments = std::make_unique(flutter::EncodableMap{ + {"request", request->toEncodableMap()}, + }); + channel->InvokeMethod("onLoadResourceWithCustomScheme", std::move(arguments), std::move(callback)); + } + WebViewChannelDelegate::~WebViewChannelDelegate() { debugLog("dealloc WebViewChannelDelegate"); diff --git a/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.h b/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.h index 576d90117..005e782dd 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.h @@ -7,6 +7,7 @@ #include "../types/base_callback_result.h" #include "../types/channel_delegate.h" #include "../types/create_window_action.h" +#include "../types/custom_scheme_response.h" #include "../types/navigation_action.h" #include "../types/permission_response.h" #include "../types/web_resource_error.h" @@ -48,6 +49,18 @@ namespace flutter_inappwebview_plugin ~PermissionRequestCallback() = default; }; + class ShouldInterceptRequestCallback : public BaseCallbackResult> { + public: + ShouldInterceptRequestCallback(); + ~ShouldInterceptRequestCallback() = default; + }; + + class LoadResourceWithCustomSchemeCallback : public BaseCallbackResult> { + public: + LoadResourceWithCustomSchemeCallback(); + ~LoadResourceWithCustomSchemeCallback() = default; + }; + WebViewChannelDelegate(InAppWebView* webView, flutter::BinaryMessenger* messenger); WebViewChannelDelegate(InAppWebView* webView, flutter::BinaryMessenger* messenger, const std::string& name); ~WebViewChannelDelegate(); @@ -70,6 +83,8 @@ namespace flutter_inappwebview_plugin void onCreateWindow(std::shared_ptr createWindowAction, std::unique_ptr callback) const; void onCloseWindow() const; void onPermissionRequest(const std::string& origin, const std::vector& resources, std::unique_ptr callback) const; + void shouldInterceptRequest(std::shared_ptr request, std::unique_ptr callback) const; + void onLoadResourceWithCustomScheme(std::shared_ptr request, std::unique_ptr callback) const; }; } diff --git a/flutter_inappwebview_windows/windows/types/custom_scheme_registration.cpp b/flutter_inappwebview_windows/windows/types/custom_scheme_registration.cpp new file mode 100644 index 000000000..b3cd295cf --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/custom_scheme_registration.cpp @@ -0,0 +1,55 @@ +#include "../utils/flutter.h" +#include "../utils/strconv.h" +#include "custom_scheme_registration.h" + +namespace flutter_inappwebview_plugin +{ + CustomSchemeRegistration::CustomSchemeRegistration(const std::string& scheme, const std::optional>& allowedOrigins, + const std::optional& treatAsSecure, const std::optional& hasAuthorityComponent) + : scheme(scheme), allowedOrigins(allowedOrigins), treatAsSecure(treatAsSecure), hasAuthorityComponent(hasAuthorityComponent) + {} + + CustomSchemeRegistration::CustomSchemeRegistration(const flutter::EncodableMap& map) + : scheme(get_fl_map_value(map, "scheme")), + allowedOrigins(get_optional_fl_map_value>(map, "allowedOrigins")), + treatAsSecure(get_optional_fl_map_value(map, "treatAsSecure")), + hasAuthorityComponent(get_optional_fl_map_value(map, "hasAuthorityComponent")) + {} + + flutter::EncodableMap CustomSchemeRegistration::toEncodableMap() const + { + return flutter::EncodableMap{ + {"scheme", make_fl_value(scheme)}, + {"allowedOrigins", make_fl_value(allowedOrigins)}, + {"treatAsSecure", make_fl_value(treatAsSecure)}, + {"hasAuthorityComponent", make_fl_value(hasAuthorityComponent)} + }; + } + + CoreWebView2CustomSchemeRegistration* CustomSchemeRegistration::toWebView2CustomSchemeRegistration() const + { + auto customSchemeRegistration = Microsoft::WRL::Make(utf8_to_wide(scheme).c_str()); + + if (allowedOrigins.has_value()) { + std::vector wideAllowedOrigins; + for (const auto& origin : allowedOrigins.value()) { + wideAllowedOrigins.push_back(utf8_to_wide(origin).c_str()); + } + customSchemeRegistration->SetAllowedOrigins( + static_cast(wideAllowedOrigins.size()), + wideAllowedOrigins.data()); + } + + if (treatAsSecure.has_value()) { + customSchemeRegistration->put_TreatAsSecure(treatAsSecure.value()); + } + + if (hasAuthorityComponent.has_value()) { + customSchemeRegistration->put_HasAuthorityComponent(hasAuthorityComponent.value()); + } + + customSchemeRegistration->AddRef(); + return customSchemeRegistration.Get(); + } + +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/custom_scheme_registration.h b/flutter_inappwebview_windows/windows/types/custom_scheme_registration.h new file mode 100644 index 000000000..0d8c9f139 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/custom_scheme_registration.h @@ -0,0 +1,28 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_SCHEME_REGISTRATION_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_SCHEME_REGISTRATION_H_ + +#include +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + class CustomSchemeRegistration + { + public: + const std::string scheme; + const std::optional> allowedOrigins; + const std::optional treatAsSecure; + const std::optional hasAuthorityComponent; + + CustomSchemeRegistration(const std::string& scheme, const std::optional>& allowedOrigins, const std::optional& treatAsSecure, const std::optional& hasAuthorityComponent); + CustomSchemeRegistration(const flutter::EncodableMap& map); + ~CustomSchemeRegistration() = default; + + flutter::EncodableMap toEncodableMap() const; + CoreWebView2CustomSchemeRegistration* toWebView2CustomSchemeRegistration() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_SCHEME_REGISTRATION_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/custom_scheme_response.cpp b/flutter_inappwebview_windows/windows/types/custom_scheme_response.cpp new file mode 100644 index 000000000..848aa3917 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/custom_scheme_response.cpp @@ -0,0 +1,62 @@ +#include "../utils/flutter.h" +#include "../utils/string.h" +#include "custom_scheme_response.h" + +#include + +namespace flutter_inappwebview_plugin +{ + CustomSchemeResponse::CustomSchemeResponse(const std::vector& data, const std::string& contentType, const std::string& contentEncoding) + : data(data), contentType(contentType), contentEncoding(contentEncoding) + {} + + CustomSchemeResponse::CustomSchemeResponse(const flutter::EncodableMap& map) + : data(get_fl_map_value>(map, "data")), + contentType(get_fl_map_value(map, "contentType")), + contentEncoding(get_fl_map_value(map, "contentEncoding")) + {} + + flutter::EncodableMap CustomSchemeResponse::toEncodableMap() const + { + return flutter::EncodableMap{ + {"data", make_fl_value(data)}, + {"contentType", make_fl_value(contentType)}, + {"contentEncoding", make_fl_value(contentEncoding)} + }; + } + + ICoreWebView2WebResourceResponse* CustomSchemeResponse::toWebView2Response(const wil::com_ptr webViewEnvironment) const + { + wil::com_ptr webResourceResponse; + + if (webViewEnvironment) { + wil::com_ptr postDataStream = nullptr; + if (!data.empty()) { + auto postData = std::string(data.begin(), data.end()); + postDataStream = SHCreateMemStream( + reinterpret_cast(postData.data()), static_cast(postData.length())); + } + + webViewEnvironment->CreateWebResourceResponse( + postDataStream.get(), + 200, // Default to 200 + L"OK", // Default to "OK" + nullptr, + &webResourceResponse); + + wil::com_ptr responseHeaders; + if (SUCCEEDED(webResourceResponse->get_Headers(&responseHeaders))) { + if (!contentType.empty()) { + responseHeaders->AppendHeader(L"Content-Type", utf8_to_wide(contentType).c_str()); + } + if (!contentEncoding.empty()) { + responseHeaders->AppendHeader(L"Content-Encoding", utf8_to_wide(contentEncoding).c_str()); + } + } + + webResourceResponse->AddRef(); + } + + return webResourceResponse.get(); + } +} diff --git a/flutter_inappwebview_windows/windows/types/custom_scheme_response.h b/flutter_inappwebview_windows/windows/types/custom_scheme_response.h new file mode 100644 index 000000000..6b98d9095 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/custom_scheme_response.h @@ -0,0 +1,26 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_SCHEME_RESPONSE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_SCHEME_RESPONSE_H_ + +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + class CustomSchemeResponse + { + public: + const std::vector data; + const std::string contentType; + const std::string contentEncoding; + + CustomSchemeResponse(const std::vector& data, const std::string& contentType, const std::string& contentEncoding); + CustomSchemeResponse(const flutter::EncodableMap& map); + ~CustomSchemeResponse() = default; + + flutter::EncodableMap toEncodableMap() const; + ICoreWebView2WebResourceResponse* toWebView2Response(const wil::com_ptr webViewEnvironment) const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_CUSTOM_SCHEME_RESPONSE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/url_request.h b/flutter_inappwebview_windows/windows/types/url_request.h index 37373d1ce..ded69b6e4 100644 --- a/flutter_inappwebview_windows/windows/types/url_request.h +++ b/flutter_inappwebview_windows/windows/types/url_request.h @@ -4,8 +4,6 @@ #include #include -#include "../utils/flutter.h" - namespace flutter_inappwebview_plugin { class URLRequest diff --git a/flutter_inappwebview_windows/windows/types/web_resource_request.cpp b/flutter_inappwebview_windows/windows/types/web_resource_request.cpp index b7074207f..437fa1903 100644 --- a/flutter_inappwebview_windows/windows/types/web_resource_request.cpp +++ b/flutter_inappwebview_windows/windows/types/web_resource_request.cpp @@ -1,4 +1,5 @@ #include "../utils/flutter.h" +#include "../utils/log.h" #include "web_resource_request.h" namespace flutter_inappwebview_plugin @@ -15,6 +16,37 @@ namespace flutter_inappwebview_plugin isForMainFrame(get_optional_fl_map_value(map, "isForMainFrame")) {} + WebResourceRequest::WebResourceRequest(wil::com_ptr webResourceRequest) + { + wil::unique_cotaskmem_string uri; + url = SUCCEEDED(webResourceRequest->get_Uri(&uri)) ? wide_to_utf8(uri.get()) : std::optional{}; + + wil::unique_cotaskmem_string methodStr; + method = SUCCEEDED(webResourceRequest->get_Method(&methodStr)) ? wide_to_utf8(methodStr.get()) : std::optional{}; + + // Get the headers + wil::com_ptr requestHeaders; + if (SUCCEEDED(webResourceRequest->get_Headers(&requestHeaders))) { + std::map headersMap; + wil::com_ptr iterator; + if (SUCCEEDED(requestHeaders->GetIterator(&iterator))) { + BOOL hasCurrent = FALSE; + iterator->get_HasCurrentHeader(&hasCurrent); + while (hasCurrent) { + wil::unique_cotaskmem_string name, value; + iterator->GetCurrentHeader(&name, &value); + headersMap.emplace(wide_to_utf8(name.get()), wide_to_utf8(value.get())); + iterator->MoveNext(&hasCurrent); + } + if (!headersMap.empty()) { + headers = headersMap; + } + } + } + + isForMainFrame = true; + } + flutter::EncodableMap WebResourceRequest::toEncodableMap() const { return flutter::EncodableMap{ diff --git a/flutter_inappwebview_windows/windows/types/web_resource_request.h b/flutter_inappwebview_windows/windows/types/web_resource_request.h index ea9bb5873..39f559a89 100644 --- a/flutter_inappwebview_windows/windows/types/web_resource_request.h +++ b/flutter_inappwebview_windows/windows/types/web_resource_request.h @@ -3,20 +3,23 @@ #include #include +#include +#include namespace flutter_inappwebview_plugin { class WebResourceRequest { public: - const std::optional url; - const std::optional method; - const std::optional> headers; - const std::optional isForMainFrame; + std::optional url; + std::optional method; + std::optional> headers; + std::optional isForMainFrame; WebResourceRequest(const std::optional& url, const std::optional& method, const std::optional>& headers, const std::optional& isForMainFrame); WebResourceRequest(const flutter::EncodableMap& map); + WebResourceRequest(wil::com_ptr webResourceRequest); ~WebResourceRequest() = default; flutter::EncodableMap toEncodableMap() const; diff --git a/flutter_inappwebview_windows/windows/types/web_resource_response.cpp b/flutter_inappwebview_windows/windows/types/web_resource_response.cpp index 2e84cd9eb..bd17832c6 100644 --- a/flutter_inappwebview_windows/windows/types/web_resource_response.cpp +++ b/flutter_inappwebview_windows/windows/types/web_resource_response.cpp @@ -1,20 +1,80 @@ #include "../utils/flutter.h" +#include "../utils/strconv.h" #include "web_resource_response.h" +#include + namespace flutter_inappwebview_plugin { - WebResourceResponse::WebResourceResponse(const std::optional& statusCode) - : statusCode(statusCode) + WebResourceResponse::WebResourceResponse(const std::optional& contentType, + const std::optional& contentEncoding, + const std::optional& statusCode, + const std::optional& reasonPhrase, + const std::optional>& headers, + const std::optional>& data) + : contentType(contentType), contentEncoding(contentEncoding), statusCode(statusCode), + reasonPhrase(reasonPhrase), headers(headers), data(data) {} WebResourceResponse::WebResourceResponse(const flutter::EncodableMap& map) - : statusCode(get_optional_fl_map_value(map, "statusCode")) + : contentType(get_optional_fl_map_value(map, "contentType")), + contentEncoding(get_optional_fl_map_value(map, "contentEncoding")), + statusCode(get_optional_fl_map_value(map, "statusCode")), + reasonPhrase(get_optional_fl_map_value(map, "reasonPhrase")), + headers(get_optional_fl_map_value>(map, "headers")), + data(get_optional_fl_map_value>(map, "data")) {} flutter::EncodableMap WebResourceResponse::toEncodableMap() const { return flutter::EncodableMap{ - {"statusCode", make_fl_value(statusCode)} + {"contentEncoding", make_fl_value(contentEncoding)}, + {"contentType", make_fl_value(contentType)}, + {"statusCode", make_fl_value(statusCode)}, + {"reasonPhrase", make_fl_value(reasonPhrase)}, + {"headers", make_fl_value(headers)}, + {"data", make_fl_value(data)} }; } -} \ No newline at end of file + + ICoreWebView2WebResourceResponse* WebResourceResponse::toWebView2Response(const wil::com_ptr webViewEnvironment) const + { + wil::com_ptr webResourceResponse; + + if (webViewEnvironment) { + wil::com_ptr postDataStream = nullptr; + if (data.has_value()) { + auto postData = std::string(data.value().begin(), data.value().end()); + postDataStream = SHCreateMemStream( + reinterpret_cast(postData.data()), static_cast(postData.length())); + } + + webViewEnvironment->CreateWebResourceResponse( + postDataStream.get(), + statusCode.value_or(200), // Default to 200 if statusCode is not set + reasonPhrase.has_value() ? utf8_to_wide(reasonPhrase.value()).c_str() : L"OK", // Default to "OK" if reasonPhrase is not set + nullptr, + &webResourceResponse); + + wil::com_ptr responseHeaders; + if (SUCCEEDED(webResourceResponse->get_Headers(&responseHeaders))) { + // Set the headers + if (headers.has_value()) { + for (auto const& [key, val] : headers.value()) { + responseHeaders->AppendHeader(utf8_to_wide(key).c_str(), utf8_to_wide(val).c_str()); + } + } + if (contentType.has_value() && !contentType.value().empty()) { + responseHeaders->AppendHeader(L"Content-Type", utf8_to_wide(contentType.value()).c_str()); + } + if (contentEncoding.has_value() && !contentEncoding.value().empty()) { + responseHeaders->AppendHeader(L"Content-Encoding", utf8_to_wide(contentEncoding.value()).c_str()); + } + } + + webResourceResponse->AddRef(); + } + + return webResourceResponse.get(); + } +} diff --git a/flutter_inappwebview_windows/windows/types/web_resource_response.h b/flutter_inappwebview_windows/windows/types/web_resource_response.h index c428e0add..0cc4ed528 100644 --- a/flutter_inappwebview_windows/windows/types/web_resource_response.h +++ b/flutter_inappwebview_windows/windows/types/web_resource_response.h @@ -3,19 +3,32 @@ #include #include +#include +#include namespace flutter_inappwebview_plugin { class WebResourceResponse { public: + const std::optional contentType; + const std::optional contentEncoding; const std::optional statusCode; + const std::optional reasonPhrase; + const std::optional> headers; + const std::optional> data; - WebResourceResponse(const std::optional& statusCode); + WebResourceResponse(const std::optional& contentType, + const std::optional& contentEncoding, + const std::optional& statusCode, + const std::optional& reasonPhrase, + const std::optional>& headers, + const std::optional>& data); WebResourceResponse(const flutter::EncodableMap& map); ~WebResourceResponse() = default; flutter::EncodableMap toEncodableMap() const; + ICoreWebView2WebResourceResponse* WebResourceResponse::toWebView2Response(const wil::com_ptr webViewEnvironment) const; }; } diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp index e8ae3933e..580a1787f 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp @@ -46,6 +46,14 @@ namespace flutter_inappwebview_plugin if (settings->targetCompatibleBrowserVersion.has_value()) { options->put_TargetCompatibleBrowserVersion(utf8_to_wide(settings->targetCompatibleBrowserVersion.value()).c_str()); } + wil::com_ptr options4; + if (succeededOrLog(options->QueryInterface(IID_PPV_ARGS(&options4))) && settings->customSchemeRegistrations.has_value()) { + std::vector registrations = {}; + for (auto& customSchemeRegistration : settings->customSchemeRegistrations.value()) { + registrations.push_back(std::move(customSchemeRegistration->toWebView2CustomSchemeRegistration())); + } + options4->SetCustomSchemeRegistrations(static_cast(registrations.size()), registrations.data()); + } } auto hr = CreateCoreWebView2EnvironmentWithOptions( diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.cpp b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.cpp index 24091a7d2..7667f6003 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.cpp +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.cpp @@ -9,7 +9,8 @@ namespace flutter_inappwebview_plugin additionalBrowserArguments(get_optional_fl_map_value(map, "additionalBrowserArguments")), allowSingleSignOnUsingOSPrimaryAccount(get_optional_fl_map_value(map, "allowSingleSignOnUsingOSPrimaryAccount")), language(get_optional_fl_map_value(map, "language")), - targetCompatibleBrowserVersion(get_optional_fl_map_value(map, "targetCompatibleBrowserVersion")) + targetCompatibleBrowserVersion(get_optional_fl_map_value(map, "targetCompatibleBrowserVersion")), + customSchemeRegistrations(functional_map(get_optional_fl_map_value(map, "customSchemeRegistrations"), [](const flutter::EncodableValue& m) { return std::make_shared(std::get(m)); })) {} flutter::EncodableMap WebViewEnvironmentSettings::toEncodableMap() const @@ -20,7 +21,8 @@ namespace flutter_inappwebview_plugin {"additionalBrowserArguments", make_fl_value(additionalBrowserArguments)}, {"allowSingleSignOnUsingOSPrimaryAccount", make_fl_value(allowSingleSignOnUsingOSPrimaryAccount)}, {"language", make_fl_value(language)}, - {"targetCompatibleBrowserVersion", make_fl_value(targetCompatibleBrowserVersion)} + {"targetCompatibleBrowserVersion", make_fl_value(targetCompatibleBrowserVersion)}, + {"customSchemeRegistrations", make_fl_value(functional_map(customSchemeRegistrations, [](const std::shared_ptr& item) { return item->toEncodableMap(); }))} }; } diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.h b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.h index 12d1388c9..84314aac6 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.h +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.h @@ -6,6 +6,7 @@ #include #include "../flutter_inappwebview_windows_plugin.h" +#include "../types/custom_scheme_registration.h" namespace flutter_inappwebview_plugin { @@ -18,6 +19,7 @@ namespace flutter_inappwebview_plugin const std::optional allowSingleSignOnUsingOSPrimaryAccount; const std::optional language; const std::optional targetCompatibleBrowserVersion; + const std::optional>> customSchemeRegistrations; WebViewEnvironmentSettings() = default; WebViewEnvironmentSettings(const flutter::EncodableMap& map);