windows: implemented some other methods and events, initial implementation work for UserScripts and JavaScript handlers

This commit is contained in:
unknown 2024-01-19 01:55:55 +01:00
parent a8e960c4d0
commit 9a5dae03ba
38 changed files with 1084 additions and 232 deletions

View File

@ -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

View File

@ -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<bool> 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<bool> 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<void> 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<bool> canGoBackOrForward({required int steps}) {
throw UnimplementedError(
@ -452,6 +456,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface
///- iOS
///- MacOS
///- Web
///- Windows
///{@endtemplate}
Future<void> 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<bool> 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<void> stopLoading() {
throw UnimplementedError(
@ -558,6 +565,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface
///- iOS
///- MacOS
///- Web
///- Windows
///{@endtemplate}
Future<dynamic> injectJavascriptFileFromAsset(
{required String assetFilePath}) {

View File

@ -38,6 +38,7 @@ class PlatformWebViewCreationParams<T> {
///- iOS
///- MacOS
///- Web
///- Windows
///{@endtemplate}
final void Function(T controller)? onWebViewCreated;
@ -54,6 +55,7 @@ class PlatformWebViewCreationParams<T> {
///- 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<T> {
///- 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<T> {
///- 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<T> {
///- 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<T> {
///- 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<T> {
///- 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;

View File

@ -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;

View File

@ -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.

View File

@ -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.

View File

@ -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<NavigationType> 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;
}
}

View File

@ -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});
}

View File

@ -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<String, dynamic>? 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<String, dynamic> 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}';
}
}

View File

@ -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"

View File

@ -1,3 +1,4 @@
#include "../utils/log.h"
#include "custom_platform_view.h"
#include <flutter/event_stream_handler_functions.h>

View File

@ -1,6 +1,7 @@
#include <Windows.h>
#include "../utils/util.h"
#include "../utils/log.h"
#include "../utils/strconv.h"
#include "in_app_browser.h"
#include "in_app_browser_manager.h"

View File

@ -1,4 +1,4 @@
#include "../utils/util.h"
#include "../utils/log.h"
#include "in_app_browser.h"
#include "in_app_browser_channel_delegate.h"

View File

@ -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"

View File

@ -1,4 +1,5 @@
#include "../utils/flutter.h"
#include "../utils/log.h"
#include "in_app_browser_settings.h"
namespace flutter_inappwebview_plugin

View File

