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 acf5da2d..6574d899 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 @@ -899,6 +899,7 @@ abstract class PlatformInAppBrowserEvents { ///- Android native WebView ([Official API - WebViewClient.doUpdateVisitedHistory](https://developer.android.com/reference/android/webkit/WebViewClient#doUpdateVisitedHistory(android.webkit.WebView,%20java.lang.String,%20boolean))) ///- iOS ///- MacOS + ///- Windows ([Official API - IWebView2WebView.add_HistoryChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_historychanged)) void onUpdateVisitedHistory(WebUri? url, bool? isReload) {} ///Use [onPrintRequest] instead diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_inappwebview_controller.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_inappwebview_controller.dart index 9bde75a2..1276f2b6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_inappwebview_controller.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/platform_inappwebview_controller.dart @@ -377,6 +377,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///- Android native WebView ([Official API - WebView.canGoBack](https://developer.android.com/reference/android/webkit/WebView#canGoBack())) ///- iOS ([Official API - WKWebView.canGoBack](https://developer.apple.com/documentation/webkit/wkwebview/1414966-cangoback)) ///- MacOS ([Official API - WKWebView.canGoBack](https://developer.apple.com/documentation/webkit/wkwebview/1414966-cangoback)) + ///- Windows ([Official API - IWebView2WebView.get_CanGoBack](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#get_cangoback)) ///{@endtemplate} Future canGoBack() { throw UnimplementedError( @@ -407,6 +408,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///- Android native WebView ([Official API - WebView.canGoForward](https://developer.android.com/reference/android/webkit/WebView#canGoForward())) ///- iOS ([Official API - WKWebView.canGoForward](https://developer.apple.com/documentation/webkit/wkwebview/1414962-cangoforward)) ///- MacOS ([Official API - WKWebView.canGoForward](https://developer.apple.com/documentation/webkit/wkwebview/1414962-cangoforward)) + ///- Windows ([Official API - IWebView2WebView.get_CanGoForward](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#get_cangoforward)) ///{@endtemplate} Future canGoForward() { throw UnimplementedError( @@ -423,6 +425,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///- iOS ([Official API - WKWebView.go](https://developer.apple.com/documentation/webkit/wkwebview/1414991-go)) ///- MacOS ([Official API - WKWebView.go](https://developer.apple.com/documentation/webkit/wkwebview/1414991-go)) ///- Web ([Official API - History.go](https://developer.mozilla.org/en-US/docs/Web/API/History/go)) + ///- Windows ///{@endtemplate} Future goBackOrForward({required int steps}) { throw UnimplementedError( @@ -436,6 +439,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///- Android native WebView ([Official API - WebView.canGoBackOrForward](https://developer.android.com/reference/android/webkit/WebView#canGoBackOrForward(int))) ///- iOS ///- MacOS + ///- Windows ///{@endtemplate} Future canGoBackOrForward({required int steps}) { throw UnimplementedError( @@ -452,6 +456,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///- iOS ///- MacOS ///- Web + ///- Windows ///{@endtemplate} Future goTo({required WebHistoryItem historyItem}) { throw UnimplementedError('goTo is not implemented on the current platform'); @@ -465,6 +470,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///- iOS ///- MacOS ///- Web + ///- Windows ///{@endtemplate} Future isLoading() { throw UnimplementedError( @@ -481,6 +487,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///- iOS ([Official API - WKWebView.stopLoading](https://developer.apple.com/documentation/webkit/wkwebview/1414981-stoploading)) ///- MacOS ([Official API - WKWebView.stopLoading](https://developer.apple.com/documentation/webkit/wkwebview/1414981-stoploading)) ///- Web ([Official API - Window.stop](https://developer.mozilla.org/en-US/docs/Web/API/Window/stop)) + ///- Windows ([Official API - IWebView2WebView.Stop](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#stop)) ///{@endtemplate} Future stopLoading() { throw UnimplementedError( @@ -558,6 +565,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///- iOS ///- MacOS ///- Web + ///- Windows ///{@endtemplate} Future injectJavascriptFileFromAsset( {required String assetFilePath}) { 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 a4d4890d..4949d48b 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 @@ -38,6 +38,7 @@ class PlatformWebViewCreationParams { ///- iOS ///- MacOS ///- Web + ///- Windows ///{@endtemplate} final void Function(T controller)? onWebViewCreated; @@ -54,6 +55,7 @@ class PlatformWebViewCreationParams { ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview)) ///- MacOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview)) ///- Web + ///- Windows ([Official API - IWebView2WebView.add_NavigationStarting](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationstarting)) ///{@endtemplate} final void Function(T controller, WebUri? url)? onLoadStart; @@ -68,6 +70,7 @@ class PlatformWebViewCreationParams { ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview)) ///- MacOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455629-webview)) ///- Web ([Official API - Window.onload](https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event)) + ///- Windows ([Official API - IWebView2WebView.add_NavigationCompleted](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationcompleted)) ///{@endtemplate} final void Function(T controller, WebUri? url)? onLoadStop; @@ -83,6 +86,7 @@ class PlatformWebViewCreationParams { ///- Android native WebView ([Official API - WebViewClient.onReceivedError](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedError(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20android.webkit.WebResourceError))) ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455623-webview)) ///- MacOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455623-webview)) + ///- Windows ([Official API - IWebView2WebView.add_NavigationCompleted](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationcompleted)) ///{@endtemplate} final void Function( T controller, WebResourceRequest request, WebResourceError error)? @@ -107,6 +111,7 @@ class PlatformWebViewCreationParams { ///- Android native WebView ([Official API - WebViewClient.onReceivedHttpError](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedHttpError(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20android.webkit.WebResourceResponse))) ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview)) ///- MacOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview)) + ///- Windows ([Official API - IWebView2WebView.add_NavigationCompleted](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/iwebview2webview?view=webview2-0.8.355#add_navigationcompleted)) ///{@endtemplate} final void Function(T controller, WebResourceRequest request, WebResourceResponse errorResponse)? onReceivedHttpError; @@ -499,6 +504,7 @@ class PlatformWebViewCreationParams { ///- iOS ///- MacOS ///- Web + ///- Windows ([Official API - IWebView2WebView.add_HistoryChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_historychanged)) ///{@endtemplate} final void Function(T controller, WebUri? url, bool? isReload)? onUpdateVisitedHistory; @@ -593,6 +599,7 @@ class PlatformWebViewCreationParams { ///- iOS ///- MacOS ///- Web + ///- Windows ([Official API - IWebView2WebView.add_DocumentTitleChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2210.55#add_documenttitlechanged)) ///{@endtemplate} final void Function(T controller, String? title)? onTitleChanged; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.dart index d2495be5..1d12aa35 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.dart @@ -54,7 +54,8 @@ class NavigationAction_ { available: "21", apiName: "WebResourceRequest.isRedirect", apiUrl: - "https://developer.android.com/reference/android/webkit/WebResourceRequest#isRedirect()") + "https://developer.android.com/reference/android/webkit/WebResourceRequest#isRedirect()"), + WindowsPlatform() ]) bool? isRedirect; @@ -62,7 +63,7 @@ class NavigationAction_ { @Deprecated("Use navigationType instead") IOSWKNavigationType_? iosWKNavigationType; - ///The type of action triggering the navigation.ì + ///The type of action triggering the navigation. @SupportedPlatforms(platforms: [ IOSPlatform( apiName: "WKNavigationAction.navigationType", @@ -71,7 +72,8 @@ class NavigationAction_ { MacOSPlatform( apiName: "WKNavigationAction.navigationType", apiUrl: - "https://developer.apple.com/documentation/webkit/wknavigationaction/1401914-navigationtype") + "https://developer.apple.com/documentation/webkit/wknavigationaction/1401914-navigationtype"), + WindowsPlatform() ]) NavigationType_? navigationType; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.g.dart index 9b24689e..64593a9f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.g.dart @@ -52,13 +52,15 @@ class NavigationAction { /// ///**Officially Supported Platforms/Implementations**: ///- Android native WebView 21+ ([Official API - WebResourceRequest.isRedirect](https://developer.android.com/reference/android/webkit/WebResourceRequest#isRedirect())) + ///- Windows bool? isRedirect; - ///The type of action triggering the navigation.ì + ///The type of action triggering the navigation. /// ///**Officially Supported Platforms/Implementations**: ///- iOS ([Official API - WKNavigationAction.navigationType](https://developer.apple.com/documentation/webkit/wknavigationaction/1401914-navigationtype)) ///- MacOS ([Official API - WKNavigationAction.navigationType](https://developer.apple.com/documentation/webkit/wknavigationaction/1401914-navigationtype)) + ///- Windows NavigationType? navigationType; ///The URL request object associated with the navigation action. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.dart index 72c07c8c..297046fa 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../in_app_webview/platform_webview.dart'; part 'navigation_type.g.dart'; @@ -6,26 +7,119 @@ part 'navigation_type.g.dart'; @ExchangeableEnum() class NavigationType_ { // ignore: unused_field - final int _value; + final String _value; + // ignore: unused_field + final int? _nativeValue = null; + const NavigationType_._internal(this._value); ///A link with an href attribute was activated by the user. - static const LINK_ACTIVATED = const NavigationType_._internal(0); + @EnumSupportedPlatforms(platforms: [ + EnumIOSPlatform( + apiName: 'WKNavigationType.linkActivated', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/linkactivated', + value: 0), + EnumMacOSPlatform( + apiName: 'WKNavigationType.linkActivated', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/linkactivated', + value: 0), + EnumWindowsPlatform( + value: 0 + ), + ]) + static const LINK_ACTIVATED = const NavigationType_._internal('LINK_ACTIVATED'); ///A form was submitted. - static const FORM_SUBMITTED = const NavigationType_._internal(1); + @EnumSupportedPlatforms(platforms: [ + EnumIOSPlatform( + apiName: 'WKNavigationType.formSubmitted', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted', + value: 1), + EnumMacOSPlatform( + apiName: 'WKNavigationType.formSubmitted', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted', + value: 1), + ]) + static const FORM_SUBMITTED = const NavigationType_._internal('FORM_SUBMITTED'); ///An item from the back-forward list was requested. - static const BACK_FORWARD = const NavigationType_._internal(2); + @EnumSupportedPlatforms(platforms: [ + EnumIOSPlatform( + apiName: 'WKNavigationType.formSubmitted', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted', + value: 2), + EnumMacOSPlatform( + apiName: 'WKNavigationType.formSubmitted', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted', + value: 2), + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_NAVIGATION_KIND_BACK_OR_FORWARD', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_navigation_kind', + value: 1 + ), + ]) + static const BACK_FORWARD = const NavigationType_._internal('BACK_FORWARD'); ///The webpage was reloaded. - static const RELOAD = const NavigationType_._internal(3); + @EnumSupportedPlatforms(platforms: [ + EnumIOSPlatform( + apiName: 'WKNavigationType.reload', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/reload', + value: 3), + EnumMacOSPlatform( + apiName: 'WKNavigationType.reload', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/reload', + value: 3), + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_NAVIGATION_KIND_RELOAD', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_navigation_kind', + value: 2 + ), + ]) + static const RELOAD = const NavigationType_._internal('RELOAD'); ///A form was resubmitted (for example by going back, going forward, or reloading). - static const FORM_RESUBMITTED = const NavigationType_._internal(4); + @EnumSupportedPlatforms(platforms: [ + EnumIOSPlatform( + apiName: 'WKNavigationType.formSubmitted', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/formresubmitted', + value: 4), + EnumMacOSPlatform( + apiName: 'WKNavigationType.formSubmitted', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/formresubmitted', + value: 4), + ]) + static const FORM_RESUBMITTED = const NavigationType_._internal('FORM_RESUBMITTED'); ///Navigation is taking place for some other reason. - static const OTHER = const NavigationType_._internal(-1); + @EnumSupportedPlatforms(platforms: [ + EnumIOSPlatform( + apiName: 'WKNavigationType.other', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/other', + value: -1), + EnumMacOSPlatform( + apiName: 'WKNavigationType.other', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wknavigationtype/other', + value: -1), + EnumWindowsPlatform( + value: 3 + ), + ]) + static const OTHER = const NavigationType_._internal('OTHER'); } ///Class that represents the type of action triggering a navigation on iOS for the [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.g.dart index bdf1b525..7615cd66 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.g.dart @@ -8,31 +8,131 @@ part of 'navigation_type.dart'; ///Class that represents the type of action triggering a navigation for the [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event. class NavigationType { - final int _value; - final int _nativeValue; + final String _value; + final int? _nativeValue; const NavigationType._internal(this._value, this._nativeValue); // ignore: unused_element factory NavigationType._internalMultiPlatform( - int value, Function nativeValue) => + String value, Function nativeValue) => NavigationType._internal(value, nativeValue()); ///An item from the back-forward list was requested. - static const BACK_FORWARD = NavigationType._internal(2, 2); + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) + ///- MacOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) + ///- Windows ([Official API - COREWEBVIEW2_NAVIGATION_KIND_BACK_OR_FORWARD](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_navigation_kind)) + static final BACK_FORWARD = + NavigationType._internalMultiPlatform('BACK_FORWARD', () { + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + return 2; + case TargetPlatform.macOS: + return 2; + case TargetPlatform.windows: + return 1; + default: + break; + } + return null; + }); ///A form was resubmitted (for example by going back, going forward, or reloading). - static const FORM_RESUBMITTED = NavigationType._internal(4, 4); + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formresubmitted)) + ///- MacOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formresubmitted)) + static final FORM_RESUBMITTED = + NavigationType._internalMultiPlatform('FORM_RESUBMITTED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + return 4; + case TargetPlatform.macOS: + return 4; + default: + break; + } + return null; + }); ///A form was submitted. - static const FORM_SUBMITTED = NavigationType._internal(1, 1); + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) + ///- MacOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) + static final FORM_SUBMITTED = + NavigationType._internalMultiPlatform('FORM_SUBMITTED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + return 1; + case TargetPlatform.macOS: + return 1; + default: + break; + } + return null; + }); ///A link with an href attribute was activated by the user. - static const LINK_ACTIVATED = NavigationType._internal(0, 0); + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS ([Official API - WKNavigationType.linkActivated](https://developer.apple.com/documentation/webkit/wknavigationtype/linkactivated)) + ///- MacOS ([Official API - WKNavigationType.linkActivated](https://developer.apple.com/documentation/webkit/wknavigationtype/linkactivated)) + ///- Windows + static final LINK_ACTIVATED = + NavigationType._internalMultiPlatform('LINK_ACTIVATED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + return 0; + case TargetPlatform.macOS: + return 0; + case TargetPlatform.windows: + return 0; + default: + break; + } + return null; + }); ///Navigation is taking place for some other reason. - static const OTHER = NavigationType._internal(-1, -1); + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS ([Official API - WKNavigationType.other](https://developer.apple.com/documentation/webkit/wknavigationtype/other)) + ///- MacOS ([Official API - WKNavigationType.other](https://developer.apple.com/documentation/webkit/wknavigationtype/other)) + ///- Windows + static final OTHER = NavigationType._internalMultiPlatform('OTHER', () { + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + return -1; + case TargetPlatform.macOS: + return -1; + case TargetPlatform.windows: + return 3; + default: + break; + } + return null; + }); ///The webpage was reloaded. - static const RELOAD = NavigationType._internal(3, 3); + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS ([Official API - WKNavigationType.reload](https://developer.apple.com/documentation/webkit/wknavigationtype/reload)) + ///- MacOS ([Official API - WKNavigationType.reload](https://developer.apple.com/documentation/webkit/wknavigationtype/reload)) + ///- Windows ([Official API - COREWEBVIEW2_NAVIGATION_KIND_RELOAD](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_navigation_kind)) + static final RELOAD = NavigationType._internalMultiPlatform('RELOAD', () { + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + return 3; + case TargetPlatform.macOS: + return 3; + case TargetPlatform.windows: + return 2; + default: + break; + } + return null; + }); ///Set of all values of [NavigationType]. static final Set values = [ @@ -44,8 +144,8 @@ class NavigationType { NavigationType.RELOAD, ].toSet(); - ///Gets a possible [NavigationType] instance from [int] value. - static NavigationType? fromValue(int? value) { + ///Gets a possible [NavigationType] instance from [String] value. + static NavigationType? fromValue(String? value) { if (value != null) { try { return NavigationType.values @@ -70,11 +170,11 @@ class NavigationType { return null; } - ///Gets [int] value. - int toValue() => _value; + ///Gets [String] value. + String toValue() => _value; - ///Gets [int] native value. - int toNativeValue() => _nativeValue; + ///Gets [int?] native value. + int? toNativeValue() => _nativeValue; @override int get hashCode => _value.hashCode; @@ -84,21 +184,7 @@ class NavigationType { @override String toString() { - switch (_value) { - case 2: - return 'BACK_FORWARD'; - case 4: - return 'FORM_RESUBMITTED'; - case 1: - return 'FORM_SUBMITTED'; - case 0: - return 'LINK_ACTIVATED'; - case -1: - return 'OTHER'; - case 3: - return 'RELOAD'; - } - return _value.toString(); + return _value; } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.dart index 84fc615f..973f85d3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.dart @@ -24,6 +24,12 @@ class WebHistoryItem_ { ///Position offset respect to the currentIndex of the back-forward [WebHistory.list]. int? offset; + ///Unique id of the navigation history entry. + @SupportedPlatforms(platforms: [ + WindowsPlatform() + ]) + int? entryId; + WebHistoryItem_( - {this.originalUrl, this.title, this.url, this.index, this.offset}); + {this.originalUrl, this.title, this.url, this.index, this.offset, this.entryId}); } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.g.dart index 790e503d..bcffea28 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.g.dart @@ -9,6 +9,12 @@ part of 'web_history_item.dart'; ///A convenience class for accessing fields in an entry in the back/forward list of a `WebView`. ///Each [WebHistoryItem] is a snapshot of the requested history item. class WebHistoryItem { + ///Unique id of the navigation history entry. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + int? entryId; + ///0-based position index in the back-forward [WebHistory.list]. int? index; @@ -24,7 +30,12 @@ class WebHistoryItem { ///Url of this history item. WebUri? url; WebHistoryItem( - {this.index, this.offset, this.originalUrl, this.title, this.url}); + {this.entryId, + this.index, + this.offset, + this.originalUrl, + this.title, + this.url}); ///Gets a possible [WebHistoryItem] instance from a [Map] value. static WebHistoryItem? fromMap(Map? map) { @@ -32,6 +43,7 @@ class WebHistoryItem { return null; } final instance = WebHistoryItem( + entryId: map['entryId'], index: map['index'], offset: map['offset'], originalUrl: @@ -45,6 +57,7 @@ class WebHistoryItem { ///Converts instance to a map. Map toMap() { return { + "entryId": entryId, "index": index, "offset": offset, "originalUrl": originalUrl?.toString(), @@ -60,6 +73,6 @@ class WebHistoryItem { @override String toString() { - return 'WebHistoryItem{index: $index, offset: $offset, originalUrl: $originalUrl, title: $title, url: $url}'; + return 'WebHistoryItem{entryId: $entryId, index: $index, offset: $offset, originalUrl: $originalUrl, title: $title, url: $url}'; } } diff --git a/flutter_inappwebview_windows/windows/CMakeLists.txt b/flutter_inappwebview_windows/windows/CMakeLists.txt index 4ccf72af..998a399b 100644 --- a/flutter_inappwebview_windows/windows/CMakeLists.txt +++ b/flutter_inappwebview_windows/windows/CMakeLists.txt @@ -40,7 +40,10 @@ add_custom_command( list(APPEND PLUGIN_SOURCES "flutter_inappwebview_windows_plugin.cpp" "flutter_inappwebview_windows_plugin.h" + "utils/log.h" "utils/strconv.h" + "utils/map.h" + "utils/vector.h" "utils/util.h" "utils/flutter.h" "types/channel_delegate.cpp" @@ -60,6 +63,10 @@ list(APPEND PLUGIN_SOURCES "types/web_history.h" "types/web_history_item.cpp" "types/web_history_item.h" + "types/user_script.cpp" + "types/user_script.h" + "types/plugin_script.cpp" + "types/plugin_script.h" "custom_platform_view/custom_platform_view.cc" "custom_platform_view/custom_platform_view.h" "custom_platform_view/texture_bridge.cc" @@ -73,6 +80,10 @@ list(APPEND PLUGIN_SOURCES "custom_platform_view/util/string_converter.cc" "custom_platform_view/util/string_converter.h" "custom_platform_view/util/swizzle.h" + "plugin_scripts_js/javascript_bridge_js.cpp" + "plugin_scripts_js/javascript_bridge_js.h" + "in_app_webview/user_content_controller.cpp" + "in_app_webview/user_content_controller.h" "in_app_webview/in_app_webview_settings.cpp" "in_app_webview/in_app_webview_settings.h" "in_app_webview/in_app_webview.cpp" diff --git a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc index e8de9cc4..34579e12 100644 --- a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc +++ b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc @@ -1,3 +1,4 @@ +#include "../utils/log.h" #include "custom_platform_view.h" #include diff --git a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser.cpp b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser.cpp index 577db80c..824602a1 100644 --- a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser.cpp +++ b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser.cpp @@ -1,6 +1,7 @@ #include -#include "../utils/util.h" +#include "../utils/log.h" +#include "../utils/strconv.h" #include "in_app_browser.h" #include "in_app_browser_manager.h" diff --git a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_channel_delegate.cpp b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_channel_delegate.cpp index d3bc5961..34aa966e 100644 --- a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_channel_delegate.cpp +++ b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_channel_delegate.cpp @@ -1,4 +1,4 @@ -#include "../utils/util.h" +#include "../utils/log.h" #include "in_app_browser.h" #include "in_app_browser_channel_delegate.h" diff --git a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_manager.cpp b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_manager.cpp index 9086497f..efdd422a 100644 --- a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_manager.cpp +++ b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_manager.cpp @@ -4,6 +4,7 @@ #include "../in_app_webview/in_app_webview_settings.h" #include "../types/url_request.h" #include "../utils/flutter.h" +#include "../utils/log.h" #include "in_app_browser_manager.h" #include "in_app_browser_settings.h" diff --git a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_settings.cpp b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_settings.cpp index 4b5d9594..80f1fa70 100644 --- a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_settings.cpp +++ b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_settings.cpp @@ -1,4 +1,5 @@ #include "../utils/flutter.h" +#include "../utils/log.h" #include "in_app_browser_settings.h" namespace flutter_inappwebview_plugin 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 85f1077f..2d601f4d 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 @@ -5,10 +5,11 @@ #include #include "../custom_platform_view/util/composition.desktop.interop.h" +#include "../plugin_scripts_js/javascript_bridge_js.h" #include "../types/web_resource_error.h" #include "../types/web_resource_request.h" +#include "../utils/log.h" #include "../utils/strconv.h" -#include "../utils/util.h" #include "in_app_webview.h" #include "in_app_webview_manager.h" @@ -19,13 +20,12 @@ namespace flutter_inappwebview_plugin InAppWebView::InAppWebView(const FlutterInappwebviewWindowsPlugin* plugin, const InAppWebViewCreationParams& params, const HWND parentWindow, wil::com_ptr webViewEnv, wil::com_ptr webViewController, wil::com_ptr webViewCompositionController) - : plugin(plugin), id(params.id), webViewEnv(std::move(webViewEnv)), webViewController(std::move(webViewController)), webViewCompositionController(std::move(webViewCompositionController)), - settings(params.initialSettings) + : plugin(plugin), id(params.id), + webViewEnv(std::move(webViewEnv)), webViewController(std::move(webViewController)), webViewCompositionController(std::move(webViewCompositionController)), + settings(params.initialSettings), userContentController(std::make_unique(this)) { - auto hrWebView2 = this->webViewController->get_CoreWebView2(webView.put()); - if (FAILED(hrWebView2)) { + if (failedAndLog(this->webViewController->get_CoreWebView2(webView.put()))) { std::cerr << "Cannot create CoreWebView2." << std::endl; - debugLog(getErrorMessage(hrWebView2)); } if (this->webViewCompositionController) { @@ -41,24 +41,7 @@ namespace flutter_inappwebview_plugin this->webViewController->put_Bounds(bounds); } - wil::com_ptr webView2Settings; - auto hrWebView2Settings = webView->get_Settings(&webView2Settings); - if (SUCCEEDED(hrWebView2Settings)) { - webView2Settings->put_IsScriptEnabled(settings->javaScriptEnabled); - webView2Settings->put_IsZoomControlEnabled(settings->supportZoom); - - wil::com_ptr webView2Settings2; - if (SUCCEEDED(webView2Settings->QueryInterface(IID_PPV_ARGS(&webView2Settings2)))) { - if (!settings->userAgent.empty()) { - webView2Settings2->put_UserAgent(ansi_to_wide(settings->userAgent).c_str()); - } - } - } - else { - debugLog(getErrorMessage(hrWebView2Settings)); - } - - registerEventHandlers(); + prepare(); } InAppWebView::InAppWebView(InAppBrowser* inAppBrowser, const FlutterInappwebviewWindowsPlugin* plugin, const InAppWebViewCreationParams& params, const HWND parentWindow, wil::com_ptr webViewEnv, @@ -73,61 +56,54 @@ namespace flutter_inappwebview_plugin wil::com_ptr webViewController, wil::com_ptr webViewCompositionController)> completionHandler) { - CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr, + failedLog(CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr, Callback( [parentWindow, completionHandler, willBeSurface](HRESULT result, wil::com_ptr env) -> HRESULT { - if (FAILED(result) || !env) { + if (failedAndLog(result) || !env) { completionHandler(nullptr, nullptr, nullptr); - debugLog(getErrorMessage(result)); return E_FAIL; } wil::com_ptr webViewEnv3; - if (willBeSurface && SUCCEEDED(env->QueryInterface(IID_PPV_ARGS(&webViewEnv3)))) { - webViewEnv3->CreateCoreWebView2CompositionController(parentWindow, Callback( + if (willBeSurface && succeededOrLog(env->QueryInterface(IID_PPV_ARGS(&webViewEnv3)))) { + failedLog(webViewEnv3->CreateCoreWebView2CompositionController(parentWindow, Callback( [completionHandler, env](HRESULT result, wil::com_ptr compositionController) -> HRESULT { wil::com_ptr webViewController = compositionController.try_query(); - if (FAILED(result) || !webViewController) { + if (failedAndLog(result) || !webViewController) { completionHandler(nullptr, nullptr, nullptr); - debugLog(getErrorMessage(result)); return E_FAIL; } ICoreWebView2Controller3* webViewController3; - HRESULT hr = webViewController->QueryInterface(IID_PPV_ARGS(&webViewController3)); - if (SUCCEEDED(hr)) { + if (succeededOrLog(webViewController->QueryInterface(IID_PPV_ARGS(&webViewController3)))) { webViewController3->put_BoundsMode(COREWEBVIEW2_BOUNDS_MODE_USE_RAW_PIXELS); webViewController3->put_ShouldDetectMonitorScaleChanges(FALSE); webViewController3->put_RasterizationScale(1.0); } - else { - debugLog(getErrorMessage(hr)); - } completionHandler(std::move(env), std::move(webViewController), std::move(compositionController)); return S_OK; } - ).Get()); + ).Get())); } else { - env->CreateCoreWebView2Controller(parentWindow, Callback( + failedLog(env->CreateCoreWebView2Controller(parentWindow, Callback( [completionHandler, env](HRESULT result, wil::com_ptr controller) -> HRESULT { - if (FAILED(result) || !controller) { + if (failedAndLog(result) || !controller) { completionHandler(nullptr, nullptr, nullptr); - debugLog(getErrorMessage(result)); return E_FAIL; } completionHandler(std::move(env), std::move(controller), nullptr); return S_OK; - }).Get()); + }).Get())); } return S_OK; - }).Get()); + }).Get())); } void InAppWebView::initChannel(const std::optional> viewId, const std::optional channelName) @@ -139,16 +115,43 @@ namespace flutter_inappwebview_plugin std::make_unique(this, plugin->registrar->messenger()); } + void InAppWebView::prepare() + { + if (!webView) { + return; + } + + wil::com_ptr webView2Settings; + auto hrWebView2Settings = webView->get_Settings(&webView2Settings); + if (succeededOrLog(hrWebView2Settings)) { + webView2Settings->put_IsScriptEnabled(settings->javaScriptEnabled); + webView2Settings->put_IsZoomControlEnabled(settings->supportZoom); + + wil::com_ptr webView2Settings2; + if (succeededOrLog(webView2Settings->QueryInterface(IID_PPV_ARGS(&webView2Settings2)))) { + if (!settings->userAgent.empty()) { + webView2Settings2->put_UserAgent(ansi_to_wide(settings->userAgent).c_str()); + } + } + } + + userContentController->addPluginScript(std::move(createJavaScriptBridgePluginScript())); + + registerEventHandlers(); + } + void InAppWebView::registerEventHandlers() { if (!webView) { return; } - webView->add_NavigationStarting( + failedLog(webView->add_NavigationStarting( Callback( [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) { + isLoading_ = true; + if (!channelDelegate) { args->put_Cancel(false); return S_OK; @@ -183,12 +186,52 @@ namespace flutter_inappwebview_plugin std::optional method = requestMethod ? wide_to_utf8(requestMethod.get()) : std::optional{}; + BOOL isUserInitiated; + if (FAILED(args->get_IsUserInitiated(&isUserInitiated))) { + isUserInitiated = FALSE; + } + + BOOL isRedirect; + if (FAILED(args->get_IsRedirected(&isRedirect))) { + isRedirect = FALSE; + } + + std::optional navigationType = std::nullopt; + wil::com_ptr args3; + if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args3)))) { + COREWEBVIEW2_NAVIGATION_KIND navigationKind; + if (SUCCEEDED(args3->get_NavigationKind(&navigationKind))) { + switch (navigationKind) { + case COREWEBVIEW2_NAVIGATION_KIND_RELOAD: + navigationType = NavigationActionType::reload; + break; + case COREWEBVIEW2_NAVIGATION_KIND_BACK_OR_FORWARD: + navigationType = NavigationActionType::backForward; + break; + case COREWEBVIEW2_NAVIGATION_KIND_NEW_DOCUMENT: + if (isUserInitiated && !isRedirect) { + navigationType = NavigationActionType::linkActivated; + } + else { + navigationType = NavigationActionType::other; + } + break; + default: + navigationType = NavigationActionType::other; + } + } + } + auto urlRequest = std::make_shared(url, method, headers, std::nullopt); auto navigationAction = std::make_shared( urlRequest, - true + true, + isRedirect, + navigationType ); + lastNavigationAction_ = navigationAction; + UINT64 navigationId; if (SUCCEEDED(args->get_NavigationId(&navigationId))) { navigationActions.insert({ navigationId, navigationAction }); @@ -202,7 +245,7 @@ namespace flutter_inappwebview_plugin callback->nonNullSuccess = [this, urlRequest](const NavigationActionPolicy actionPolicy) { callShouldOverrideUrlLoading_ = false; - if (actionPolicy == allow) { + if (actionPolicy == NavigationActionPolicy::allow) { loadUrl(*urlRequest); } return false; @@ -229,12 +272,14 @@ namespace flutter_inappwebview_plugin return S_OK; } - ).Get(), nullptr); + ).Get(), nullptr)); - webView->add_NavigationCompleted( + failedLog(webView->add_NavigationCompleted( Callback( [this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) { + isLoading_ = false; + std::shared_ptr navigationAction; UINT64 navigationId; if (SUCCEEDED(args->get_NavigationId(&navigationId))) { @@ -251,8 +296,8 @@ namespace flutter_inappwebview_plugin args->get_IsSuccess(&isSuccess); if (channelDelegate) { - LPWSTR uri = nullptr; - std::optional url = SUCCEEDED(webView->get_Source(&uri)) ? wide_to_utf8(std::wstring(uri)) : std::optional{}; + wil::unique_cotaskmem_string uri; + std::optional url = SUCCEEDED(webView->get_Source(&uri)) ? wide_to_utf8(uri.get()) : std::optional{}; if (isSuccess) { channelDelegate->onLoadStop(url); } @@ -273,9 +318,9 @@ namespace flutter_inappwebview_plugin return S_OK; } - ).Get(), nullptr); + ).Get(), nullptr)); - webView->add_DocumentTitleChanged(Callback( + failedLog(webView->add_DocumentTitleChanged(Callback( [this](ICoreWebView2* sender, IUnknown* args) { if (channelDelegate) { @@ -285,7 +330,36 @@ namespace flutter_inappwebview_plugin } return S_OK; } - ).Get(), nullptr); + ).Get(), nullptr)); + + failedLog(webView->add_HistoryChanged(Callback( + [this](ICoreWebView2* sender, IUnknown* args) + { + if (channelDelegate) { + std::optional isReload = std::nullopt; + if (lastNavigationAction_ && lastNavigationAction_->navigationType.has_value()) { + isReload = lastNavigationAction_->navigationType.value() == NavigationActionType::reload; + } + channelDelegate->onUpdateVisitedHistory(getUrl(), isReload); + } + return S_OK; + } + ).Get(), nullptr)); + + failedLog(webView->add_WebMessageReceived(Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + { + wil::unique_cotaskmem_string uri; + args->get_Source(&uri); + + wil::unique_cotaskmem_string json; + if (succeededOrLog(args->get_WebMessageAsJson(&json))) { + debugLog(json.get()); + } + + return S_OK; + } + ).Get(), nullptr)); } void InAppWebView::registerSurfaceEventHandlers() @@ -294,7 +368,7 @@ namespace flutter_inappwebview_plugin return; } - webViewCompositionController->add_CursorChanged( + failedLog(webViewCompositionController->add_CursorChanged( Callback( [this](ICoreWebView2CompositionController* sender, IUnknown* args) -> HRESULT @@ -306,19 +380,19 @@ namespace flutter_inappwebview_plugin } return S_OK; }) - .Get(), nullptr); + .Get(), nullptr)); } std::optional InAppWebView::getUrl() const { - LPWSTR uri; - return SUCCEEDED(webView->get_Source(&uri)) ? wide_to_utf8(uri) : std::optional{}; + wil::unique_cotaskmem_string uri; + return webView && succeededOrLog(webView->get_Source(&uri)) ? wide_to_utf8(uri.get()) : std::optional{}; } std::optional InAppWebView::getTitle() const { - LPWSTR title; - return SUCCEEDED(webView->get_DocumentTitle(&title)) ? wide_to_utf8(title) : std::optional{}; + wil::unique_cotaskmem_string title; + return webView && succeededOrLog(webView->get_DocumentTitle(&title)) ? wide_to_utf8(title.get()) : std::optional{}; } void InAppWebView::loadUrl(const URLRequest& urlRequest) const @@ -341,59 +415,147 @@ namespace flutter_inappwebview_plugin postDataStream = SHCreateMemStream( reinterpret_cast(postData.data()), static_cast(postData.length())); } - webViewEnv2->CreateWebResourceRequest( + if (succeededOrLog(webViewEnv2->CreateWebResourceRequest( url.c_str(), method.c_str(), postDataStream.get(), L"", &webResourceRequest - ); - wil::com_ptr requestHeaders; - if (SUCCEEDED(webResourceRequest->get_Headers(&requestHeaders))) { - if (method.compare(L"GET") != 0) { - requestHeaders->SetHeader(L"Flutter-InAppWebView-Request-Method", method.c_str()); - } - if (urlRequest.headers.has_value()) { - auto& headers = urlRequest.headers.value(); - for (auto const& [key, val] : headers) { - requestHeaders->SetHeader(ansi_to_wide(key).c_str(), ansi_to_wide(val).c_str()); + ))) { + wil::com_ptr requestHeaders; + if (SUCCEEDED(webResourceRequest->get_Headers(&requestHeaders))) { + if (method.compare(L"GET") != 0) { + requestHeaders->SetHeader(L"Flutter-InAppWebView-Request-Method", method.c_str()); + } + if (urlRequest.headers.has_value()) { + auto& headers = urlRequest.headers.value(); + for (auto const& [key, val] : headers) { + requestHeaders->SetHeader(ansi_to_wide(key).c_str(), ansi_to_wide(val).c_str()); + } } } + failedLog(webView2->NavigateWithWebResourceRequest(webResourceRequest.get())); } - webView2->NavigateWithWebResourceRequest(webResourceRequest.get()); - } - else { - webView->Navigate(url.c_str()); + return; } + failedLog(webView->Navigate(url.c_str())); } void InAppWebView::reload() const { - webView->Reload(); + if (!webView) { + return; + } + + failedLog(webView->Reload()); } void InAppWebView::goBack() { + if (!webView) { + return; + } + callShouldOverrideUrlLoading_ = false; - webView->GoBack(); + failedLog(webView->GoBack()); + } + + bool InAppWebView::canGoBack() const + { + BOOL canGoBack_; + return webView && succeededOrLog(webView->get_CanGoBack(&canGoBack_)) ? canGoBack_ : false; } void InAppWebView::goForward() { + if (!webView) { + return; + } + callShouldOverrideUrlLoading_ = false; - webView->GoForward(); + failedLog(webView->GoForward()); + } + + bool InAppWebView::canGoForward() const + { + BOOL canGoForward_; + return webView && succeededOrLog(webView->get_CanGoForward(&canGoForward_)) ? canGoForward_ : false; + } + + void InAppWebView::goBackOrForward(const int& steps) + { + getCopyBackForwardList( + [this, steps](std::unique_ptr webHistory) + { + if (webHistory && webHistory->currentIndex.has_value() && webHistory->list.has_value()) { + auto currentIndex = webHistory->currentIndex.value(); + auto items = &webHistory->list.value(); + auto nextIndex = currentIndex + steps; + int64_t size = items->size(); + if (nextIndex >= 0 && nextIndex < size) { + auto entryId = items->at(nextIndex)->entryId; + std::cout << "entryId: " + std::to_string(entryId.value()) << "\n"; + if (entryId.has_value()) { + auto oldCallShouldOverrideUrlLoading_ = callShouldOverrideUrlLoading_; + callShouldOverrideUrlLoading_ = false; + if (failedAndLog(webView->CallDevToolsProtocolMethod(L"Page.navigateToHistoryEntry", ansi_to_wide("{\"entryId\": " + std::to_string(entryId.value()) + "}").c_str(), Callback( + [this](HRESULT errorCode, LPCWSTR returnObjectAsJson) + { + failedLog(errorCode); + return S_OK; + } + ).Get()))) { + callShouldOverrideUrlLoading_ = oldCallShouldOverrideUrlLoading_; + } + } + } + } + } + ); + } + + void InAppWebView::canGoBackOrForward(const int& steps, std::function completionHandler) const + { + getCopyBackForwardList( + [steps, completionHandler](std::unique_ptr webHistory) + { + auto canGoBackOrForward_ = false; + if (webHistory && webHistory->currentIndex.has_value() && webHistory->list.has_value()) { + auto currentIndex = webHistory->currentIndex.value(); + auto items = &webHistory->list.value(); + auto nextIndex = currentIndex + steps; + int64_t size = items->size(); + canGoBackOrForward_ = nextIndex >= 0 && nextIndex < size; + } + completionHandler(canGoBackOrForward_); + } + ); + } + + void InAppWebView::stopLoading() const + { + if (!webView) { + return; + } + + failedLog(webView->Stop()); } void InAppWebView::getCopyBackForwardList(const std::function)> completionHandler) const { - webView->CallDevToolsProtocolMethod(L"Page.getNavigationHistory", L"{}", Callback( + if (!webView) { + completionHandler(std::make_unique(std::nullopt, std::nullopt)); + return; + } + + failedLog(webView->CallDevToolsProtocolMethod(L"Page.getNavigationHistory", L"{}", Callback( [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) { if (errorCode == S_OK) { auto historyJson = nlohmann::json::parse(wide_to_ansi(returnObjectAsJson)); int64_t currentIndex = historyJson.at("currentIndex").is_number_unsigned() ? historyJson.at("currentIndex").get() : 0; - auto entries = historyJson.at("entries").is_array() ? historyJson.at("entries").get>() : std::vector{}; + std::vector entries = historyJson.at("entries").is_array() ? historyJson.at("entries").get>() : std::vector{}; std::vector> webHistoryItems; webHistoryItems.reserve(entries.size()); @@ -401,6 +563,7 @@ namespace flutter_inappwebview_plugin for (auto const& entry : entries) { int64_t offset = i - currentIndex; webHistoryItems.push_back(std::make_shared( + entry.at("id").is_number_integer() ? entry.at("id").get() : std::optional{}, i, offset, entry.at("userTypedURL").is_string() ? entry.at("userTypedURL").get() : std::optional{}, @@ -413,26 +576,27 @@ namespace flutter_inappwebview_plugin completionHandler(std::make_unique(currentIndex, webHistoryItems)); } else { - debugLog(getErrorMessage(errorCode)); + debugLog(errorCode); + completionHandler(std::make_unique(std::nullopt, std::nullopt)); } return S_OK; } - ).Get()); + ).Get())); } void InAppWebView::evaluateJavascript(const std::string& source, std::function completionHanlder) const { - webView->ExecuteScript(ansi_to_wide(source).c_str(), + failedLog(webView->ExecuteScript(ansi_to_wide(source).c_str(), Callback( [completionHanlder = std::move(completionHanlder)](HRESULT error, PCWSTR result) -> HRESULT { if (error != S_OK) { - debugLog(getErrorMessage(error)); + debugLog(error); } completionHanlder(wide_to_ansi(result)); return S_OK; - }).Get()); + }).Get())); } // flutter_view 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 0012d1df..fb981452 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 @@ -13,6 +13,7 @@ #include "../types/url_request.h" #include "../types/web_history.h" #include "in_app_webview_settings.h" +#include "user_content_controller.h" #include "webview_channel_delegate.h" namespace flutter_inappwebview_plugin @@ -88,6 +89,7 @@ namespace flutter_inappwebview_plugin std::map> navigationActions = {}; const std::shared_ptr settings; InAppBrowser* inAppBrowser = nullptr; + std::unique_ptr userContentController; InAppWebView(const FlutterInappwebviewWindowsPlugin* plugin, const InAppWebViewCreationParams& params, const HWND parentWindow, wil::com_ptr webViewEnv, @@ -127,12 +129,22 @@ namespace flutter_inappwebview_plugin winrt::com_ptr compositor); void initChannel(const std::optional> viewId, const std::optional channelName); + void prepare(); std::optional getUrl() const; std::optional getTitle() const; void loadUrl(const URLRequest& urlRequest) const; void reload() const; void goBack(); + bool canGoBack() const; void goForward(); + bool canGoForward() const; + void goBackOrForward(const int& steps); + void canGoBackOrForward(const int& steps, std::function completionHandler) const; + bool isLoading() const + { + return isLoading_; + } + void stopLoading() const; void evaluateJavascript(const std::string& source, std::function completionHanlder) const; void getCopyBackForwardList(const std::function)> completionHandler) const; @@ -147,6 +159,9 @@ namespace flutter_inappwebview_plugin VirtualKeyState virtualKeys_; bool callShouldOverrideUrlLoading_ = true; + std::shared_ptr lastNavigationAction_; + bool isLoading_ = false; + void InAppWebView::registerEventHandlers(); void InAppWebView::registerSurfaceEventHandlers(); }; diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp index 408724b3..10f2a0cd 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp @@ -7,6 +7,7 @@ #include "../in_app_webview/in_app_webview_settings.h" #include "../types/url_request.h" #include "../utils/flutter.h" +#include "../utils/log.h" #include "in_app_webview_manager.h" namespace flutter_inappwebview_plugin 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 c66561dc..df3d538e 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 @@ -1,4 +1,5 @@ #include "../utils/flutter.h" +#include "../utils/log.h" #include "in_app_webview_settings.h" namespace flutter_inappwebview_plugin diff --git a/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.cpp b/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.cpp new file mode 100644 index 00000000..eed27040 --- /dev/null +++ b/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.cpp @@ -0,0 +1,121 @@ +#include + +#include "../utils/log.h" +#include "../utils/strconv.h" +#include "../utils/vector.h" +#include "in_app_webview.h" +#include "user_content_controller.h" + +namespace flutter_inappwebview_plugin +{ + using namespace Microsoft::WRL; + + UserContentController::UserContentController(InAppWebView* webView) + : webView_(webView) + {} + + std::vector> UserContentController::getUserOnlyScriptsAt(const UserScriptInjectionTime& injectionTime) const + { + return userOnlyScripts_.at(injectionTime); + } + + void UserContentController::addUserOnlyScript(std::shared_ptr userScript) + { + if (!userScript) { + return; + } + + userOnlyScripts_.at(userScript->injectionTime).push_back(std::move(userScript)); + } + + void UserContentController::addUserOnlyScripts(std::vector> userScripts) + { + for (auto& userScript : userScripts) { + addUserOnlyScript(std::move(userScript)); + } + } + + void UserContentController::removeUserOnlyScript(std::shared_ptr userScript) + { + if (!userScript) { + return; + } + + vector_remove_erase_el(userOnlyScripts_.at(userScript->injectionTime), std::move(userScript)); + } + + void UserContentController::removeUserOnlyScriptAt(const int64_t& index, const UserScriptInjectionTime& injectionTime) + { + auto& vec = userOnlyScripts_.at(injectionTime); + int64_t size = vec.size(); + if (index >= size) { + return; + } + + vec.erase(vec.begin() + index); + } + + void UserContentController::removeAllUserOnlyScripts() + { + userOnlyScripts_.at(UserScriptInjectionTime::atDocumentStart).clear(); + userOnlyScripts_.at(UserScriptInjectionTime::atDocumentEnd).clear(); + } + + std::vector> UserContentController::getPluginScriptsAt(const UserScriptInjectionTime& injectionTime) const + { + return pluginScripts_.at(injectionTime); + } + + void UserContentController::addPluginScript(std::shared_ptr pluginScript) + { + if (!pluginScript || !webView_) { + return; + } + + if (pluginScript->injectionTime == UserScriptInjectionTime::atDocumentStart) { + failedLog(webView_->webView->AddScriptToExecuteOnDocumentCreated(ansi_to_wide(pluginScript->source).c_str(), + Callback( + [pluginScript](HRESULT error, PCWSTR id) -> HRESULT + { + if (succeededOrLog(error)) { + pluginScript->id = id; + } + return S_OK; + }).Get())); + } + + pluginScripts_.at(pluginScript->injectionTime).push_back(std::move(pluginScript)); + } + + void UserContentController::addPluginScripts(std::vector> pluginScripts) + { + for (auto& pluginScript : pluginScripts) { + addPluginScript(std::move(pluginScript)); + } + } + + void UserContentController::removePluginScript(std::shared_ptr pluginScript) + { + if (!pluginScript || !webView_) { + return; + } + + failedLog(webView_->webView->RemoveScriptToExecuteOnDocumentCreated(pluginScript->id.c_str())); + + vector_remove_erase_el(pluginScripts_.at(pluginScript->injectionTime), std::move(pluginScript)); + } + + void UserContentController::removeAllPluginScripts() + { + pluginScripts_.at(UserScriptInjectionTime::atDocumentStart).clear(); + pluginScripts_.at(UserScriptInjectionTime::atDocumentEnd).clear(); + } + + UserContentController::~UserContentController() + { + debugLog("dealloc UserContentController"); + removeAllUserOnlyScripts(); + removeAllPluginScripts(); + webView_ = nullptr; + } +} diff --git a/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.h b/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.h new file mode 100644 index 00000000..1fee5cfa --- /dev/null +++ b/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.h @@ -0,0 +1,45 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_ + +#include +#include + +#include "../types/plugin_script.h" +#include "../types/user_script.h" + +namespace flutter_inappwebview_plugin +{ + class InAppWebView; + + class UserContentController + { + public: + UserContentController(InAppWebView* webView); + ~UserContentController(); + + std::vector> getUserOnlyScriptsAt(const UserScriptInjectionTime& injectionTime) const; + void addUserOnlyScript(std::shared_ptr userScript); + void addUserOnlyScripts(std::vector> userScripts); + void removeUserOnlyScript(std::shared_ptr userScript); + void removeUserOnlyScriptAt(const int64_t& index, const UserScriptInjectionTime& injectionTime); + void removeAllUserOnlyScripts(); + std::vector> getPluginScriptsAt(const UserScriptInjectionTime& injectionTime) const; + void addPluginScript(std::shared_ptr pluginScript); + void addPluginScripts(std::vector> pluginScripts); + void removePluginScript(std::shared_ptr pluginScript); + void removeAllPluginScripts(); + private: + InAppWebView* webView_; + + std::map>> pluginScripts_ = { + {UserScriptInjectionTime::atDocumentStart, {}}, + {UserScriptInjectionTime::atDocumentEnd, {}} + }; + + std::map>> userOnlyScripts_ = { + {UserScriptInjectionTime::atDocumentStart, {}}, + {UserScriptInjectionTime::atDocumentEnd, {}} + }; + }; +} +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_ \ No newline at end of file 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 066a66aa..1b634773 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 @@ -1,6 +1,7 @@ #include "../in_app_browser/in_app_browser.h" #include "../types/base_callback_result.h" #include "../utils/flutter.h" +#include "../utils/log.h" #include "../utils/strconv.h" #include "in_app_webview.h" #include "webview_channel_delegate.h" @@ -20,7 +21,7 @@ namespace flutter_inappwebview_plugin decodeResult = [](const flutter::EncodableValue* value) { if (value->IsNull()) { - return cancel; + return NavigationActionPolicy::cancel; } auto navigationPolicy = std::get(*value); return static_cast(navigationPolicy); @@ -56,10 +57,37 @@ namespace flutter_inappwebview_plugin webView->goBack(); result->Success(true); } + else if (method_call.method_name().compare("canGoBack") == 0) { + result->Success(webView->canGoBack()); + } else if (method_call.method_name().compare("goForward") == 0) { webView->goForward(); result->Success(true); } + else if (method_call.method_name().compare("canGoForward") == 0) { + result->Success(webView->canGoForward()); + } + else if (method_call.method_name().compare("goBackOrForward") == 0) { + auto steps = get_fl_map_value(arguments, "steps"); + webView->goBackOrForward(steps); + result->Success(true); + } + else if (method_call.method_name().compare("canGoBackOrForward") == 0) { + auto result_ = std::shared_ptr>(std::move(result)); + + auto steps = get_fl_map_value(arguments, "steps"); + webView->canGoBackOrForward(steps, [result_ = std::move(result_)](const bool& value) + { + result_->Success(value); + }); + } + else if (method_call.method_name().compare("isLoading") == 0) { + result->Success(webView->isLoading()); + } + else if (method_call.method_name().compare("stopLoading") == 0) { + webView->stopLoading(); + result->Success(true); + } else if (method_call.method_name().compare("evaluateJavascript") == 0) { auto result_ = std::shared_ptr>(std::move(result)); @@ -170,6 +198,19 @@ namespace flutter_inappwebview_plugin } } + void WebViewChannelDelegate::onUpdateVisitedHistory(const std::optional& url, const std::optional& isReload) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(flutter::EncodableMap{ + {"url", make_fl_value(url)}, + {"isReload", make_fl_value(isReload)} + }); + channel->InvokeMethod("onUpdateVisitedHistory", std::move(arguments)); + } + 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 f511a3c6..a3d8905d 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 @@ -42,6 +42,7 @@ namespace flutter_inappwebview_plugin void onReceivedError(std::shared_ptr request, std::shared_ptr error) const; void onReceivedHttpError(std::shared_ptr request, std::shared_ptr error) const; void onTitleChanged(const std::optional& title) const; + void onUpdateVisitedHistory(const std::optional& url, const std::optional& isReload) const; }; } diff --git a/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.cpp b/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.cpp new file mode 100644 index 00000000..ba2c3066 --- /dev/null +++ b/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.cpp @@ -0,0 +1,26 @@ +#include + +#include "javascript_bridge_js.h" + +namespace flutter_inappwebview_plugin +{ + const std::string JAVASCRIPT_BRIDGE_JS_SOURCE = "window." + JAVASCRIPT_BRIDGE_NAME + " = {}; \ + window." + JAVASCRIPT_BRIDGE_NAME + ".callHandler = function() { \ + var _callHandlerID = setTimeout(function() {}); \ + window.chrome.webview.postMessage({ 'internalHandlerName': 'callHandler', 'handlerName': arguments[0], '_callHandlerID' : _callHandlerID, 'args' : JSON.stringify(Array.prototype.slice.call(arguments, 1)) }); \ + return new Promise(function(resolve, reject) { \ + window." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = { resolve: resolve, reject : reject };\ + });\ + };"; + + std::unique_ptr createJavaScriptBridgePluginScript() + { + const std::set allowedOriginRules = { "*" }; + return std::make_unique( + JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME, + JAVASCRIPT_BRIDGE_JS_SOURCE, + UserScriptInjectionTime::atDocumentStart, + allowedOriginRules + ); + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.h b/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.h new file mode 100644 index 00000000..5366bc6e --- /dev/null +++ b/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.h @@ -0,0 +1,17 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_ + +#include +#include + +#include "../types/plugin_script.h" + +namespace flutter_inappwebview_plugin +{ + const std::string JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"; + const std::string JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT"; + + std::unique_ptr createJavaScriptBridgePluginScript(); +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/navigation_action.cpp b/flutter_inappwebview_windows/windows/types/navigation_action.cpp index 4e499490..543553e7 100644 --- a/flutter_inappwebview_windows/windows/types/navigation_action.cpp +++ b/flutter_inappwebview_windows/windows/types/navigation_action.cpp @@ -3,15 +3,19 @@ namespace flutter_inappwebview_plugin { - NavigationAction::NavigationAction(std::shared_ptr request, const bool& isForMainFrame) - : request(std::move(request)), isForMainFrame(isForMainFrame) + NavigationAction::NavigationAction(std::shared_ptr request, const bool& isForMainFrame, + const std::optional& isRedirect, const std::optional& navigationType) + : request(std::move(request)), isForMainFrame(isForMainFrame), + isRedirect(isRedirect), navigationType(navigationType) {} flutter::EncodableMap NavigationAction::toEncodableMap() const { return flutter::EncodableMap{ {"request", request->toEncodableMap()}, - {"isForMainFrame", make_fl_value(isForMainFrame)} + {"isForMainFrame", isForMainFrame}, + {"isRedirect", make_fl_value(isRedirect)}, + {"navigationType", make_fl_value(navigationType)} }; } } \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/navigation_action.h b/flutter_inappwebview_windows/windows/types/navigation_action.h index ae100e63..886640be 100644 --- a/flutter_inappwebview_windows/windows/types/navigation_action.h +++ b/flutter_inappwebview_windows/windows/types/navigation_action.h @@ -8,13 +8,22 @@ namespace flutter_inappwebview_plugin { + enum NavigationActionType { + linkActivated = 0, + backForward, + reload, + other + }; + class NavigationAction { public: const std::shared_ptr request; const bool isForMainFrame; + const std::optional isRedirect; + const std::optional navigationType; - NavigationAction(std::shared_ptr request, const bool& isForMainFrame); + NavigationAction(std::shared_ptr request, const bool& isForMainFrame, const std::optional& isRedirect, const std::optional& navigationType); ~NavigationAction() = default; flutter::EncodableMap toEncodableMap() const; diff --git a/flutter_inappwebview_windows/windows/types/plugin_script.cpp b/flutter_inappwebview_windows/windows/types/plugin_script.cpp new file mode 100644 index 00000000..adc7d3f8 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/plugin_script.cpp @@ -0,0 +1,14 @@ +#include "plugin_script.h" + +namespace flutter_inappwebview_plugin +{ + PluginScript::PluginScript( + const std::optional& groupName, + const std::string& source, + const UserScriptInjectionTime& injectionTime, + const std::set& allowedOriginRules + ) : UserScript(groupName, source, injectionTime, allowedOriginRules) + {} + + PluginScript::~PluginScript() {} +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/plugin_script.h b/flutter_inappwebview_windows/windows/types/plugin_script.h new file mode 100644 index 00000000..b2fde408 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/plugin_script.h @@ -0,0 +1,21 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_SCRIPT_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_SCRIPT_H_ + +#include "user_script.h" + +namespace flutter_inappwebview_plugin +{ + class PluginScript : public UserScript + { + public: + + PluginScript( + const std::optional& groupName, + const std::string& source, + const UserScriptInjectionTime& injectionTime, + const std::set& allowedOriginRules + ); + ~PluginScript(); + }; +} +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_SCRIPT_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/user_script.cpp b/flutter_inappwebview_windows/windows/types/user_script.cpp new file mode 100644 index 00000000..3e5f39db --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/user_script.cpp @@ -0,0 +1,15 @@ +#include "user_script.h" + +namespace flutter_inappwebview_plugin +{ + UserScript::UserScript( + const std::optional& groupName, + const std::string& source, + const UserScriptInjectionTime& injectionTime, + const std::set& allowedOriginRules + ) : groupName(groupName), source(source), injectionTime(injectionTime), allowedOriginRules(allowedOriginRules) + {} + + UserScript::~UserScript() + {} +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/user_script.h b/flutter_inappwebview_windows/windows/types/user_script.h new file mode 100644 index 00000000..e6c79166 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/user_script.h @@ -0,0 +1,33 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_USER_SCRIPT_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_USER_SCRIPT_H_ + +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + enum UserScriptInjectionTime { + atDocumentStart, + atDocumentEnd + }; + + class UserScript + { + public: + std::wstring id; + const std::optional groupName; + const std::string source; + const UserScriptInjectionTime injectionTime; + const std::set allowedOriginRules; + + UserScript( + const std::optional& groupName, + const std::string& source, + const UserScriptInjectionTime& injectionTime, + const std::set& allowedOriginRules + ); + ~UserScript(); + }; +} +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_USER_SCRIPT_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/web_history_item.cpp b/flutter_inappwebview_windows/windows/types/web_history_item.cpp index bc222022..11350eeb 100644 --- a/flutter_inappwebview_windows/windows/types/web_history_item.cpp +++ b/flutter_inappwebview_windows/windows/types/web_history_item.cpp @@ -2,14 +2,15 @@ namespace flutter_inappwebview_plugin { - WebHistoryItem::WebHistoryItem(const std::optional& index, const std::optional& offset, + WebHistoryItem::WebHistoryItem(const std::optional& entryId, const std::optional& index, const std::optional& offset, const std::optional& originalUrl, const std::optional& title, const std::optional& url) - : index(index), offset(offset), originalUrl(originalUrl), title(title), url(url) + : entryId(entryId), index(index), offset(offset), originalUrl(originalUrl), title(title), url(url) {} WebHistoryItem::WebHistoryItem(const flutter::EncodableMap& map) - : index(get_optional_fl_map_value(map, "index")), + : entryId(get_optional_fl_map_value(map, "entryId")), + index(get_optional_fl_map_value(map, "index")), offset(get_optional_fl_map_value(map, "offset")), originalUrl(get_optional_fl_map_value(map, "originalUrl")), title(get_optional_fl_map_value(map, "title")), @@ -19,6 +20,7 @@ namespace flutter_inappwebview_plugin flutter::EncodableMap WebHistoryItem::toEncodableMap() const { return flutter::EncodableMap{ + {"entryId", make_fl_value(entryId)}, {"index", make_fl_value(index)}, {"offset", make_fl_value(offset)}, {"originalUrl", make_fl_value(originalUrl)}, diff --git a/flutter_inappwebview_windows/windows/types/web_history_item.h b/flutter_inappwebview_windows/windows/types/web_history_item.h index 8e63c1b7..e58181e3 100644 --- a/flutter_inappwebview_windows/windows/types/web_history_item.h +++ b/flutter_inappwebview_windows/windows/types/web_history_item.h @@ -11,13 +11,14 @@ namespace flutter_inappwebview_plugin class WebHistoryItem { public: + const std::optional entryId; const std::optional index; const std::optional offset; const std::optional originalUrl; const std::optional title; const std::optional url; - WebHistoryItem(const std::optional& index, const std::optional& offset, + WebHistoryItem(const std::optional& entryId, const std::optional& index, const std::optional& offset, const std::optional& originalUrl, const std::optional& title, const std::optional& url); WebHistoryItem(const flutter::EncodableMap& map); diff --git a/flutter_inappwebview_windows/windows/utils/flutter.h b/flutter_inappwebview_windows/windows/utils/flutter.h index 517a0075..6447b866 100644 --- a/flutter_inappwebview_windows/windows/utils/flutter.h +++ b/flutter_inappwebview_windows/windows/utils/flutter.h @@ -3,7 +3,9 @@ #include +#include "map.h" #include "util.h" +#include "vector.h" namespace flutter_inappwebview_plugin { diff --git a/flutter_inappwebview_windows/windows/utils/log.h b/flutter_inappwebview_windows/windows/utils/log.h new file mode 100644 index 00000000..c410164a --- /dev/null +++ b/flutter_inappwebview_windows/windows/utils/log.h @@ -0,0 +1,67 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_UTIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_UTIL_H_ + +#include +#include +#include + +#include "strconv.h" + +namespace flutter_inappwebview_plugin +{ + static inline void debugLog(const std::string& msg, const bool& isError = false) + { +#ifndef NDEBUG + if (isError) { + std::cerr << msg << std::endl; + } + else { + std::cout << msg << std::endl; + } + OutputDebugString(ansi_to_wide(msg + "\n").c_str()); +#endif + } + + static inline void debugLog(const std::wstring& msg, const bool& isError = false) + { + debugLog(wide_to_ansi(msg), isError); + } + + static inline std::string getHRMessage(const HRESULT& error) + { + return wide_to_ansi(_com_error(error).ErrorMessage()); + } + + static inline void debugLog(const HRESULT& hr) + { + auto isError = hr != S_OK; + debugLog((isError ? "Error: " : "Message: ") + getHRMessage(hr), isError); + } + + static inline bool succeededOrLog(const HRESULT& hr) + { + if (SUCCEEDED(hr)) { + return true; + } + debugLog(hr); + return false; + } + + static inline bool failedAndLog(const HRESULT& hr) + { + if (FAILED(hr)) { + debugLog(hr); + return true; + } + return false; + } + + static inline void failedLog(const HRESULT& hr) + { + if (FAILED(hr)) { + debugLog(hr); + } + } +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_UTIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/utils/map.h b/flutter_inappwebview_windows/windows/utils/map.h new file mode 100644 index 00000000..3a432d9f --- /dev/null +++ b/flutter_inappwebview_windows/windows/utils/map.h @@ -0,0 +1,71 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_MAP_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_MAP_H_ + +#include +#include +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + template + struct is_mappish_impl : std::false_type { }; + + template + struct is_mappish_impl()[std::declval()])>> + : std::true_type { }; + + template + struct is_mappish : is_mappish_impl::type { }; + + template + static inline bool map_contains(const std::map& map, const K& key) + { + return map.find(key) != map.end(); + } + + template + static inline T map_at_or_null(const std::map& map, const K& key) + { + auto itr = map.find(key); + return itr != map.end() ? itr->second : nullptr; + } + + template + static inline auto functional_map(Iterator begin, Iterator end, Func&& func) -> + std::vector()))> + { + using value_type = decltype(func(std::declval())); + + std::vector out_vector; + out_vector.reserve(std::distance(begin, end)); + + std::transform(begin, end, std::back_inserter(out_vector), + std::forward(func)); + + return out_vector; + } + + template + static inline auto functional_map(const T& iterable, Func&& func) -> + std::vector()))> + { + return functional_map(std::begin(iterable), std::end(iterable), + std::forward(func)); + } + + template + static inline auto functional_map(const std::optional& iterable, Func&& func) -> + std::vector()))> + { + if (!iterable.has_value()) { + return {}; + } + return functional_map(iterable.value(), std::forward(func)); + } +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_MAP_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/utils/util.h b/flutter_inappwebview_windows/windows/utils/util.h index b4820d5c..982e404a 100644 --- a/flutter_inappwebview_windows/windows/utils/util.h +++ b/flutter_inappwebview_windows/windows/utils/util.h @@ -1,60 +1,12 @@ #ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_ #define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_ -#include -#include -#include -#include #include #include #include -#include "strconv.h" - namespace flutter_inappwebview_plugin { - template - struct is_vector_impl : std::false_type { }; - - template - struct is_mappish_impl : std::false_type { }; - - template - struct is_vector_impl>::value> - > : std::true_type { }; - - template - struct is_vector_impl::value_type>::iterator>::value> - > : std::true_type { }; - - template - struct is_mappish_impl()[std::declval()])>> - : std::true_type { }; - - template - struct is_mappish : is_mappish_impl::type { }; - - template - struct is_vector : is_vector_impl::type { }; - - static inline void debugLog(const std::string& msg) - { -#ifndef NDEBUG - std::cout << msg << std::endl; - OutputDebugString(ansi_to_wide(msg + "\n").c_str()); -#endif - } - - static inline std::string getErrorMessage(const HRESULT& error) - { - _com_error err(error); - return wide_to_ansi(err.ErrorMessage()); - } - template static inline std::optional make_pointer_optional(const T* value) { @@ -74,52 +26,6 @@ namespace flutter_inappwebview_plugin static_assert(always_false_v, "non-exhaustive visitor!"); }, var); } - - template - static inline bool map_contains(const std::map& map, const K& key) - { - return map.find(key) != map.end(); - } - - template - static inline T map_at_or_null(const std::map& map, const K& key) - { - auto itr = map.find(key); - return itr != map.end() ? itr->second : nullptr; - } - - template - static inline auto functional_map(Iterator begin, Iterator end, Func&& func) -> - std::vector()))> - { - using value_type = decltype(func(std::declval())); - - std::vector out_vector; - out_vector.reserve(std::distance(begin, end)); - - std::transform(begin, end, std::back_inserter(out_vector), - std::forward(func)); - - return out_vector; - } - - template - static inline auto functional_map(const T& iterable, Func&& func) -> - std::vector()))> - { - return functional_map(std::begin(iterable), std::end(iterable), - std::forward(func)); - } - - template - static inline auto functional_map(const std::optional& iterable, Func&& func) -> - std::vector()))> - { - if (!iterable.has_value()) { - return {}; - } - return functional_map(iterable.value(), std::forward(func)); - } } #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/utils/vector.h b/flutter_inappwebview_windows/windows/utils/vector.h new file mode 100644 index 00000000..5ba8558b --- /dev/null +++ b/flutter_inappwebview_windows/windows/utils/vector.h @@ -0,0 +1,41 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_VECTOR_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_VECTOR_H_ + +#include +#include +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + template + struct is_vector_impl : std::false_type { }; + + template + struct is_vector_impl>::value> + > : std::true_type { }; + + template + struct is_vector_impl::value_type>::iterator>::value> + > : std::true_type { }; + + template + struct is_vector : is_vector_impl::type { }; + + template + static inline void vector_remove_el(std::vector& vec, const T& el) + { + std::remove(vec.begin(), vec.end(), el); + } + + template + static inline void vector_remove_erase_el(std::vector& vec, const T& el) + { + vec.erase(std::remove(vec.begin(), vec.end(), el), vec.end()); + } +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_VECTOR_H_ \ No newline at end of file