@ -5,10 +5,11 @@
#include <wil/wrl.h>
#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<ICoreWebView2Environment> webViewEnv,
wil::com_ptr<ICoreWebView2Controller> webViewController,
wil::com_ptr<ICoreWebView2CompositionController> 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<UserContentController>(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<ICoreWebView2Settings> webView2Settings;
auto hrWebView2Settings = webView->get_Settings(&webView2Settings);
if (SUCCEEDED(hrWebView2Settings)) {
webView2Settings->put_IsScriptEnabled(settings->javaScriptEnabled);
webView2Settings->put_IsZoomControlEnabled(settings->supportZoom);
wil::com_ptr<ICoreWebView2Settings2> 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<ICoreWebView2Environment> webViewEnv,
@ -73,61 +56,54 @@ namespace flutter_inappwebview_plugin
wil::com_ptr<ICoreWebView2Controller> webViewController,
wil::com_ptr<ICoreWebView2CompositionController> webViewCompositionController)> completionHandler)
{
CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,
failedLog(CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,
Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
[parentWindow, completionHandler, willBeSurface](HRESULT result, wil::com_ptr<ICoreWebView2Environment> env) -> HRESULT
{
if (FAILED(result) || !env) {
if (failedAndLog(result) || !env) {
completionHandler(nullptr, nullptr, nullptr);
debugLog(getErrorMessage(result));
return E_FAIL;
}
wil::com_ptr<ICoreWebView2Environment3> webViewEnv3;
if (willBeSurface && SUCCEEDED(env->QueryInterface(IID_PPV_ARGS(&webViewEnv3)))) {
webViewEnv3->CreateCoreWebView2CompositionController(parentWindow, Callback<ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler>(
if (willBeSurface && succeededOrLog(env->QueryInterface(IID_PPV_ARGS(&webViewEnv3)))) {
failedLog(webViewEnv3->CreateCoreWebView2CompositionController(parentWindow, Callback<ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler>(
[completionHandler, env](HRESULT result, wil::com_ptr<ICoreWebView2CompositionController> compositionController) -> HRESULT
{
wil::com_ptr<ICoreWebView2Controller3> webViewController = compositionController.try_query<ICoreWebView2Controller3>();
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<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
failedLog(env->CreateCoreWebView2Controller(parentWindow, Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
[completionHandler, env](HRESULT result, wil::com_ptr<ICoreWebView2Controller> 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<std::variant<std::string, int64_t>> viewId, const std::optional<std::string> channelName)
@ -139,16 +115,43 @@ namespace flutter_inappwebview_plugin
std::make_unique<WebViewChannelDelegate>(this, plugin->registrar->messenger());
}
void InAppWebView::prepare()
{
if (!webView) {
return;
}
wil::com_ptr<ICoreWebView2Settings> webView2Settings;
auto hrWebView2Settings = webView->get_Settings(&webView2Settings);
if (succeededOrLog(hrWebView2Settings)) {
webView2Settings->put_IsScriptEnabled(settings->javaScriptEnabled);
webView2Settings->put_IsZoomControlEnabled(settings->supportZoom);
wil::com_ptr<ICoreWebView2Settings2> 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<ICoreWebView2NavigationStartingEventHandler>(
[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<std::string> method = requestMethod ? wide_to_utf8(requestMethod.get()) : std::optional<std::string>{};
BOOL isUserInitiated;
if (FAILED(args->get_IsUserInitiated(&isUserInitiated))) {
isUserInitiated = FALSE;
}
BOOL isRedirect;
if (FAILED(args->get_IsRedirected(&isRedirect))) {
isRedirect = FALSE;
}
std::optional<NavigationActionType> navigationType = std::nullopt;
wil::com_ptr<ICoreWebView2NavigationStartingEventArgs3> 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<URLRequest>(url, method, headers, std::nullopt);
auto navigationAction = std::make_shared<NavigationAction>(
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<ICoreWebView2NavigationCompletedEventHandler>(
[this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args)
{
isLoading_ = false;
std::shared_ptr<NavigationAction> 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<std::string> url = SUCCEEDED(webView->get_Source(&uri)) ? wide_to_utf8(std::wstring(uri)) : std::optional<std::string>{};
wil::unique_cotaskmem_string uri;
std::optional<std::string> url = SUCCEEDED(webView->get_Source(&uri)) ? wide_to_utf8(uri.get()) : std::optional<std::string>{};
if (isSuccess) {
channelDelegate->onLoadStop(url);
}
@ -273,9 +318,9 @@ namespace flutter_inappwebview_plugin
return S_OK;
}
).Get(), nullptr);
).Get(), nullptr));
webView->add_DocumentTitleChanged(Callback<ICoreWebView2DocumentTitleChangedEventHandler>(
failedLog(webView->add_DocumentTitleChanged(Callback<ICoreWebView2DocumentTitleChangedEventHandler>(
[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<ICoreWebView2HistoryChangedEventHandler>(
[this](ICoreWebView2* sender, IUnknown* args)
{
if (channelDelegate) {
std::optional<bool> 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<ICoreWebView2WebMessageReceivedEventHandler>(
[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<ICoreWebView2CursorChangedEventHandler>(
[this](ICoreWebView2CompositionController* sender,
IUnknown* args) -> HRESULT
@ -306,19 +380,19 @@ namespace flutter_inappwebview_plugin
}
return S_OK;
})
.Get(), nullptr);
.Get(), nullptr));
}
std::optional<std::string> InAppWebView::getUrl() const
{
LPWSTR uri;
return SUCCEEDED(webView->get_Source(&uri)) ? wide_to_utf8(uri) : std::optional<std::string>{};
wil::unique_cotaskmem_string uri;
return webView && succeededOrLog(webView->get_Source(&uri)) ? wide_to_utf8(uri.get()) : std::optional<std::string>{};
}
std::optional<std::string> InAppWebView::getTitle() const
{
LPWSTR title;
return SUCCEEDED(webView->get_DocumentTitle(&title)) ? wide_to_utf8(title) : std::optional<std::string>{};
wil::unique_cotaskmem_string title;
return webView && succeededOrLog(webView->get_DocumentTitle(&title)) ? wide_to_utf8(title.get()) : std::optional<std::string>{};
}
void InAppWebView::loadUrl(const URLRequest& urlRequest) const
@ -341,59 +415,147 @@ namespace flutter_inappwebview_plugin
postDataStream = SHCreateMemStream(
reinterpret_cast<const BYTE*>(postData.data()), static_cast<UINT>(postData.length()));
}
webViewEnv2->CreateWebResourceRequest(
if (succeededOrLog(webViewEnv2->CreateWebResourceRequest(
url.c_str(),
method.c_str(),
postDataStream.get(),
L"",
&webResourceRequest
);
wil::com_ptr<ICoreWebView2HttpRequestHeaders> 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<ICoreWebView2HttpRequestHeaders> 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> 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<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
[this](HRESULT errorCode, LPCWSTR returnObjectAsJson)
{
failedLog(errorCode);
return S_OK;
}
).Get()))) {
callShouldOverrideUrlLoading_ = oldCallShouldOverrideUrlLoading_;
}
}
}
}
}
);
}
void InAppWebView::canGoBackOrForward(const int& steps, std::function<void(bool)> completionHandler) const
{
getCopyBackForwardList(
[steps, completionHandler](std::unique_ptr<WebHistory> 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<void(std::unique_ptr<WebHistory>)> completionHandler) const
{
webView->CallDevToolsProtocolMethod(L"Page.getNavigationHistory", L"{}", Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
if (!webView) {
completionHandler(std::make_unique<WebHistory>(std::nullopt, std::nullopt));
return;
}
failedLog(webView->CallDevToolsProtocolMethod(L"Page.getNavigationHistory", L"{}", Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
[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<int64_t>() : 0;
auto entries = historyJson.at("entries").is_array() ? historyJson.at("entries").get<std::vector<nlohmann::json>>() : std::vector<nlohmann::json>{};
std::vector<nlohmann::json> entries = historyJson.at("entries").is_array() ? historyJson.at("entries").get<std::vector<nlohmann::json>>() : std::vector<nlohmann::json>{};
std::vector<std::shared_ptr<WebHistoryItem>> 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<WebHistoryItem>(
entry.at("id").is_number_integer() ? entry.at("id").get<int64_t>() : std::optional<int64_t>{},
i,
offset,
entry.at("userTypedURL").is_string() ? entry.at("userTypedURL").get<std::string>() : std::optional<std::string>{},
@ -413,26 +576,27 @@ namespace flutter_inappwebview_plugin
completionHandler(std::make_unique<WebHistory>(currentIndex, webHistoryItems));
}
else {
debugLog(getErrorMessage(errorCode));
debugLog(errorCode);
completionHandler(std::make_unique<WebHistory>(std::nullopt, std::nullopt));
}
return S_OK;
}
).Get());
).Get()));
}
void InAppWebView::evaluateJavascript(const std::string& source, std::function<void(std::string)> completionHanlder) const
{
webView->ExecuteScript(ansi_to_wide(source).c_str(),
failedLog(webView->ExecuteScript(ansi_to_wide(source).c_str(),
Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
[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

View File

@ -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<UINT64, std::shared_ptr<NavigationAction>> navigationActions = {};
const std::shared_ptr<InAppWebViewSettings> settings;
InAppBrowser* inAppBrowser = nullptr;
std::unique_ptr<UserContentController> userContentController;
InAppWebView(const FlutterInappwebviewWindowsPlugin* plugin, const InAppWebViewCreationParams& params, const HWND parentWindow,
wil::com_ptr<ICoreWebView2Environment> webViewEnv,
@ -127,12 +129,22 @@ namespace flutter_inappwebview_plugin
winrt::com_ptr<ABI::Windows::UI::Composition::ICompositor> compositor);
void initChannel(const std::optional<std::variant<std::string, int64_t>> viewId, const std::optional<std::string> channelName);
void prepare();
std::optional<std::string> getUrl() const;
std::optional<std::string> 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<void(bool)> completionHandler) const;
bool isLoading() const
{
return isLoading_;
}
void stopLoading() const;
void evaluateJavascript(const std::string& source, std::function<void(std::string)> completionHanlder) const;
void getCopyBackForwardList(const std::function<void(std::unique_ptr<WebHistory>)> completionHandler) const;
@ -147,6 +159,9 @@ namespace flutter_inappwebview_plugin
VirtualKeyState virtualKeys_;
bool callShouldOverrideUrlLoading_ = true;
std::shared_ptr<NavigationAction> lastNavigationAction_;
bool isLoading_ = false;
void InAppWebView::registerEventHandlers();
void InAppWebView::registerSurfaceEventHandlers();
};

View File

@ -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

View File

@ -1,4 +1,5 @@
#include "../utils/flutter.h"
#include "../utils/log.h"
#include "in_app_webview_settings.h"
namespace flutter_inappwebview_plugin

View File

@ -0,0 +1,121 @@
#include <wil/wrl.h>
#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<std::shared_ptr<UserScript>> UserContentController::getUserOnlyScriptsAt(const UserScriptInjectionTime& injectionTime) const
{
return userOnlyScripts_.at(injectionTime);
}
void UserContentController::addUserOnlyScript(std::shared_ptr<UserScript> userScript)
{
if (!userScript) {
return;
}
userOnlyScripts_.at(userScript->injectionTime).push_back(std::move(userScript));
}
void UserContentController::addUserOnlyScripts(std::vector<std::shared_ptr<UserScript>> userScripts)
{
for (auto& userScript : userScripts) {
addUserOnlyScript(std::move(userScript));
}
}
void UserContentController::removeUserOnlyScript(std::shared_ptr<UserScript> 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<std::shared_ptr<PluginScript>> UserContentController::getPluginScriptsAt(const UserScriptInjectionTime& injectionTime) const
{
return pluginScripts_.at(injectionTime);
}
void UserContentController::addPluginScript(std::shared_ptr<PluginScript> pluginScript)
{
if (!pluginScript || !webView_) {
return;
}
if (pluginScript->injectionTime == UserScriptInjectionTime::atDocumentStart) {
failedLog(webView_->webView->AddScriptToExecuteOnDocumentCreated(ansi_to_wide(pluginScript->source).c_str(),
Callback<ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler>(
[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<std::shared_ptr<PluginScript>> pluginScripts)
{
for (auto& pluginScript : pluginScripts) {
addPluginScript(std::move(pluginScript));
}
}
void UserContentController::removePluginScript(std::shared_ptr<PluginScript> 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;
}
}

View File

@ -0,0 +1,45 @@
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_
#define FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_
#include <map>
#include <vector>
#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<std::shared_ptr<UserScript>> getUserOnlyScriptsAt(const UserScriptInjectionTime& injectionTime) const;
void addUserOnlyScript(std::shared_ptr<UserScript> userScript);
void addUserOnlyScripts(std::vector<std::shared_ptr<UserScript>> userScripts);
void removeUserOnlyScript(std::shared_ptr<UserScript> userScript);
void removeUserOnlyScriptAt(const int64_t& index, const UserScriptInjectionTime& injectionTime);
void removeAllUserOnlyScripts();
std::vector<std::shared_ptr<PluginScript>> getPluginScriptsAt(const UserScriptInjectionTime& injectionTime) const;
void addPluginScript(std::shared_ptr<PluginScript> pluginScript);
void addPluginScripts(std::vector<std::shared_ptr<PluginScript>> pluginScripts);
void removePluginScript(std::shared_ptr<PluginScript> pluginScript);
void removeAllPluginScripts();
private:
InAppWebView* webView_;
std::map<UserScriptInjectionTime, std::vector<std::shared_ptr<PluginScript>>> pluginScripts_ = {
{UserScriptInjectionTime::atDocumentStart, {}},
{UserScriptInjectionTime::atDocumentEnd, {}}
};
std::map<UserScriptInjectionTime, std::vector<std::shared_ptr<UserScript>>> userOnlyScripts_ = {
{UserScriptInjectionTime::atDocumentStart, {}},
{UserScriptInjectionTime::atDocumentEnd, {}}
};
};
}
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_

View File

@ -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<int>(*value);
return static_cast<NavigationActionPolicy>(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<int>(arguments, "steps");
webView->goBackOrForward(steps);
result->Success(true);
}
else if (method_call.method_name().compare("canGoBackOrForward") == 0) {
auto result_ = std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>>(std::move(result));
auto steps = get_fl_map_value<int>(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<flutter::MethodResult<flutter::EncodableValue>>(std::move(result));
@ -170,6 +198,19 @@ namespace flutter_inappwebview_plugin
}
}
void WebViewChannelDelegate::onUpdateVisitedHistory(const std::optional<std::string>& url, const std::optional<bool>& isReload) const
{
if (!channel) {
return;
}
auto arguments = std::make_unique<flutter::EncodableValue>(flutter::EncodableMap{
{"url", make_fl_value(url)},
{"isReload", make_fl_value(isReload)}
});
channel->InvokeMethod("onUpdateVisitedHistory", std::move(arguments));
}
WebViewChannelDelegate::~WebViewChannelDelegate()
{
debugLog("dealloc WebViewChannelDelegate");

View File

@ -42,6 +42,7 @@ namespace flutter_inappwebview_plugin
void onReceivedError(std::shared_ptr<WebResourceRequest> request, std::shared_ptr<WebResourceError> error) const;
void onReceivedHttpError(std::shared_ptr<WebResourceRequest> request, std::shared_ptr<WebResourceResponse> error) const;
void onTitleChanged(const std::optional<std::string>& title) const;
void onUpdateVisitedHistory(const std::optional<std::string>& url, const std::optional<bool>& isReload) const;
};
}

View File

@ -0,0 +1,26 @@
#include <set>
#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<PluginScript> createJavaScriptBridgePluginScript()
{
const std::set<std::string> allowedOriginRules = { "*" };
return std::make_unique<PluginScript>(
JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME,
JAVASCRIPT_BRIDGE_JS_SOURCE,
UserScriptInjectionTime::atDocumentStart,
allowedOriginRules
);
}
}

View File

@ -0,0 +1,17 @@
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_
#define FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_
#include <memory>
#include <string>
#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<PluginScript> createJavaScriptBridgePluginScript();
}
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_

View File

@ -3,15 +3,19 @@
namespace flutter_inappwebview_plugin
{
NavigationAction::NavigationAction(std::shared_ptr<URLRequest> request, const bool& isForMainFrame)
: request(std::move(request)), isForMainFrame(isForMainFrame)
NavigationAction::NavigationAction(std::shared_ptr<URLRequest> request, const bool& isForMainFrame,
const std::optional<bool>& isRedirect, const std::optional<NavigationActionType>& 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)}
};
}
}

View File

@ -8,13 +8,22 @@
namespace flutter_inappwebview_plugin
{
enum NavigationActionType {
linkActivated = 0,
backForward,
reload,
other
};
class NavigationAction
{
public:
const std::shared_ptr<URLRequest> request;
const bool isForMainFrame;
const std::optional<bool> isRedirect;
const std::optional<NavigationActionType> navigationType;
NavigationAction(std::shared_ptr<URLRequest> request, const bool& isForMainFrame);
NavigationAction(std::shared_ptr<URLRequest> request, const bool& isForMainFrame, const std::optional<bool>& isRedirect, const std::optional<NavigationActionType>& navigationType);
~NavigationAction() = default;
flutter::EncodableMap toEncodableMap() const;

View File

@ -0,0 +1,14 @@
#include "plugin_script.h"
namespace flutter_inappwebview_plugin
{
PluginScript::PluginScript(
const std::optional<std::string>& groupName,
const std::string& source,
const UserScriptInjectionTime& injectionTime,
const std::set<std::string>& allowedOriginRules
) : UserScript(groupName, source, injectionTime, allowedOriginRules)
{}
PluginScript::~PluginScript() {}
}

View File

@ -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<std::string>& groupName,
const std::string& source,
const UserScriptInjectionTime& injectionTime,
const std::set<std::string>& allowedOriginRules
);
~PluginScript();
};
}
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_SCRIPT_H_

View File

@ -0,0 +1,15 @@
#include "user_script.h"
namespace flutter_inappwebview_plugin
{
UserScript::UserScript(
const std::optional<std::string>& groupName,
const std::string& source,
const UserScriptInjectionTime& injectionTime,
const std::set<std::string>& allowedOriginRules
) : groupName(groupName), source(source), injectionTime(injectionTime), allowedOriginRules(allowedOriginRules)
{}
UserScript::~UserScript()
{}
}

View File

@ -0,0 +1,33 @@
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_USER_SCRIPT_H_
#define FLUTTER_INAPPWEBVIEW_PLUGIN_USER_SCRIPT_H_
#include <optional>
#include <set>
#include <string>
namespace flutter_inappwebview_plugin
{
enum UserScriptInjectionTime {
atDocumentStart,
atDocumentEnd
};
class UserScript
{
public:
std::wstring id;
const std::optional<std::string> groupName;
const std::string source;
const UserScriptInjectionTime injectionTime;
const std::set<std::string> allowedOriginRules;
UserScript(
const std::optional<std::string>& groupName,
const std::string& source,
const UserScriptInjectionTime& injectionTime,
const std::set<std::string>& allowedOriginRules
);
~UserScript();
};
}
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_USER_SCRIPT_H_

View File

@ -2,14 +2,15 @@
namespace flutter_inappwebview_plugin
{
WebHistoryItem::WebHistoryItem(const std::optional<int64_t>& index, const std::optional<int64_t>& offset,
WebHistoryItem::WebHistoryItem(const std::optional<int64_t>& entryId, const std::optional<int64_t>& index, const std::optional<int64_t>& offset,
const std::optional<std::string>& originalUrl, const std::optional<std::string>& title,
const std::optional<std::string>& 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<int64_t>(map, "index")),
: entryId(get_optional_fl_map_value<int64_t>(map, "entryId")),
index(get_optional_fl_map_value<int64_t>(map, "index")),
offset(get_optional_fl_map_value<int64_t>(map, "offset")),
originalUrl(get_optional_fl_map_value<std::string>(map, "originalUrl")),
title(get_optional_fl_map_value<std::string>(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)},

View File

@ -11,13 +11,14 @@ namespace flutter_inappwebview_plugin
class WebHistoryItem
{
public:
const std::optional<int64_t> entryId;
const std::optional<int64_t> index;
const std::optional<int64_t> offset;
const std::optional<std::string> originalUrl;
const std::optional<std::string> title;
const std::optional<std::string> url;
WebHistoryItem(const std::optional<int64_t>& index, const std::optional<int64_t>& offset,
WebHistoryItem(const std::optional<int64_t>& entryId, const std::optional<int64_t>& index, const std::optional<int64_t>& offset,
const std::optional<std::string>& originalUrl, const std::optional<std::string>& title,
const std::optional<std::string>& url);
WebHistoryItem(const flutter::EncodableMap& map);

View File

@ -3,7 +3,9 @@
#include <flutter/encodable_value.h>
#include "map.h"
#include "util.h"
#include "vector.h"
namespace flutter_inappwebview_plugin
{

View File

@ -0,0 +1,67 @@
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_UTIL_H_
#define FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_UTIL_H_
#include <comdef.h>
#include <iostream>
#include <string>
#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_

View File

@ -0,0 +1,71 @@
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_MAP_H_
#define FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_MAP_H_
#include <algorithm>
#include <iterator>
#include <map>
#include <optional>
#include <vector>
namespace flutter_inappwebview_plugin
{
template<typename T, typename U = void>
struct is_mappish_impl : std::false_type { };
template<typename T>
struct is_mappish_impl<T, std::void_t<typename T::key_type,
typename T::mapped_type,
decltype(std::declval<T&>()[std::declval<const typename T::key_type&>()])>>
: std::true_type { };
template<typename T>
struct is_mappish : is_mappish_impl<T>::type { };
template<typename K, typename T>
static inline bool map_contains(const std::map<K, T>& map, const K& key)
{
return map.find(key) != map.end();
}
template<typename K, typename T>
static inline T map_at_or_null(const std::map<K, T>& map, const K& key)
{
auto itr = map.find(key);
return itr != map.end() ? itr->second : nullptr;
}
template <typename Iterator, typename Func>
static inline auto functional_map(Iterator begin, Iterator end, Func&& func) ->
std::vector<decltype(func(std::declval<typename Iterator::value_type>()))>
{
using value_type = decltype(func(std::declval<typename Iterator::value_type>()));
std::vector<value_type> out_vector;
out_vector.reserve(std::distance(begin, end));
std::transform(begin, end, std::back_inserter(out_vector),
std::forward<Func>(func));
return out_vector;
}
template <typename T, typename Func>
static inline auto functional_map(const T& iterable, Func&& func) ->
std::vector<decltype(func(std::declval<typename T::value_type>()))>
{
return functional_map(std::begin(iterable), std::end(iterable),
std::forward<Func>(func));
}
template <typename T, typename Func>
static inline auto functional_map(const std::optional<T>& iterable, Func&& func) ->
std::vector<decltype(func(std::declval<typename T::value_type>()))>
{
if (!iterable.has_value()) {
return {};
}
return functional_map(iterable.value(), std::forward<Func>(func));
}
}
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_MAP_H_

View File

@ -1,60 +1,12 @@
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_
#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_
#include <algorithm>
#include <comdef.h>
#include <iostream>
#include <map>
#include <optional>
#include <string>
#include <variant>
#include "strconv.h"
namespace flutter_inappwebview_plugin
{
template<typename T = void, typename = void>
struct is_vector_impl : std::false_type { };
template<typename T, typename U = void>
struct is_mappish_impl : std::false_type { };
template<typename T>
struct is_vector_impl<T, std::enable_if_t<
std::is_same<T, typename std::vector<std::string>>::value>
> : std::true_type { };
template<typename T>
struct is_vector_impl<T, std::enable_if_t<
std::is_same<T, typename std::vector<typename std::iterator_traits<T>::value_type>::iterator>::value>
> : std::true_type { };
template<typename T>
struct is_mappish_impl<T, std::void_t<typename T::key_type,
typename T::mapped_type,
decltype(std::declval<T&>()[std::declval<const typename T::key_type&>()])>>
: std::true_type { };
template<typename T>
struct is_mappish : is_mappish_impl<T>::type { };
template<typename T>
struct is_vector : is_vector_impl<T>::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<typename T>
static inline std::optional<T> make_pointer_optional(const T* value)
{
@ -74,52 +26,6 @@ namespace flutter_inappwebview_plugin
static_assert(always_false_v<T>, "non-exhaustive visitor!");
}, var);
}
template<typename K, typename T>
static inline bool map_contains(const std::map<K, T>& map, const K& key)
{
return map.find(key) != map.end();
}
template<typename K, typename T>
static inline T map_at_or_null(const std::map<K, T>& map, const K& key)
{
auto itr = map.find(key);
return itr != map.end() ? itr->second : nullptr;
}
template <typename Iterator, typename Func>
static inline auto functional_map(Iterator begin, Iterator end, Func&& func) ->
std::vector<decltype(func(std::declval<typename Iterator::value_type>()))>
{
using value_type = decltype(func(std::declval<typename Iterator::value_type>()));
std::vector<value_type> out_vector;
out_vector.reserve(std::distance(begin, end));
std::transform(begin, end, std::back_inserter(out_vector),
std::forward<Func>(func));
return out_vector;
}
template <typename T, typename Func>
static inline auto functional_map(const T& iterable, Func&& func) ->
std::vector<decltype(func(std::declval<typename T::value_type>()))>
{
return functional_map(std::begin(iterable), std::end(iterable),
std::forward<Func>(func));
}
template <typename T, typename Func>
static inline auto functional_map(const std::optional<T>& iterable, Func&& func) ->
std::vector<decltype(func(std::declval<typename T::value_type>()))>
{
if (!iterable.has_value()) {
return {};
}
return functional_map(iterable.value(), std::forward<Func>(func));
}
}
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_

View File

@ -0,0 +1,41 @@
#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_VECTOR_H_
#define FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_VECTOR_H_
#include <algorithm>
#include <iterator>
#include <optional>
#include <string>
#include <vector>
namespace flutter_inappwebview_plugin
{
template<typename T = void, typename = void>
struct is_vector_impl : std::false_type { };
template<typename T>
struct is_vector_impl<T, std::enable_if_t<
std::is_same<T, typename std::vector<std::string>>::value>
> : std::true_type { };
template<typename T>
struct is_vector_impl<T, std::enable_if_t<
std::is_same<T, typename std::vector<typename std::iterator_traits<T>::value_type>::iterator>::value>
> : std::true_type { };
template<typename T>
struct is_vector : is_vector_impl<T>::type { };
template <typename T>
static inline void vector_remove_el(std::vector<T>& vec, const T& el)
{
std::remove(vec.begin(), vec.end(), el);
}
template <typename T>
static inline void vector_remove_erase_el(std::vector<T>& vec, const T& el)
{
vec.erase(std::remove(vec.begin(), vec.end(), el), vec.end());
}
}
#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_LOG_VECTOR_H_