From 7e1ba2c2c8772f2d8ee89e40a1b40caa91b2aa27 Mon Sep 17 00:00:00 2001 From: "Suzuki, Shuhei" Date: Thu, 18 Jan 2024 13:40:16 +0900 Subject: [PATCH 001/137] issue #1983: Fixed to prevent Activity from being restored --- .../in_app_browser/InAppBrowserActivity.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java index 6cb763c49..d2c193b4b 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java @@ -82,6 +82,11 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (savedInstanceState != null) { + finish(); + return; + } + Bundle b = getIntent().getExtras(); if (b == null) return; From 69c629e020a4eb527c85bf119e4e0f1fdd970f92 Mon Sep 17 00:00:00 2001 From: liyuanbo Date: Thu, 1 Feb 2024 17:43:28 +0800 Subject: [PATCH 002/137] redirect bug fix solution [issue 1884](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1884) --- .../in_app_webview/InAppWebViewClient.java | 49 +++++++----- .../in_app_webview/InAppWebViewSettings.java | 5 ++ .../in_app_webview_settings.dart | 75 +++++++------------ .../in_app_webview_settings.g.dart | 19 +++-- 4 files changed, 72 insertions(+), 76 deletions(-) diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java index c409efe54..b06276b79 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java @@ -56,6 +56,7 @@ import java.util.List; import java.util.Map; import java.util.regex.Matcher; +import java.util.regex.Pattern; public class InAppWebViewClient extends WebViewClient { @@ -74,6 +75,12 @@ public InAppWebViewClient(InAppBrowserDelegate inAppBrowserDelegate) { public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { InAppWebView webView = (InAppWebView) view; if (webView.customSettings.useShouldOverrideUrlLoading) { + if (webView.customSettings.regexToCancelOverrideUrlLoading != null) { + Pattern pattern = Pattern.compile(webView.customSettings.regexToCancelOverrideUrlLoading); + Matcher m = pattern.matcher(request.getUrl().toString()); + Log.i(LOG_TAG, request.getUrl().toString() + " isMatch " + m.matches()); + if (m.matches() == false) return false; + } boolean isRedirect = false; if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT)) { isRedirect = WebResourceRequestCompat.isRedirect(request); @@ -108,6 +115,12 @@ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request public boolean shouldOverrideUrlLoading(WebView webView, String url) { InAppWebView inAppWebView = (InAppWebView) webView; if (inAppWebView.customSettings.useShouldOverrideUrlLoading) { + if (inAppWebView.customSettings.regexToCancelOverrideUrlLoading != null) { + Pattern pattern = Pattern.compile(inAppWebView.customSettings.regexToCancelOverrideUrlLoading); + Matcher m = pattern.matcher(url); + Log.i(LOG_TAG, url + " isMatch " + m.matches()); + if (m.matches() == false) return false; + } onShouldOverrideUrlLoading(inAppWebView, url, "GET", null,true, false, false); return true; } @@ -164,7 +177,7 @@ public void error(String errorCode, @Nullable String errorMessage, @Nullable Obj defaultBehaviour(null); } }; - + if (webView.channelDelegate != null) { webView.channelDelegate.shouldOverrideUrlLoading(navigationAction, callback); } else { @@ -216,7 +229,7 @@ public void onPageStarted(WebView view, String url, Bitmap favicon) { webView.channelDelegate.onLoadStart(url); } } - + public void onPageFinished(WebView view, String url) { final InAppWebView webView = (InAppWebView) view; webView.isLoading = false; @@ -260,13 +273,13 @@ public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { if (inAppBrowserDelegate != null) { inAppBrowserDelegate.didUpdateVisitedHistory(url); } - + final InAppWebView webView = (InAppWebView) view; if (webView.channelDelegate != null) { webView.channelDelegate.onUpdateVisitedHistory(url, isReload); } } - + @RequiresApi(api = Build.VERSION_CODES.M) @Override public void onReceivedError(WebView view, @NonNull WebResourceRequest request, @NonNull WebResourceError error) { @@ -430,7 +443,7 @@ public void error(String errorCode, @Nullable String errorMessage, @Nullable Obj defaultBehaviour(null); } }; - + if (webView.channelDelegate != null) { webView.channelDelegate.onReceivedHttpAuthRequest(challenge, callback); } else { @@ -489,7 +502,7 @@ public void error(String errorCode, @Nullable String errorMessage, @Nullable Obj defaultBehaviour(null); } }; - + if (webView.channelDelegate != null) { webView.channelDelegate.onReceivedServerTrustAuthRequest(challenge, callback); } else { @@ -525,19 +538,19 @@ public boolean nonNullSuccess(@NonNull ClientCertResponse response) { if (action != null && webView.plugin != null) { switch (action) { case 1: - { - String certificatePath = (String) response.getCertificatePath(); - String certificatePassword = (String) response.getCertificatePassword(); - String keyStoreType = (String) response.getKeyStoreType(); - Util.PrivateKeyAndCertificates privateKeyAndCertificates = - Util.loadPrivateKeyAndCertificate(webView.plugin, certificatePath, certificatePassword, keyStoreType); - if (privateKeyAndCertificates != null) { - request.proceed(privateKeyAndCertificates.privateKey, privateKeyAndCertificates.certificates); - } else { - request.cancel(); - } + { + String certificatePath = (String) response.getCertificatePath(); + String certificatePassword = (String) response.getCertificatePassword(); + String keyStoreType = (String) response.getKeyStoreType(); + Util.PrivateKeyAndCertificates privateKeyAndCertificates = + Util.loadPrivateKeyAndCertificate(webView.plugin, certificatePath, certificatePassword, keyStoreType); + if (privateKeyAndCertificates != null) { + request.proceed(privateKeyAndCertificates.privateKey, privateKeyAndCertificates.certificates); + } else { + request.cancel(); } - break; + } + break; case 2: request.ignore(); break; diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java index 6bf17f607..6bdeb9ec8 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java @@ -104,6 +104,7 @@ public class InAppWebViewSettings implements ISettings { public Boolean hardwareAcceleration = true; public Boolean supportMultipleWindows = false; public String regexToCancelSubFramesLoading; + public String regexToCancelOverrideUrlLoading; public Integer overScrollMode = View.OVER_SCROLL_IF_CONTENT_SCROLLS; public Boolean networkAvailable = null; public Integer scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY; @@ -346,6 +347,9 @@ public InAppWebViewSettings parse(@NonNull Map settings) { case "regexToCancelSubFramesLoading": regexToCancelSubFramesLoading = (String) value; break; + case "regexToCancelOverrideUrlLoading": + regexToCancelOverrideUrlLoading = (String) value; + break; case "overScrollMode": overScrollMode = (Integer) value; break; @@ -489,6 +493,7 @@ public Map toMap() { settings.put("hardwareAcceleration", hardwareAcceleration); settings.put("supportMultipleWindows", supportMultipleWindows); settings.put("regexToCancelSubFramesLoading", regexToCancelSubFramesLoading); + settings.put("regexToCancelOverrideUrlLoading", regexToCancelOverrideUrlLoading); settings.put("overScrollMode", overScrollMode); settings.put("networkAvailable", networkAvailable); settings.put("scrollBarStyle", scrollBarStyle); diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart index f12b274ce..2b0f896f0 100755 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart @@ -1,15 +1,23 @@ +import 'dart:typed_data'; + import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; -import 'dart:typed_data'; +import '../content_blocker.dart'; +import '../context_menu/context_menu.dart'; +import '../in_app_browser/in_app_browser_settings.dart'; +import '../in_app_browser/platform_in_app_browser.dart'; +import '../in_app_webview/platform_inappwebview_controller.dart'; import '../platform_webview_asset_loader.dart'; +import '../platform_webview_feature.dart'; import '../types/action_mode_menu_item.dart'; import '../types/cache_mode.dart'; import '../types/data_detector_types.dart'; import '../types/force_dark.dart'; import '../types/force_dark_strategy.dart'; import '../types/layout_algorithm.dart'; +import '../types/main.dart'; import '../types/mixed_content_mode.dart'; import '../types/over_scroll_mode.dart'; import '../types/referrer_policy.dart'; @@ -21,17 +29,10 @@ import '../types/scrollview_deceleration_rate.dart'; import '../types/selection_granularity.dart'; import '../types/user_preferred_content_mode.dart'; import '../types/vertical_scrollbar_position.dart'; +import '../util.dart'; import '../web_uri.dart'; import 'android/in_app_webview_options.dart'; import 'apple/in_app_webview_options.dart'; -import '../content_blocker.dart'; -import '../types/main.dart'; -import '../util.dart'; -import '../in_app_browser/in_app_browser_settings.dart'; -import '../platform_webview_feature.dart'; -import '../in_app_webview/platform_inappwebview_controller.dart'; -import '../context_menu/context_menu.dart'; -import '../in_app_browser/platform_in_app_browser.dart'; import 'platform_webview.dart'; part 'in_app_webview_settings.g.dart'; @@ -57,12 +58,8 @@ class InAppWebViewSettings_ { ///If the [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event is implemented and this value is `null`, ///it will be automatically inferred as `true`, otherwise, the default value is `false`. ///This logic will not be applied for [PlatformInAppBrowser], where you must set the value manually. - @SupportedPlatforms(platforms: [ - AndroidPlatform(), - IOSPlatform(), - MacOSPlatform(), - WindowsPlatform() - ]) + @SupportedPlatforms( + platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()]) bool? useShouldOverrideUrlLoading; ///Set to `true` to be able to listen at the [PlatformWebViewCreationParams.onLoadResource] event. @@ -102,11 +99,7 @@ class InAppWebViewSettings_ { MacOSPlatform( apiName: "WKWebView.customUserAgent", apiUrl: - "https://developer.apple.com/documentation/webkit/wkwebview/1414950-customuseragent"), - WindowsPlatform( - apiName: 'ICoreWebView2Settings2.put_UserAgent', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings2?view=webview2-1.0.2210.55#put_useragent') + "https://developer.apple.com/documentation/webkit/wkwebview/1414950-customuseragent") ]) String? userAgent; @@ -138,11 +131,7 @@ class InAppWebViewSettings_ { apiName: "WKWebpagePreferences.allowsContentJavaScript", apiUrl: "https://developer.apple.com/documentation/webkit/wkwebpagepreferences/3552422-allowscontentjavascript/"), - WebPlatform(requiresSameOrigin: false), - WindowsPlatform( - apiName: "ICoreWebView2Settings.put_IsScriptEnabled", - apiUrl: - "https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_isscriptenabled") + WebPlatform(requiresSameOrigin: false) ]) bool? javaScriptEnabled; @@ -319,12 +308,7 @@ because there isn't any way to make the website data store non-persistent for th @SupportedPlatforms(platforms: [ AndroidPlatform(), IOSPlatform(), - MacOSPlatform(available: "12.0"), - WindowsPlatform( - available: '1.0.774.44', - apiName: 'ICoreWebView2Controller2.put_DefaultBackgroundColor', - apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controller2?view=webview2-1.0.2210.55#put_defaultbackgroundcolor') + MacOSPlatform(available: "12.0") ]) bool? transparentBackground; @@ -339,15 +323,8 @@ because there isn't any way to make the website data store non-persistent for th bool? disableHorizontalScroll; ///Set to `true` to disable context menu. The default value is `false`. - @SupportedPlatforms(platforms: [ - AndroidPlatform(), - IOSPlatform(), - WebPlatform(), - WindowsPlatform( - apiName: "ICoreWebView2Settings.put_AreDefaultContextMenusEnabled", - apiUrl: - "https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_aredefaultcontextmenusenabled") - ]) + @SupportedPlatforms( + platforms: [AndroidPlatform(), IOSPlatform(), WebPlatform()]) bool? disableContextMenu; ///Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`. @@ -357,11 +334,7 @@ because there isn't any way to make the website data store non-persistent for th apiUrl: "https://developer.android.com/reference/android/webkit/WebSettings?hl=en#setSupportZoom(boolean)"), IOSPlatform(), - MacOSPlatform(), - WindowsPlatform( - apiName: "ICoreWebView2Settings.put_IsZoomControlEnabled", - apiUrl: - "https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_iszoomcontrolenabled") + MacOSPlatform() ]) bool? supportZoom; @@ -805,6 +778,11 @@ because there isn't any way to make the website data store non-persistent for th @SupportedPlatforms(platforms: [AndroidPlatform()]) String? regexToCancelSubFramesLoading; + ///Regular expression used by [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event to cancel navigation requests + ///If the url request not matches the regular expression, then the shouldOverrideUrlLoading is return false. + @SupportedPlatforms(platforms: [AndroidPlatform()]) + String? regexToCancelOverrideUrlLoading; + ///Set to `false` to disable Flutter Hybrid Composition. The default value is `true`. ///Hybrid Composition is supported starting with Flutter v1.20+. @SupportedPlatforms(platforms: [ @@ -1565,11 +1543,7 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri available: "13.3", apiName: "WKWebView.isInspectable", apiUrl: - "https://developer.apple.com/documentation/webkit/wkwebview/4111163-isinspectable"), - WindowsPlatform( - apiName: "ICoreWebView2Settings.put_AreDevToolsEnabled", - apiUrl: - "https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_aredevtoolsenabled") + "https://developer.apple.com/documentation/webkit/wkwebview/4111163-isinspectable") ]) bool? isInspectable; @@ -1722,6 +1696,7 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri this.initialScale = 0, this.supportMultipleWindows = false, this.regexToCancelSubFramesLoading, + this.regexToCancelOverrideUrlLoading, this.useHybridComposition = true, this.useShouldInterceptRequest, this.useOnRenderProcessGone, diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart index 7c30031d1..0eed562b2 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart @@ -371,7 +371,6 @@ class InAppWebViewSettings { ///- Android native WebView ///- iOS ///- Web but iframe requires same origin - ///- Windows ([Official API - ICoreWebView2Settings.put_AreDefaultContextMenusEnabled](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_aredefaultcontextmenusenabled)) bool? disableContextMenu; ///Sets whether the default Android WebView’s internal error page should be suppressed or displayed for bad navigations. @@ -649,7 +648,6 @@ class InAppWebViewSettings { ///**Officially Supported Platforms/Implementations**: ///- iOS 16.4+ ([Official API - WKWebView.isInspectable](https://developer.apple.com/documentation/webkit/wkwebview/4111163-isinspectable)) ///- MacOS 13.3+ ([Official API - WKWebView.isInspectable](https://developer.apple.com/documentation/webkit/wkwebview/4111163-isinspectable)) - ///- Windows ([Official API - ICoreWebView2Settings.put_AreDevToolsEnabled](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_aredevtoolsenabled)) bool? isInspectable; ///A Boolean value that determines whether paging is enabled for the scroll view. @@ -693,7 +691,6 @@ class InAppWebViewSettings { ///- iOS ([Official API - WKWebpagePreferences.allowsContentJavaScript](https://developer.apple.com/documentation/webkit/wkwebpagepreferences/3552422-allowscontentjavascript/)) ///- MacOS ([Official API - WKWebpagePreferences.allowsContentJavaScript](https://developer.apple.com/documentation/webkit/wkwebpagepreferences/3552422-allowscontentjavascript/)) ///- Web - ///- Windows ([Official API - ICoreWebView2Settings.put_IsScriptEnabled](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_isscriptenabled)) bool? javaScriptEnabled; ///Sets the underlying layout algorithm. This will cause a re-layout of the WebView. @@ -849,6 +846,13 @@ class InAppWebViewSettings { ///- Android native WebView String? regexToCancelSubFramesLoading; + ///Regular expression used by [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event to cancel navigation requests + ///If the url request not matches the regular expression, then the shouldOverrideUrlLoading is return false. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android native WebView + String? regexToCancelOverrideUrlLoading; + ///Sets the renderer priority policy for this WebView. /// ///**Officially Supported Platforms/Implementations**: @@ -986,7 +990,6 @@ class InAppWebViewSettings { ///- Android native WebView ([Official API - WebSettings.setSupportZoom](https://developer.android.com/reference/android/webkit/WebSettings?hl=en#setSupportZoom(boolean))) ///- iOS ///- MacOS - ///- Windows ([Official API - ICoreWebView2Settings.put_IsZoomControlEnabled](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_iszoomcontrolenabled)) bool? supportZoom; ///Set to `true` if you want the WebView suppresses content rendering until it is fully loaded into memory. The default value is `false`. @@ -1016,7 +1019,6 @@ class InAppWebViewSettings { ///- Android native WebView ///- iOS ///- MacOS 12.0+ - ///- Windows 1.0.774.44+ ([Official API - ICoreWebView2Controller2.put_DefaultBackgroundColor](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controller2?view=webview2-1.0.2210.55#put_defaultbackgroundcolor)) bool? transparentBackground; ///The color the web view displays behind the active page, visible when the user scrolls beyond the bounds of the page. @@ -1142,7 +1144,6 @@ class InAppWebViewSettings { ///- Android native WebView ///- iOS ///- MacOS - ///- Windows bool? useShouldOverrideUrlLoading; ///Set to `true` if the WebView should enable support for the "viewport" HTML meta tag or should use a wide viewport. @@ -1160,7 +1161,6 @@ class InAppWebViewSettings { ///- Android native WebView ([Official API - WebSettings.setUserAgentString](https://developer.android.com/reference/android/webkit/WebSettings?hl=en#setUserAgentString(java.lang.String))) ///- iOS ([Official API - WKWebView.customUserAgent](https://developer.apple.com/documentation/webkit/wkwebview/1414950-customuseragent)) ///- MacOS ([Official API - WKWebView.customUserAgent](https://developer.apple.com/documentation/webkit/wkwebview/1414950-customuseragent)) - ///- Windows ([Official API - ICoreWebView2Settings2.put_UserAgent](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings2?view=webview2-1.0.2210.55#put_useragent)) String? userAgent; ///Define whether the vertical scrollbar should be drawn or not. The default value is `true`. @@ -1267,6 +1267,7 @@ class InAppWebViewSettings { this.initialScale = 0, this.supportMultipleWindows = false, this.regexToCancelSubFramesLoading, + this.regexToCancelOverrideUrlLoading, this.useHybridComposition = true, this.useShouldInterceptRequest, this.useOnRenderProcessGone, @@ -1404,6 +1405,7 @@ class InAppWebViewSettings { MixedContentMode.fromNativeValue(map['mixedContentMode']), networkAvailable: map['networkAvailable'], regexToCancelSubFramesLoading: map['regexToCancelSubFramesLoading'], + regexToCancelOverrideUrlLoading: map['regexToCancelOverrideUrlLoading'], rendererPriorityPolicy: RendererPriorityPolicy.fromMap( map['rendererPriorityPolicy']?.cast()), requestedWithHeaderOriginAllowList: @@ -1676,6 +1678,7 @@ class InAppWebViewSettings { "pageZoom": pageZoom, "preferredContentMode": preferredContentMode?.toNativeValue(), "regexToCancelSubFramesLoading": regexToCancelSubFramesLoading, + "regexToCancelOverrideUrlLoading": regexToCancelOverrideUrlLoading, "rendererPriorityPolicy": rendererPriorityPolicy?.toMap(), "requestedWithHeaderOriginAllowList": requestedWithHeaderOriginAllowList?.toList(), @@ -1732,6 +1735,6 @@ class InAppWebViewSettings { @override String toString() { - return 'InAppWebViewSettings{accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowingReadAccessTo: $allowingReadAccessTo, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsLinkPreview: $allowsLinkPreview, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, alwaysBounceHorizontal: $alwaysBounceHorizontal, alwaysBounceVertical: $alwaysBounceVertical, appCachePath: $appCachePath, applePayAPIEnabled: $applePayAPIEnabled, applicationNameForUserAgent: $applicationNameForUserAgent, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, builtInZoomControls: $builtInZoomControls, cacheEnabled: $cacheEnabled, cacheMode: $cacheMode, contentBlockers: $contentBlockers, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, cursiveFontFamily: $cursiveFontFamily, dataDetectorTypes: $dataDetectorTypes, databaseEnabled: $databaseEnabled, decelerationRate: $decelerationRate, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, defaultVideoPoster: $defaultVideoPoster, disableContextMenu: $disableContextMenu, disableDefaultErrorPage: $disableDefaultErrorPage, disableHorizontalScroll: $disableHorizontalScroll, disableInputAccessoryView: $disableInputAccessoryView, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableVerticalScroll: $disableVerticalScroll, disabledActionModeMenuItems: $disabledActionModeMenuItems, disallowOverScroll: $disallowOverScroll, displayZoomControls: $displayZoomControls, domStorageEnabled: $domStorageEnabled, enableViewportScale: $enableViewportScale, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, forceDark: $forceDark, forceDarkStrategy: $forceDarkStrategy, geolocationEnabled: $geolocationEnabled, hardwareAcceleration: $hardwareAcceleration, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeCsp: $iframeCsp, iframeName: $iframeName, iframeReferrerPolicy: $iframeReferrerPolicy, iframeSandbox: $iframeSandbox, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, incognito: $incognito, initialScale: $initialScale, interceptOnlyAsyncAjaxRequests: $interceptOnlyAsyncAjaxRequests, isDirectionalLockEnabled: $isDirectionalLockEnabled, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, isInspectable: $isInspectable, isPagingEnabled: $isPagingEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, isTextInteractionEnabled: $isTextInteractionEnabled, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, javaScriptEnabled: $javaScriptEnabled, layoutAlgorithm: $layoutAlgorithm, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, maximumViewportInset: $maximumViewportInset, maximumZoomScale: $maximumZoomScale, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, mediaType: $mediaType, minimumFontSize: $minimumFontSize, minimumLogicalFontSize: $minimumLogicalFontSize, minimumViewportInset: $minimumViewportInset, minimumZoomScale: $minimumZoomScale, mixedContentMode: $mixedContentMode, needInitialFocus: $needInitialFocus, networkAvailable: $networkAvailable, offscreenPreRaster: $offscreenPreRaster, overScrollMode: $overScrollMode, pageZoom: $pageZoom, preferredContentMode: $preferredContentMode, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading, rendererPriorityPolicy: $rendererPriorityPolicy, requestedWithHeaderOriginAllowList: $requestedWithHeaderOriginAllowList, resourceCustomSchemes: $resourceCustomSchemes, safeBrowsingEnabled: $safeBrowsingEnabled, sansSerifFontFamily: $sansSerifFontFamily, saveFormData: $saveFormData, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollBarFadeDuration: $scrollBarFadeDuration, scrollBarStyle: $scrollBarStyle, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollsToTop: $scrollsToTop, selectionGranularity: $selectionGranularity, serifFontFamily: $serifFontFamily, sharedCookiesEnabled: $sharedCookiesEnabled, shouldPrintBackgrounds: $shouldPrintBackgrounds, standardFontFamily: $standardFontFamily, supportMultipleWindows: $supportMultipleWindows, supportZoom: $supportZoom, suppressesIncrementalRendering: $suppressesIncrementalRendering, textZoom: $textZoom, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, transparentBackground: $transparentBackground, underPageBackgroundColor: $underPageBackgroundColor, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, useHybridComposition: $useHybridComposition, useOnDownloadStart: $useOnDownloadStart, useOnLoadResource: $useOnLoadResource, useOnNavigationResponse: $useOnNavigationResponse, useOnRenderProcessGone: $useOnRenderProcessGone, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, useShouldInterceptRequest: $useShouldInterceptRequest, useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useWideViewPort: $useWideViewPort, userAgent: $userAgent, verticalScrollBarEnabled: $verticalScrollBarEnabled, verticalScrollbarPosition: $verticalScrollbarPosition, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, webViewAssetLoader: $webViewAssetLoader}'; + return 'InAppWebViewSettings{accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowingReadAccessTo: $allowingReadAccessTo, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsLinkPreview: $allowsLinkPreview, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, alwaysBounceHorizontal: $alwaysBounceHorizontal, alwaysBounceVertical: $alwaysBounceVertical, appCachePath: $appCachePath, applePayAPIEnabled: $applePayAPIEnabled, applicationNameForUserAgent: $applicationNameForUserAgent, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, builtInZoomControls: $builtInZoomControls, cacheEnabled: $cacheEnabled, cacheMode: $cacheMode, contentBlockers: $contentBlockers, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, cursiveFontFamily: $cursiveFontFamily, dataDetectorTypes: $dataDetectorTypes, databaseEnabled: $databaseEnabled, decelerationRate: $decelerationRate, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, defaultVideoPoster: $defaultVideoPoster, disableContextMenu: $disableContextMenu, disableDefaultErrorPage: $disableDefaultErrorPage, disableHorizontalScroll: $disableHorizontalScroll, disableInputAccessoryView: $disableInputAccessoryView, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableVerticalScroll: $disableVerticalScroll, disabledActionModeMenuItems: $disabledActionModeMenuItems, disallowOverScroll: $disallowOverScroll, displayZoomControls: $displayZoomControls, domStorageEnabled: $domStorageEnabled, enableViewportScale: $enableViewportScale, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, forceDark: $forceDark, forceDarkStrategy: $forceDarkStrategy, geolocationEnabled: $geolocationEnabled, hardwareAcceleration: $hardwareAcceleration, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeCsp: $iframeCsp, iframeName: $iframeName, iframeReferrerPolicy: $iframeReferrerPolicy, iframeSandbox: $iframeSandbox, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, incognito: $incognito, initialScale: $initialScale, interceptOnlyAsyncAjaxRequests: $interceptOnlyAsyncAjaxRequests, isDirectionalLockEnabled: $isDirectionalLockEnabled, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, isInspectable: $isInspectable, isPagingEnabled: $isPagingEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, isTextInteractionEnabled: $isTextInteractionEnabled, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, javaScriptEnabled: $javaScriptEnabled, layoutAlgorithm: $layoutAlgorithm, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, maximumViewportInset: $maximumViewportInset, maximumZoomScale: $maximumZoomScale, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, mediaType: $mediaType, minimumFontSize: $minimumFontSize, minimumLogicalFontSize: $minimumLogicalFontSize, minimumViewportInset: $minimumViewportInset, minimumZoomScale: $minimumZoomScale, mixedContentMode: $mixedContentMode, needInitialFocus: $needInitialFocus, networkAvailable: $networkAvailable, offscreenPreRaster: $offscreenPreRaster, overScrollMode: $overScrollMode, pageZoom: $pageZoom, preferredContentMode: $preferredContentMode, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading,regexToCancelOverrideUrlLoading: $regexToCancelOverrideUrlLoading, rendererPriorityPolicy: $rendererPriorityPolicy, requestedWithHeaderOriginAllowList: $requestedWithHeaderOriginAllowList, resourceCustomSchemes: $resourceCustomSchemes, safeBrowsingEnabled: $safeBrowsingEnabled, sansSerifFontFamily: $sansSerifFontFamily, saveFormData: $saveFormData, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollBarFadeDuration: $scrollBarFadeDuration, scrollBarStyle: $scrollBarStyle, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollsToTop: $scrollsToTop, selectionGranularity: $selectionGranularity, serifFontFamily: $serifFontFamily, sharedCookiesEnabled: $sharedCookiesEnabled, shouldPrintBackgrounds: $shouldPrintBackgrounds, standardFontFamily: $standardFontFamily, supportMultipleWindows: $supportMultipleWindows, supportZoom: $supportZoom, suppressesIncrementalRendering: $suppressesIncrementalRendering, textZoom: $textZoom, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, transparentBackground: $transparentBackground, underPageBackgroundColor: $underPageBackgroundColor, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, useHybridComposition: $useHybridComposition, useOnDownloadStart: $useOnDownloadStart, useOnLoadResource: $useOnLoadResource, useOnNavigationResponse: $useOnNavigationResponse, useOnRenderProcessGone: $useOnRenderProcessGone, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, useShouldInterceptRequest: $useShouldInterceptRequest, useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useWideViewPort: $useWideViewPort, userAgent: $userAgent, verticalScrollBarEnabled: $verticalScrollBarEnabled, verticalScrollbarPosition: $verticalScrollbarPosition, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, webViewAssetLoader: $webViewAssetLoader}'; } } From 6f705b077b1b67c2d7133a6b85eaac17bf431586 Mon Sep 17 00:00:00 2001 From: liyuanbo Date: Fri, 23 Feb 2024 16:41:57 +0800 Subject: [PATCH 003/137] Update InAppWebViewClientCompat.java add WebViewClientCompat regex match --- .../InAppWebViewClientCompat.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java index 5aecaa5b4..137a1e362 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java @@ -56,6 +56,7 @@ import java.util.List; import java.util.Map; import java.util.regex.Matcher; +import java.util.regex.Pattern; public class InAppWebViewClientCompat extends WebViewClientCompat { @@ -74,6 +75,12 @@ public InAppWebViewClientCompat(InAppBrowserDelegate inAppBrowserDelegate) { public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull WebResourceRequest request) { InAppWebView webView = (InAppWebView) view; if (webView.customSettings.useShouldOverrideUrlLoading) { + if (webView.customSettings.regexToCancelOverrideUrlLoading != null) { + Pattern pattern = Pattern.compile(webView.customSettings.regexToCancelOverrideUrlLoading); + Matcher m = pattern.matcher(request.getUrl().toString()); + Log.i(LOG_TAG, request.getUrl().toString() + " isMatch " + m.matches()); + if (m.matches() == false) return false; + } boolean isRedirect = false; if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT)) { isRedirect = WebResourceRequestCompat.isRedirect(request); @@ -108,6 +115,12 @@ public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull WebResou public boolean shouldOverrideUrlLoading(WebView webView, String url) { InAppWebView inAppWebView = (InAppWebView) webView; if (inAppWebView.customSettings.useShouldOverrideUrlLoading) { + if (inAppWebView.customSettings.regexToCancelOverrideUrlLoading != null) { + Pattern pattern = Pattern.compile(inAppWebView.customSettings.regexToCancelOverrideUrlLoading); + Matcher m = pattern.matcher(url); + Log.i(LOG_TAG, url + " isMatch " + m.matches()); + if (m.matches() == false) return false; + } onShouldOverrideUrlLoading(inAppWebView, url, "GET", null,true, false, false); return true; } @@ -164,7 +177,7 @@ public void error(String errorCode, @Nullable String errorMessage, @Nullable Obj defaultBehaviour(null); } }; - + if (webView.channelDelegate != null) { webView.channelDelegate.shouldOverrideUrlLoading(navigationAction, callback); } else { @@ -216,7 +229,7 @@ public void onPageStarted(WebView view, String url, Bitmap favicon) { webView.channelDelegate.onLoadStart(url); } } - + public void onPageFinished(WebView view, String url) { final InAppWebView webView = (InAppWebView) view; webView.isLoading = false; @@ -260,13 +273,13 @@ public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { if (inAppBrowserDelegate != null) { inAppBrowserDelegate.didUpdateVisitedHistory(url); } - + final InAppWebView webView = (InAppWebView) view; if (webView.channelDelegate != null) { webView.channelDelegate.onUpdateVisitedHistory(url, isReload); } } - + @RequiresApi(api = Build.VERSION_CODES.M) @Override public void onReceivedError(@NonNull WebView view, @@ -442,7 +455,7 @@ public void error(String errorCode, @Nullable String errorMessage, @Nullable Obj defaultBehaviour(null); } }; - + if (webView.channelDelegate != null) { webView.channelDelegate.onReceivedHttpAuthRequest(challenge, callback); } else { @@ -501,7 +514,7 @@ public void error(String errorCode, @Nullable String errorMessage, @Nullable Obj defaultBehaviour(null); } }; - + if (webView.channelDelegate != null) { webView.channelDelegate.onReceivedServerTrustAuthRequest(challenge, callback); } else { @@ -541,7 +554,7 @@ public boolean nonNullSuccess(@NonNull ClientCertResponse response) { String certificatePath = (String) response.getCertificatePath(); String certificatePassword = (String) response.getCertificatePassword(); String keyStoreType = (String) response.getKeyStoreType(); - Util.PrivateKeyAndCertificates privateKeyAndCertificates = + Util.PrivateKeyAndCertificates privateKeyAndCertificates = Util.loadPrivateKeyAndCertificate(webView.plugin, certificatePath, certificatePassword, keyStoreType); if (privateKeyAndCertificates != null) { request.proceed(privateKeyAndCertificates.privateKey, privateKeyAndCertificates.certificates); From e4d043d3a2d5fcc2e0f6a68297c7e3eca1d594ac Mon Sep 17 00:00:00 2001 From: yamaha252 Date: Thu, 18 Jan 2024 18:40:14 +0500 Subject: [PATCH 004/137] request focus --- .../lib/src/in_app_webview/in_app_webview_controller.dart | 3 +++ .../webview/WebViewChannelDelegate.java | 6 ++++++ .../webview/WebViewChannelDelegateMethods.java | 1 + .../lib/src/in_app_webview/in_app_webview_controller.dart | 6 ++++++ .../ios/Classes/InAppWebView/InAppWebView.swift | 4 ++++ .../ios/Classes/InAppWebView/WebViewChannelDelegate.swift | 4 ++++ .../InAppWebView/WebViewChannelDelegateMethods.swift | 1 + .../lib/src/in_app_webview/in_app_webview_controller.dart | 6 ++++++ .../in_app_webview/platform_inappwebview_controller.dart | 5 +++++ 9 files changed, 36 insertions(+) diff --git a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart index 1544754d3..871afe217 100644 --- a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart @@ -290,6 +290,9 @@ class InAppWebViewController { Future getHitTestResult() => platform.getHitTestResult(); + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestFocus} + Future requestFocus() => platform.requestFocus(); + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearFocus} Future clearFocus() => platform.clearFocus(); diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java index 5f87b93c0..880d25f68 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java @@ -474,6 +474,12 @@ public void onReceiveValue(String value) { } result.success(true); break; + case requestFocus: + if (webView != null) { + webView.requestFocus(); + } + result.success(true); + break; case setContextMenu: if (webView != null) { Map contextMenu = (Map) call.argument("contextMenu"); diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegateMethods.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegateMethods.java index 3c6d6ae1f..d2a4b5e8e 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegateMethods.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegateMethods.java @@ -62,6 +62,7 @@ public enum WebViewChannelDelegateMethods { saveWebArchive, zoomIn, zoomOut, + requestFocus, clearFocus, setContextMenu, requestFocusNodeHref, diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart index ceb4bc9a9..1d5c37408 100644 --- a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart @@ -2241,6 +2241,12 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController return InAppWebViewHitTestResult(type: type, extra: extra); } + @override + Future requestFocus() async { + Map args = {}; + return await channel?.invokeMethod('requestFocus', args); + } + @override Future clearFocus() async { Map args = {}; diff --git a/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift b/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift index 25dee18da..b69eb02a2 100755 --- a/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift @@ -3129,6 +3129,10 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { public func clearFocus() { self.scrollView.subviews.first?.resignFirstResponder() } + + public func requestFocus() { + self.scrollView.subviews.first?.becomeFirstResponder() + } public func getCertificate() -> SslCertificate? { guard let scheme = url?.scheme, diff --git a/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift b/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift index 46bab6d05..6948d17c3 100644 --- a/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -348,6 +348,10 @@ public class WebViewChannelDelegate: ChannelDelegate { webView?.clearFocus() result(true) break + case .requestFocus: + webView?.requestFocus() + result(true) + break case .setContextMenu: if let webView = webView { let contextMenu = arguments!["contextMenu"] as? [String: Any] diff --git a/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegateMethods.swift b/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegateMethods.swift index 899cd769b..e05f37306 100644 --- a/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegateMethods.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegateMethods.swift @@ -59,6 +59,7 @@ public enum WebViewChannelDelegateMethods: String { case getSelectedText = "getSelectedText" case getHitTestResult = "getHitTestResult" case clearFocus = "clearFocus" + case requestFocus = "requestFocus" case setContextMenu = "setContextMenu" case requestFocusNodeHref = "requestFocusNodeHref" case requestImageRef = "requestImageRef" diff --git a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart index 7e847f14f..d9fb63dd1 100644 --- a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart @@ -2234,6 +2234,12 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController return await channel?.invokeMethod('clearFocus', args); } + @override + Future requestFocus() async { + Map args = {}; + return await channel?.invokeMethod('requestFocus', args); + } + @override Future setContextMenu(ContextMenu? contextMenu) async { Map args = {}; 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 b027eb8d9..631fe1428 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 @@ -1045,6 +1045,11 @@ abstract class PlatformInAppWebViewController extends PlatformInterface 'getHitTestResult is not implemented on the current platform'); } + Future requestFocus() { + throw UnimplementedError( + 'requestFocus is not implemented on the current platform'); + } + ///{@template flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearFocus} ///Clears the current focus. On iOS and Android native WebView, it will clear also, for example, the current text selection. /// From 4f5919242155d7d3072302cecb9bf5c235b9b1cb Mon Sep 17 00:00:00 2001 From: Doflatango Date: Mon, 8 Jul 2024 23:03:39 +0800 Subject: [PATCH 005/137] Android: implemented PlatformPrintJobController.onComplete --- .../print_job/PrintJobChannelDelegate.java | 4 ++ .../print_job/PrintJobController.java | 15 ++++-- .../webview/in_app_webview/InAppWebView.java | 50 +++++++++++++++++-- .../src/print_job/print_job_controller.dart | 3 ++ .../platform_print_job_controller.dart | 1 + 5 files changed, 64 insertions(+), 9 deletions(-) diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobChannelDelegate.java index 1a2165670..b15717f8c 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobChannelDelegate.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobChannelDelegate.java @@ -62,6 +62,10 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result } } + public void onComplete() { + getChannel().invokeMethod("onComplete", null); + } + @Override public void dispose() { super.dispose(); diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobController.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobController.java index 2283e44f6..985dfd994 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobController.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/print_job/PrintJobController.java @@ -28,16 +28,19 @@ public class PrintJobController implements Disposable { @Nullable public PrintJobSettings settings; - public PrintJobController(@NonNull String id, @NonNull android.print.PrintJob job, - @Nullable PrintJobSettings settings, @NonNull InAppWebViewFlutterPlugin plugin) { + public PrintJobController(@NonNull String id, @Nullable PrintJobSettings settings, + @NonNull InAppWebViewFlutterPlugin plugin) { this.id = id; this.plugin = plugin; - this.job = job; this.settings = settings; final MethodChannel channel = new MethodChannel(plugin.messenger, METHOD_CHANNEL_NAME_PREFIX + id); this.channelDelegate = new PrintJobChannelDelegate(this, channel); } - + + public void setJob(@Nullable android.print.PrintJob job) { + this.job = job; + } + public void cancel() { if (this.job != null) { this.job.cancel(); @@ -93,4 +96,8 @@ public void dispose() { } plugin = null; } + + public void onComplete() { + if (channelDelegate != null) channelDelegate.onComplete(); + } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java index bde634bb7..a5fe4ccab 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java @@ -17,9 +17,12 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.print.PageRange; import android.print.PrintAttributes; import android.print.PrintDocumentAdapter; import android.print.PrintManager; @@ -1403,6 +1406,37 @@ public void setDesktopMode(final boolean enabled) { webSettings.setBuiltInZoomControls(enabled); } + interface PrintDocumentAdapterWrapperCallback { + void onFinish(); + } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + class PrintDocumentAdapterWrapper extends PrintDocumentAdapter { + @NonNull PrintDocumentAdapter delegate; + @Nullable PrintDocumentAdapterWrapperCallback callback; + + PrintDocumentAdapterWrapper(@NonNull PrintDocumentAdapter delegate, @Nullable PrintDocumentAdapterWrapperCallback callback) { + this.delegate = delegate; + this.callback = callback; + } + + @Override + public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) { + this.delegate.onLayout(oldAttributes, newAttributes, cancellationSignal, callback, extras); + } + + @Override + public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) { + this.delegate.onWrite(pages, destination, cancellationSignal, callback); + } + + @Override + public void onFinish() { + this.delegate.onFinish(); + if (this.callback != null) this.callback.onFinish(); + } + } + @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Nullable public String printCurrentPage(@Nullable PrintJobSettings settings) { @@ -1458,15 +1492,21 @@ public String printCurrentPage(@Nullable PrintJobSettings settings) { printAdapter = createPrintDocumentAdapter(); } - // Create a printCurrentPage job with name and adapter instance - android.print.PrintJob job = printManager.print(jobName, printAdapter, builder.build()); + PrintJobController printJobController = null; + String id = null; if (settings != null && settings.handledByClient && plugin.printJobManager != null) { - String id = UUID.randomUUID().toString(); - PrintJobController printJobController = new PrintJobController(id, job, settings, plugin); + id = UUID.randomUUID().toString(); + printJobController = new PrintJobController(id, settings, plugin); plugin.printJobManager.jobs.put(printJobController.id, printJobController); - return id; + printAdapter = new PrintDocumentAdapterWrapper(printAdapter, printJobController::onComplete); } + + // Create a printCurrentPage job with name and adapter instance + android.print.PrintJob job = printManager.print(jobName, printAdapter, builder.build()); + if (printJobController != null) printJobController.setJob(job); + + return id; } else { Log.e(LOG_TAG, "No PrintManager available"); } diff --git a/flutter_inappwebview_android/lib/src/print_job/print_job_controller.dart b/flutter_inappwebview_android/lib/src/print_job/print_job_controller.dart index 768311549..4ed0acb58 100644 --- a/flutter_inappwebview_android/lib/src/print_job/print_job_controller.dart +++ b/flutter_inappwebview_android/lib/src/print_job/print_job_controller.dart @@ -43,6 +43,9 @@ class AndroidPrintJobController extends PlatformPrintJobController Future _handleMethod(MethodCall call) async { switch (call.method) { + case "onComplete": + onComplete?.call(true, null); + break; default: throw UnimplementedError("Unimplemented ${call.method} method"); } diff --git a/flutter_inappwebview_platform_interface/lib/src/print_job/platform_print_job_controller.dart b/flutter_inappwebview_platform_interface/lib/src/print_job/platform_print_job_controller.dart index e2abce439..bd4ff6f8e 100644 --- a/flutter_inappwebview_platform_interface/lib/src/print_job/platform_print_job_controller.dart +++ b/flutter_inappwebview_platform_interface/lib/src/print_job/platform_print_job_controller.dart @@ -73,6 +73,7 @@ abstract class PlatformPrintJobController extends PlatformInterface ///A completion handler used to handle the conclusion of the print job (for instance, to reset state) and to handle any errors encountered in printing. /// ///**Officially Supported Platforms/Implementations**: + ///- Android ([Official API - PrintDocumentAdapter.onFinish](https://developer.android.com/reference/android/print/PrintDocumentAdapter#onFinish())) ///- iOS ([Official API - UIPrintInteractionController.CompletionHandler](https://developer.apple.com/documentation/uikit/uiprintinteractioncontroller/completionhandler)) ///- MacOS ([Official API - NSPrintOperation.runModal](https://developer.apple.com/documentation/appkit/nsprintoperation/1532065-runmodal)) ///{@endtemplate} From 36eb8cb7bf9eca75672ef8f54afb26408a857097 Mon Sep 17 00:00:00 2001 From: p-mazhnik Date: Thu, 16 May 2024 13:21:07 +0300 Subject: [PATCH 006/137] [web] support iframe role attribute --- .../src/in_app_webview/in_app_webview_settings.dart | 11 +++++++++++ .../in_app_webview/in_app_webview_settings.g.dart | 13 +++++++++++-- .../lib/web/in_app_web_view_web_element.dart | 4 ++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart index f12b274ce..2d86c8268 100755 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart @@ -1652,6 +1652,16 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri ]) String? iframeCsp; + ///A string that reflects the `role` HTML attribute, containing a WAI-ARIA role for the element. + @SupportedPlatforms(platforms: [ + WebPlatform( + requiresSameOrigin: false, + apiName: "iframe.role", + apiUrl: + "https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles") + ]) + String? iframeRole; + @ExchangeableObjectConstructor() InAppWebViewSettings_({ this.useShouldOverrideUrlLoading, @@ -1794,6 +1804,7 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri this.iframeReferrerPolicy, this.iframeName, this.iframeCsp, + this.iframeRole, }) { if (this.minimumFontSize == null) this.minimumFontSize = Util.isAndroid ? 8 : 0; diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart index 7c30031d1..311cc0017 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart @@ -557,6 +557,12 @@ class InAppWebViewSettings { ///- Web ([Official API - iframe.referrerpolicy](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-referrerpolicy)) ReferrerPolicy? iframeReferrerPolicy; + ///A string that reflects the `role` HTML attribute, containing a WAI-ARIA role for the element. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Web ([Official API - iframe.role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles)) + String? iframeRole; + ///Applies extra restrictions to the content in the frame. /// ///**Officially Supported Platforms/Implementations**: @@ -1338,7 +1344,8 @@ class InAppWebViewSettings { this.iframeSandbox, this.iframeReferrerPolicy, this.iframeName, - this.iframeCsp}) { + this.iframeCsp, + this.iframeRole}) { if (this.minimumFontSize == null) this.minimumFontSize = Util.isAndroid ? 8 : 0; assert(this.resourceCustomSchemes == null || @@ -1389,6 +1396,7 @@ class InAppWebViewSettings { iframeName: map['iframeName'], iframeReferrerPolicy: ReferrerPolicy.fromNativeValue(map['iframeReferrerPolicy']), + iframeRole: map['iframeRole'], iframeSandbox: map['iframeSandbox'] != null ? Set.from( map['iframeSandbox'].map((e) => Sandbox.fromNativeValue(e)!)) @@ -1640,6 +1648,7 @@ class InAppWebViewSettings { "iframeCsp": iframeCsp, "iframeName": iframeName, "iframeReferrerPolicy": iframeReferrerPolicy?.toNativeValue(), + "iframeRole": iframeRole, "iframeSandbox": iframeSandbox?.map((e) => e.toNativeValue()).toList(), "ignoresViewportScaleLimits": ignoresViewportScaleLimits, "incognito": incognito, @@ -1732,6 +1741,6 @@ class InAppWebViewSettings { @override String toString() { - return 'InAppWebViewSettings{accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowingReadAccessTo: $allowingReadAccessTo, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsLinkPreview: $allowsLinkPreview, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, alwaysBounceHorizontal: $alwaysBounceHorizontal, alwaysBounceVertical: $alwaysBounceVertical, appCachePath: $appCachePath, applePayAPIEnabled: $applePayAPIEnabled, applicationNameForUserAgent: $applicationNameForUserAgent, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, builtInZoomControls: $builtInZoomControls, cacheEnabled: $cacheEnabled, cacheMode: $cacheMode, contentBlockers: $contentBlockers, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, cursiveFontFamily: $cursiveFontFamily, dataDetectorTypes: $dataDetectorTypes, databaseEnabled: $databaseEnabled, decelerationRate: $decelerationRate, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, defaultVideoPoster: $defaultVideoPoster, disableContextMenu: $disableContextMenu, disableDefaultErrorPage: $disableDefaultErrorPage, disableHorizontalScroll: $disableHorizontalScroll, disableInputAccessoryView: $disableInputAccessoryView, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableVerticalScroll: $disableVerticalScroll, disabledActionModeMenuItems: $disabledActionModeMenuItems, disallowOverScroll: $disallowOverScroll, displayZoomControls: $displayZoomControls, domStorageEnabled: $domStorageEnabled, enableViewportScale: $enableViewportScale, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, forceDark: $forceDark, forceDarkStrategy: $forceDarkStrategy, geolocationEnabled: $geolocationEnabled, hardwareAcceleration: $hardwareAcceleration, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeCsp: $iframeCsp, iframeName: $iframeName, iframeReferrerPolicy: $iframeReferrerPolicy, iframeSandbox: $iframeSandbox, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, incognito: $incognito, initialScale: $initialScale, interceptOnlyAsyncAjaxRequests: $interceptOnlyAsyncAjaxRequests, isDirectionalLockEnabled: $isDirectionalLockEnabled, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, isInspectable: $isInspectable, isPagingEnabled: $isPagingEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, isTextInteractionEnabled: $isTextInteractionEnabled, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, javaScriptEnabled: $javaScriptEnabled, layoutAlgorithm: $layoutAlgorithm, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, maximumViewportInset: $maximumViewportInset, maximumZoomScale: $maximumZoomScale, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, mediaType: $mediaType, minimumFontSize: $minimumFontSize, minimumLogicalFontSize: $minimumLogicalFontSize, minimumViewportInset: $minimumViewportInset, minimumZoomScale: $minimumZoomScale, mixedContentMode: $mixedContentMode, needInitialFocus: $needInitialFocus, networkAvailable: $networkAvailable, offscreenPreRaster: $offscreenPreRaster, overScrollMode: $overScrollMode, pageZoom: $pageZoom, preferredContentMode: $preferredContentMode, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading, rendererPriorityPolicy: $rendererPriorityPolicy, requestedWithHeaderOriginAllowList: $requestedWithHeaderOriginAllowList, resourceCustomSchemes: $resourceCustomSchemes, safeBrowsingEnabled: $safeBrowsingEnabled, sansSerifFontFamily: $sansSerifFontFamily, saveFormData: $saveFormData, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollBarFadeDuration: $scrollBarFadeDuration, scrollBarStyle: $scrollBarStyle, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollsToTop: $scrollsToTop, selectionGranularity: $selectionGranularity, serifFontFamily: $serifFontFamily, sharedCookiesEnabled: $sharedCookiesEnabled, shouldPrintBackgrounds: $shouldPrintBackgrounds, standardFontFamily: $standardFontFamily, supportMultipleWindows: $supportMultipleWindows, supportZoom: $supportZoom, suppressesIncrementalRendering: $suppressesIncrementalRendering, textZoom: $textZoom, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, transparentBackground: $transparentBackground, underPageBackgroundColor: $underPageBackgroundColor, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, useHybridComposition: $useHybridComposition, useOnDownloadStart: $useOnDownloadStart, useOnLoadResource: $useOnLoadResource, useOnNavigationResponse: $useOnNavigationResponse, useOnRenderProcessGone: $useOnRenderProcessGone, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, useShouldInterceptRequest: $useShouldInterceptRequest, useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useWideViewPort: $useWideViewPort, userAgent: $userAgent, verticalScrollBarEnabled: $verticalScrollBarEnabled, verticalScrollbarPosition: $verticalScrollbarPosition, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, webViewAssetLoader: $webViewAssetLoader}'; + return 'InAppWebViewSettings{accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowingReadAccessTo: $allowingReadAccessTo, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsLinkPreview: $allowsLinkPreview, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, alwaysBounceHorizontal: $alwaysBounceHorizontal, alwaysBounceVertical: $alwaysBounceVertical, appCachePath: $appCachePath, applePayAPIEnabled: $applePayAPIEnabled, applicationNameForUserAgent: $applicationNameForUserAgent, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, builtInZoomControls: $builtInZoomControls, cacheEnabled: $cacheEnabled, cacheMode: $cacheMode, contentBlockers: $contentBlockers, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, cursiveFontFamily: $cursiveFontFamily, dataDetectorTypes: $dataDetectorTypes, databaseEnabled: $databaseEnabled, decelerationRate: $decelerationRate, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, defaultVideoPoster: $defaultVideoPoster, disableContextMenu: $disableContextMenu, disableDefaultErrorPage: $disableDefaultErrorPage, disableHorizontalScroll: $disableHorizontalScroll, disableInputAccessoryView: $disableInputAccessoryView, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableVerticalScroll: $disableVerticalScroll, disabledActionModeMenuItems: $disabledActionModeMenuItems, disallowOverScroll: $disallowOverScroll, displayZoomControls: $displayZoomControls, domStorageEnabled: $domStorageEnabled, enableViewportScale: $enableViewportScale, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, forceDark: $forceDark, forceDarkStrategy: $forceDarkStrategy, geolocationEnabled: $geolocationEnabled, hardwareAcceleration: $hardwareAcceleration, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeCsp: $iframeCsp, iframeName: $iframeName, iframeReferrerPolicy: $iframeReferrerPolicy, iframeRole: $iframeRole, iframeSandbox: $iframeSandbox, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, incognito: $incognito, initialScale: $initialScale, interceptOnlyAsyncAjaxRequests: $interceptOnlyAsyncAjaxRequests, isDirectionalLockEnabled: $isDirectionalLockEnabled, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, isInspectable: $isInspectable, isPagingEnabled: $isPagingEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, isTextInteractionEnabled: $isTextInteractionEnabled, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, javaScriptEnabled: $javaScriptEnabled, layoutAlgorithm: $layoutAlgorithm, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, maximumViewportInset: $maximumViewportInset, maximumZoomScale: $maximumZoomScale, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, mediaType: $mediaType, minimumFontSize: $minimumFontSize, minimumLogicalFontSize: $minimumLogicalFontSize, minimumViewportInset: $minimumViewportInset, minimumZoomScale: $minimumZoomScale, mixedContentMode: $mixedContentMode, needInitialFocus: $needInitialFocus, networkAvailable: $networkAvailable, offscreenPreRaster: $offscreenPreRaster, overScrollMode: $overScrollMode, pageZoom: $pageZoom, preferredContentMode: $preferredContentMode, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading, rendererPriorityPolicy: $rendererPriorityPolicy, requestedWithHeaderOriginAllowList: $requestedWithHeaderOriginAllowList, resourceCustomSchemes: $resourceCustomSchemes, safeBrowsingEnabled: $safeBrowsingEnabled, sansSerifFontFamily: $sansSerifFontFamily, saveFormData: $saveFormData, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollBarFadeDuration: $scrollBarFadeDuration, scrollBarStyle: $scrollBarStyle, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollsToTop: $scrollsToTop, selectionGranularity: $selectionGranularity, serifFontFamily: $serifFontFamily, sharedCookiesEnabled: $sharedCookiesEnabled, shouldPrintBackgrounds: $shouldPrintBackgrounds, standardFontFamily: $standardFontFamily, supportMultipleWindows: $supportMultipleWindows, supportZoom: $supportZoom, suppressesIncrementalRendering: $suppressesIncrementalRendering, textZoom: $textZoom, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, transparentBackground: $transparentBackground, underPageBackgroundColor: $underPageBackgroundColor, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, useHybridComposition: $useHybridComposition, useOnDownloadStart: $useOnDownloadStart, useOnLoadResource: $useOnLoadResource, useOnNavigationResponse: $useOnNavigationResponse, useOnRenderProcessGone: $useOnRenderProcessGone, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, useShouldInterceptRequest: $useShouldInterceptRequest, useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useWideViewPort: $useWideViewPort, userAgent: $userAgent, verticalScrollBarEnabled: $verticalScrollBarEnabled, verticalScrollbarPosition: $verticalScrollbarPosition, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, webViewAssetLoader: $webViewAssetLoader}'; } } diff --git a/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart b/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart index 2e9a114f6..fb20618e7 100644 --- a/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart +++ b/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart @@ -230,6 +230,7 @@ class InAppWebViewWebElement implements Disposable { iframe.referrerPolicy; iframe.name = settings!.iframeName ?? iframe.name; iframe.csp = settings!.iframeCsp ?? iframe.csp; + iframe.role = settings!.iframeRole ?? iframe.role; if (settings!.iframeSandbox != null && settings!.iframeSandbox != Sandbox.ALLOW_ALL) { @@ -470,6 +471,9 @@ class InAppWebViewWebElement implements Disposable { if (settings!.iframeCsp != newSettings.iframeCsp) { iframe.csp = newSettings.iframeCsp; } + if (settings!.iframeRole != newSettings.iframeRole) { + iframe.role = newSettings.iframeRole; + } if (settings!.iframeSandbox != newSettings.iframeSandbox) { var sandbox = newSettings.iframeSandbox; From abb5eec9813bc733b0504949b69115fa69498df0 Mon Sep 17 00:00:00 2001 From: p-mazhnik Date: Tue, 28 May 2024 11:54:13 +0300 Subject: [PATCH 007/137] [web] support iframe aria-hidden attribute --- .../src/in_app_webview/in_app_webview_settings.dart | 10 ++++++++++ .../in_app_webview/in_app_webview_settings.g.dart | 12 ++++++++++-- .../lib/web/in_app_web_view_web_element.dart | 4 ++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart index 2d86c8268..08bd07c18 100755 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart @@ -1662,6 +1662,15 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri ]) String? iframeRole; + @SupportedPlatforms(platforms: [ + WebPlatform( + requiresSameOrigin: false, + apiName: "iframe.ariaHidden", + apiUrl: + "https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-hidden") + ]) + String? iframeAriaHidden; + @ExchangeableObjectConstructor() InAppWebViewSettings_({ this.useShouldOverrideUrlLoading, @@ -1805,6 +1814,7 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri this.iframeName, this.iframeCsp, this.iframeRole, + this.iframeAriaHidden, }) { if (this.minimumFontSize == null) this.minimumFontSize = Util.isAndroid ? 8 : 0; diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart index 311cc0017..bcaaed99f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart @@ -539,6 +539,11 @@ class InAppWebViewSettings { ///- Web ([Official API - iframe.allowfullscreen](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allowfullscreen)) bool? iframeAllowFullscreen; + /// + ///**Officially Supported Platforms/Implementations**: + ///- Web ([Official API - iframe.ariaHidden](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-hidden)) + String? iframeAriaHidden; + ///A Content Security Policy enforced for the embedded resource. /// ///**Officially Supported Platforms/Implementations**: @@ -1345,7 +1350,8 @@ class InAppWebViewSettings { this.iframeReferrerPolicy, this.iframeName, this.iframeCsp, - this.iframeRole}) { + this.iframeRole, + this.iframeAriaHidden}) { if (this.minimumFontSize == null) this.minimumFontSize = Util.isAndroid ? 8 : 0; assert(this.resourceCustomSchemes == null || @@ -1392,6 +1398,7 @@ class InAppWebViewSettings { : null, iframeAllow: map['iframeAllow'], iframeAllowFullscreen: map['iframeAllowFullscreen'], + iframeAriaHidden: map['iframeAriaHidden'], iframeCsp: map['iframeCsp'], iframeName: map['iframeName'], iframeReferrerPolicy: @@ -1645,6 +1652,7 @@ class InAppWebViewSettings { "horizontalScrollbarTrackColor": horizontalScrollbarTrackColor?.toHex(), "iframeAllow": iframeAllow, "iframeAllowFullscreen": iframeAllowFullscreen, + "iframeAriaHidden": iframeAriaHidden, "iframeCsp": iframeCsp, "iframeName": iframeName, "iframeReferrerPolicy": iframeReferrerPolicy?.toNativeValue(), @@ -1741,6 +1749,6 @@ class InAppWebViewSettings { @override String toString() { - return 'InAppWebViewSettings{accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowingReadAccessTo: $allowingReadAccessTo, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsLinkPreview: $allowsLinkPreview, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, alwaysBounceHorizontal: $alwaysBounceHorizontal, alwaysBounceVertical: $alwaysBounceVertical, appCachePath: $appCachePath, applePayAPIEnabled: $applePayAPIEnabled, applicationNameForUserAgent: $applicationNameForUserAgent, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, builtInZoomControls: $builtInZoomControls, cacheEnabled: $cacheEnabled, cacheMode: $cacheMode, contentBlockers: $contentBlockers, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, cursiveFontFamily: $cursiveFontFamily, dataDetectorTypes: $dataDetectorTypes, databaseEnabled: $databaseEnabled, decelerationRate: $decelerationRate, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, defaultVideoPoster: $defaultVideoPoster, disableContextMenu: $disableContextMenu, disableDefaultErrorPage: $disableDefaultErrorPage, disableHorizontalScroll: $disableHorizontalScroll, disableInputAccessoryView: $disableInputAccessoryView, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableVerticalScroll: $disableVerticalScroll, disabledActionModeMenuItems: $disabledActionModeMenuItems, disallowOverScroll: $disallowOverScroll, displayZoomControls: $displayZoomControls, domStorageEnabled: $domStorageEnabled, enableViewportScale: $enableViewportScale, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, forceDark: $forceDark, forceDarkStrategy: $forceDarkStrategy, geolocationEnabled: $geolocationEnabled, hardwareAcceleration: $hardwareAcceleration, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeCsp: $iframeCsp, iframeName: $iframeName, iframeReferrerPolicy: $iframeReferrerPolicy, iframeRole: $iframeRole, iframeSandbox: $iframeSandbox, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, incognito: $incognito, initialScale: $initialScale, interceptOnlyAsyncAjaxRequests: $interceptOnlyAsyncAjaxRequests, isDirectionalLockEnabled: $isDirectionalLockEnabled, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, isInspectable: $isInspectable, isPagingEnabled: $isPagingEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, isTextInteractionEnabled: $isTextInteractionEnabled, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, javaScriptEnabled: $javaScriptEnabled, layoutAlgorithm: $layoutAlgorithm, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, maximumViewportInset: $maximumViewportInset, maximumZoomScale: $maximumZoomScale, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, mediaType: $mediaType, minimumFontSize: $minimumFontSize, minimumLogicalFontSize: $minimumLogicalFontSize, minimumViewportInset: $minimumViewportInset, minimumZoomScale: $minimumZoomScale, mixedContentMode: $mixedContentMode, needInitialFocus: $needInitialFocus, networkAvailable: $networkAvailable, offscreenPreRaster: $offscreenPreRaster, overScrollMode: $overScrollMode, pageZoom: $pageZoom, preferredContentMode: $preferredContentMode, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading, rendererPriorityPolicy: $rendererPriorityPolicy, requestedWithHeaderOriginAllowList: $requestedWithHeaderOriginAllowList, resourceCustomSchemes: $resourceCustomSchemes, safeBrowsingEnabled: $safeBrowsingEnabled, sansSerifFontFamily: $sansSerifFontFamily, saveFormData: $saveFormData, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollBarFadeDuration: $scrollBarFadeDuration, scrollBarStyle: $scrollBarStyle, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollsToTop: $scrollsToTop, selectionGranularity: $selectionGranularity, serifFontFamily: $serifFontFamily, sharedCookiesEnabled: $sharedCookiesEnabled, shouldPrintBackgrounds: $shouldPrintBackgrounds, standardFontFamily: $standardFontFamily, supportMultipleWindows: $supportMultipleWindows, supportZoom: $supportZoom, suppressesIncrementalRendering: $suppressesIncrementalRendering, textZoom: $textZoom, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, transparentBackground: $transparentBackground, underPageBackgroundColor: $underPageBackgroundColor, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, useHybridComposition: $useHybridComposition, useOnDownloadStart: $useOnDownloadStart, useOnLoadResource: $useOnLoadResource, useOnNavigationResponse: $useOnNavigationResponse, useOnRenderProcessGone: $useOnRenderProcessGone, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, useShouldInterceptRequest: $useShouldInterceptRequest, useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useWideViewPort: $useWideViewPort, userAgent: $userAgent, verticalScrollBarEnabled: $verticalScrollBarEnabled, verticalScrollbarPosition: $verticalScrollbarPosition, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, webViewAssetLoader: $webViewAssetLoader}'; + return 'InAppWebViewSettings{accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowingReadAccessTo: $allowingReadAccessTo, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsLinkPreview: $allowsLinkPreview, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, alwaysBounceHorizontal: $alwaysBounceHorizontal, alwaysBounceVertical: $alwaysBounceVertical, appCachePath: $appCachePath, applePayAPIEnabled: $applePayAPIEnabled, applicationNameForUserAgent: $applicationNameForUserAgent, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, builtInZoomControls: $builtInZoomControls, cacheEnabled: $cacheEnabled, cacheMode: $cacheMode, contentBlockers: $contentBlockers, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, cursiveFontFamily: $cursiveFontFamily, dataDetectorTypes: $dataDetectorTypes, databaseEnabled: $databaseEnabled, decelerationRate: $decelerationRate, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, defaultVideoPoster: $defaultVideoPoster, disableContextMenu: $disableContextMenu, disableDefaultErrorPage: $disableDefaultErrorPage, disableHorizontalScroll: $disableHorizontalScroll, disableInputAccessoryView: $disableInputAccessoryView, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableVerticalScroll: $disableVerticalScroll, disabledActionModeMenuItems: $disabledActionModeMenuItems, disallowOverScroll: $disallowOverScroll, displayZoomControls: $displayZoomControls, domStorageEnabled: $domStorageEnabled, enableViewportScale: $enableViewportScale, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, forceDark: $forceDark, forceDarkStrategy: $forceDarkStrategy, geolocationEnabled: $geolocationEnabled, hardwareAcceleration: $hardwareAcceleration, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeAriaHidden: $iframeAriaHidden, iframeCsp: $iframeCsp, iframeName: $iframeName, iframeReferrerPolicy: $iframeReferrerPolicy, iframeRole: $iframeRole, iframeSandbox: $iframeSandbox, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, incognito: $incognito, initialScale: $initialScale, interceptOnlyAsyncAjaxRequests: $interceptOnlyAsyncAjaxRequests, isDirectionalLockEnabled: $isDirectionalLockEnabled, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, isInspectable: $isInspectable, isPagingEnabled: $isPagingEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, isTextInteractionEnabled: $isTextInteractionEnabled, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, javaScriptEnabled: $javaScriptEnabled, layoutAlgorithm: $layoutAlgorithm, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, maximumViewportInset: $maximumViewportInset, maximumZoomScale: $maximumZoomScale, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, mediaType: $mediaType, minimumFontSize: $minimumFontSize, minimumLogicalFontSize: $minimumLogicalFontSize, minimumViewportInset: $minimumViewportInset, minimumZoomScale: $minimumZoomScale, mixedContentMode: $mixedContentMode, needInitialFocus: $needInitialFocus, networkAvailable: $networkAvailable, offscreenPreRaster: $offscreenPreRaster, overScrollMode: $overScrollMode, pageZoom: $pageZoom, preferredContentMode: $preferredContentMode, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading, rendererPriorityPolicy: $rendererPriorityPolicy, requestedWithHeaderOriginAllowList: $requestedWithHeaderOriginAllowList, resourceCustomSchemes: $resourceCustomSchemes, safeBrowsingEnabled: $safeBrowsingEnabled, sansSerifFontFamily: $sansSerifFontFamily, saveFormData: $saveFormData, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollBarFadeDuration: $scrollBarFadeDuration, scrollBarStyle: $scrollBarStyle, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollsToTop: $scrollsToTop, selectionGranularity: $selectionGranularity, serifFontFamily: $serifFontFamily, sharedCookiesEnabled: $sharedCookiesEnabled, shouldPrintBackgrounds: $shouldPrintBackgrounds, standardFontFamily: $standardFontFamily, supportMultipleWindows: $supportMultipleWindows, supportZoom: $supportZoom, suppressesIncrementalRendering: $suppressesIncrementalRendering, textZoom: $textZoom, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, transparentBackground: $transparentBackground, underPageBackgroundColor: $underPageBackgroundColor, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, useHybridComposition: $useHybridComposition, useOnDownloadStart: $useOnDownloadStart, useOnLoadResource: $useOnLoadResource, useOnNavigationResponse: $useOnNavigationResponse, useOnRenderProcessGone: $useOnRenderProcessGone, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, useShouldInterceptRequest: $useShouldInterceptRequest, useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useWideViewPort: $useWideViewPort, userAgent: $userAgent, verticalScrollBarEnabled: $verticalScrollBarEnabled, verticalScrollbarPosition: $verticalScrollbarPosition, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, webViewAssetLoader: $webViewAssetLoader}'; } } diff --git a/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart b/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart index fb20618e7..3bf38f34c 100644 --- a/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart +++ b/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart @@ -231,6 +231,7 @@ class InAppWebViewWebElement implements Disposable { iframe.name = settings!.iframeName ?? iframe.name; iframe.csp = settings!.iframeCsp ?? iframe.csp; iframe.role = settings!.iframeRole ?? iframe.role; + iframe.ariaHidden = settings!.iframeAriaHidden ?? iframe.ariaHidden; if (settings!.iframeSandbox != null && settings!.iframeSandbox != Sandbox.ALLOW_ALL) { @@ -474,6 +475,9 @@ class InAppWebViewWebElement implements Disposable { if (settings!.iframeRole != newSettings.iframeRole) { iframe.role = newSettings.iframeRole; } + if (settings!.iframeAriaHidden != newSettings.iframeAriaHidden) { + iframe.ariaHidden = newSettings.iframeAriaHidden; + } if (settings!.iframeSandbox != newSettings.iframeSandbox) { var sandbox = newSettings.iframeSandbox; From 6a0c1927bd439ee206b6222a0d6ab2cd25b14a6f Mon Sep 17 00:00:00 2001 From: nnnlog Date: Thu, 3 Oct 2024 23:50:44 +0900 Subject: [PATCH 008/137] change priority of DispatchQueue --- .../ios/Classes/InAppWebView/InAppWebView.swift | 4 ++-- .../ios/Classes/InAppWebView/WebViewChannelDelegate.swift | 8 ++++---- .../macos/Classes/InAppWebView/InAppWebView.swift | 4 ++-- .../Classes/InAppWebView/WebViewChannelDelegate.swift | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift b/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift index 43ac03776..788795159 100755 --- a/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift @@ -2072,7 +2072,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, if let scheme = challenge.protectionSpace.protocol, scheme == "https" { // workaround for ProtectionSpace SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { if let sslCertificate = challenge.protectionSpace.sslCertificate { DispatchQueue.main.async { InAppWebView.sslCertificatesMap[challenge.protectionSpace.host] = sslCertificate @@ -2092,7 +2092,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, break case 1: // workaround for https://github.com/pichillilorenzo/flutter_inappwebview/issues/1924 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let exceptions = SecTrustCopyExceptions(serverTrust) SecTrustSetExceptions(serverTrust, exceptions) let credential = URLCredential(trust: serverTrust) diff --git a/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift b/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift index 46bab6d05..0f389de04 100644 --- a/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -965,7 +965,7 @@ public class WebViewChannelDelegate: ChannelDelegate { } // workaround for ProtectionSpace.toMap() SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let arguments = challenge.toMap() DispatchQueue.main.async { [weak self] in if self?.channel == nil { @@ -997,7 +997,7 @@ public class WebViewChannelDelegate: ChannelDelegate { } // workaround for ProtectionSpace.toMap() SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let arguments = challenge.toMap() DispatchQueue.main.async { [weak self] in if self?.channel == nil { @@ -1029,7 +1029,7 @@ public class WebViewChannelDelegate: ChannelDelegate { } // workaround for ProtectionSpace.toMap() SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let arguments = challenge.toMap() DispatchQueue.main.async { [weak self] in if self?.channel == nil { @@ -1142,7 +1142,7 @@ public class WebViewChannelDelegate: ChannelDelegate { } // workaround for ProtectionSpace.toMap() SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let arguments = challenge.toMap() DispatchQueue.main.async { [weak self] in if self?.channel == nil { diff --git a/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift index 5e73f981c..3d3e36f40 100755 --- a/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift +++ b/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift @@ -1455,7 +1455,7 @@ public class InAppWebView: WKWebView, WKUIDelegate, if let scheme = challenge.protectionSpace.protocol, scheme == "https" { // workaround for ProtectionSpace SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { if let sslCertificate = challenge.protectionSpace.sslCertificate { DispatchQueue.main.async { InAppWebView.sslCertificatesMap[challenge.protectionSpace.host] = sslCertificate @@ -1475,7 +1475,7 @@ public class InAppWebView: WKWebView, WKUIDelegate, break case 1: // workaround for https://github.com/pichillilorenzo/flutter_inappwebview/issues/1924 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let exceptions = SecTrustCopyExceptions(serverTrust) SecTrustSetExceptions(serverTrust, exceptions) let credential = URLCredential(trust: serverTrust) diff --git a/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift index 9eb906e57..ff36c597d 100644 --- a/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -928,7 +928,7 @@ public class WebViewChannelDelegate: ChannelDelegate { } // workaround for ProtectionSpace.toMap() SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let arguments = challenge.toMap() DispatchQueue.main.async { [weak self] in if self?.channel == nil { @@ -960,7 +960,7 @@ public class WebViewChannelDelegate: ChannelDelegate { } // workaround for ProtectionSpace.toMap() SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let arguments = challenge.toMap() DispatchQueue.main.async { [weak self] in if self?.channel == nil { @@ -992,7 +992,7 @@ public class WebViewChannelDelegate: ChannelDelegate { } // workaround for ProtectionSpace.toMap() SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let arguments = challenge.toMap() DispatchQueue.main.async { [weak self] in if self?.channel == nil { @@ -1105,7 +1105,7 @@ public class WebViewChannelDelegate: ChannelDelegate { } // workaround for ProtectionSpace.toMap() SSL Certificate // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 - DispatchQueue.global(qos: .background).async { + DispatchQueue.global().async { let arguments = challenge.toMap() DispatchQueue.main.async { [weak self] in if self?.channel == nil { From 952aa783912c9b0fd98d01e3c2c707d97512cd63 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Oct 2024 00:00:48 +0200 Subject: [PATCH 009/137] windows: Updated code to support multiple flutter windows --- flutter_inappwebview_windows/CHANGELOG.md | 4 ++ flutter_inappwebview_windows/pubspec.yaml | 2 +- .../windows/cookie_manager.cpp | 2 +- .../custom_platform_view.cc | 13 ++++- .../custom_platform_view.h | 2 + .../flutter_inappwebview_windows_plugin.cpp | 8 ++- .../headless_in_app_webview_manager.cpp | 7 ++- .../headless_webview_channel_delegate.cpp | 6 ++ .../windows/in_app_browser/in_app_browser.cpp | 10 +++- .../in_app_browser/in_app_browser_manager.cpp | 10 +++- .../in_app_webview/in_app_webview_manager.cpp | 58 ++++++++++++------- .../in_app_webview/in_app_webview_manager.h | 12 ++-- .../windows/types/channel_delegate.cpp | 10 +++- .../windows/types/channel_delegate.h | 2 + 14 files changed, 106 insertions(+), 40 deletions(-) diff --git a/flutter_inappwebview_windows/CHANGELOG.md b/flutter_inappwebview_windows/CHANGELOG.md index a1051a195..dd1cc41a6 100644 --- a/flutter_inappwebview_windows/CHANGELOG.md +++ b/flutter_inappwebview_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.0 + +- Updated code to support multiple flutter windows + ## 0.5.0+2 - Fixed `InAppWebViewController.callAsyncJavaScript` not working with JSON objects diff --git a/flutter_inappwebview_windows/pubspec.yaml b/flutter_inappwebview_windows/pubspec.yaml index ed5710fcb..d1c3ce45d 100644 --- a/flutter_inappwebview_windows/pubspec.yaml +++ b/flutter_inappwebview_windows/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_windows description: Windows implementation of the flutter_inappwebview plugin. -version: 0.5.0+2 +version: 0.6.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_windows issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues diff --git a/flutter_inappwebview_windows/windows/cookie_manager.cpp b/flutter_inappwebview_windows/windows/cookie_manager.cpp index 2fa0eb5d3..7ea8750c6 100644 --- a/flutter_inappwebview_windows/windows/cookie_manager.cpp +++ b/flutter_inappwebview_windows/windows/cookie_manager.cpp @@ -25,7 +25,7 @@ namespace flutter_inappwebview_plugin auto webViewEnvironmentId = get_optional_fl_map_value(arguments, "webViewEnvironmentId"); - auto webViewEnvironment = webViewEnvironmentId.has_value() && map_contains(plugin->webViewEnvironmentManager->webViewEnvironments, webViewEnvironmentId.value()) + auto webViewEnvironment = plugin && webViewEnvironmentId.has_value() && map_contains(plugin->webViewEnvironmentManager->webViewEnvironments, webViewEnvironmentId.value()) ? plugin->webViewEnvironmentManager->webViewEnvironments.at(webViewEnvironmentId.value()).get() : nullptr; auto result_ = std::shared_ptr>(std::move(result)); 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 1b6a3ff88..8ce649f4b 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 @@ -186,12 +186,21 @@ namespace flutter_inappwebview_plugin event_channel_->SetStreamHandler(std::move(handler)); } + void CustomPlatformView::UnregisterMethodCallHandler() const + { + if (method_channel_) { + method_channel_->SetMethodCallHandler(nullptr); + if (view && view->channelDelegate) { + view->channelDelegate->UnregisterMethodCallHandler(); + } + } + } + CustomPlatformView::~CustomPlatformView() { debugLog("dealloc CustomPlatformView"); - method_channel_->SetMethodCallHandler(nullptr); event_sink_ = nullptr; - texture_registrar_->UnregisterTexture(texture_id_); + texture_registrar_->UnregisterTexture(texture_id_, nullptr); } void CustomPlatformView::RegisterEventHandlers() diff --git a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.h b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.h index 35946f340..65db5476a 100644 --- a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.h +++ b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.h @@ -29,6 +29,8 @@ namespace flutter_inappwebview_plugin TextureBridge* texture_bridge() const { return texture_bridge_.get(); } int64_t texture_id() const { return texture_id_; } + + void UnregisterMethodCallHandler() const; private: HWND hwnd_; std::unique_ptr flutter_texture_; diff --git a/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.cpp b/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.cpp index a616a89bd..ed1f29fea 100644 --- a/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.cpp +++ b/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.cpp @@ -33,5 +33,11 @@ namespace flutter_inappwebview_plugin } FlutterInappwebviewWindowsPlugin::~FlutterInappwebviewWindowsPlugin() - {} + { + webViewEnvironmentManager = nullptr; + inAppWebViewManager = nullptr; + inAppBrowserManager = nullptr; + headlessInAppWebViewManager = nullptr; + cookieManager = nullptr; + } } \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_in_app_webview_manager.cpp b/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_in_app_webview_manager.cpp index e5ff4c447..a74587d59 100644 --- a/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_in_app_webview_manager.cpp +++ b/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_in_app_webview_manager.cpp @@ -46,6 +46,11 @@ namespace flutter_inappwebview_plugin { auto result_ = std::shared_ptr>(std::move(result)); + if (!plugin) { + result_->Error("0", "Cannot create the HeadlessInAppWebView instance!"); + return; + } + auto id = get_fl_map_value(*arguments, "id"); auto params = get_fl_map_value(*arguments, "params"); @@ -80,7 +85,7 @@ namespace flutter_inappwebview_plugin wil::com_ptr webViewController, wil::com_ptr webViewCompositionController) { - if (webViewEnv && webViewController) { + if (plugin && webViewEnv && webViewController) { std::optional>> initialUserScripts = initialUserScriptList.has_value() ? functional_map(initialUserScriptList.value(), [](const flutter::EncodableValue& map) { return std::make_shared(std::get(map)); }) : std::optional>>{}; diff --git a/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_webview_channel_delegate.cpp b/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_webview_channel_delegate.cpp index 5aadab56c..95099be68 100644 --- a/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_webview_channel_delegate.cpp +++ b/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_webview_channel_delegate.cpp @@ -29,6 +29,12 @@ namespace flutter_inappwebview_plugin std::map>& webViews = webView->plugin->headlessInAppWebViewManager->webViews; auto& id = webView->id; if (map_contains(webViews, id)) { + if (webView->channelDelegate) { + webView->channelDelegate->UnregisterMethodCallHandler(); + if (webView->webView && webView->webView->channelDelegate) { + webView->webView->channelDelegate->UnregisterMethodCallHandler(); + } + } webViews.erase(id); } } 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 ec9ad3900..d85f11102 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 @@ -200,12 +200,18 @@ namespace flutter_inappwebview_plugin if (!destroyed_) { destroyed_ = true; - webView.reset(); - if (channelDelegate) { channelDelegate->onExit(); } + if (channelDelegate) { + channelDelegate->UnregisterMethodCallHandler(); + if (webView && webView->channelDelegate) { + webView->channelDelegate->UnregisterMethodCallHandler(); + } + } + webView.reset(); + if (plugin && plugin->inAppBrowserManager) { plugin->inAppBrowserManager->browsers.erase(id); } 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 461300679..7f210f7bb 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 @@ -25,8 +25,14 @@ namespace flutter_inappwebview_plugin auto& methodName = method_call.method_name(); if (string_equals(methodName, "open")) { - createInAppBrowser(arguments); - result->Success(true); + if (plugin) { + createInAppBrowser(arguments); + result->Success(true); + } + else { + result->Error("0", "Cannot create the InAppBrowser instance!"); + + } } else if (string_equals(methodName, "openWithSystemBrowser")) { auto url = get_fl_map_value(*arguments, "url"); 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 9b6850930..5f025c678 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 @@ -18,29 +18,32 @@ namespace flutter_inappwebview_plugin { InAppWebViewManager::InAppWebViewManager(const FlutterInappwebviewWindowsPlugin* plugin) : plugin(plugin), - ChannelDelegate(plugin->registrar->messenger(), InAppWebViewManager::METHOD_CHANNEL_NAME), - rohelper_(std::make_unique(RO_INIT_SINGLETHREADED)) + ChannelDelegate(plugin->registrar->messenger(), InAppWebViewManager::METHOD_CHANNEL_NAME) { - if (rohelper_->WinRtAvailable()) { - DispatcherQueueOptions options{ sizeof(DispatcherQueueOptions), - DQTYPE_THREAD_CURRENT, DQTAT_COM_STA }; - - if (FAILED(rohelper_->CreateDispatcherQueueController( - options, dispatcher_queue_controller_.put()))) { - std::cerr << "Creating DispatcherQueueController failed." << std::endl; - return; - } + if (!rohelper_) { + rohelper_ = std::make_unique(RO_INIT_SINGLETHREADED); - if (!isGraphicsCaptureSessionSupported()) { - std::cerr << "Windows::Graphics::Capture::GraphicsCaptureSession is not " - "supported." - << std::endl; - return; - } + if (rohelper_->WinRtAvailable()) { + DispatcherQueueOptions options{ sizeof(DispatcherQueueOptions), + DQTYPE_THREAD_CURRENT, DQTAT_COM_STA }; + + if (FAILED(rohelper_->CreateDispatcherQueueController( + options, dispatcher_queue_controller_.put()))) { + std::cerr << "Creating DispatcherQueueController failed." << std::endl; + return; + } + + if (!isGraphicsCaptureSessionSupported()) { + std::cerr << "Windows::Graphics::Capture::GraphicsCaptureSession is not " + "supported." + << std::endl; + return; + } - graphics_context_ = std::make_unique(rohelper_.get()); - compositor_ = graphics_context_->CreateCompositor(); - valid_ = graphics_context_->IsValid(); + graphics_context_ = std::make_unique(rohelper_.get()); + compositor_ = graphics_context_->CreateCompositor(); + valid_ = graphics_context_->IsValid(); + } } windowClass_.lpszClassName = CustomPlatformView::CLASS_NAME; @@ -66,6 +69,10 @@ namespace flutter_inappwebview_plugin else if (string_equals(methodName, "dispose")) { auto id = get_fl_map_value(*arguments, "id"); if (map_contains(webViews, (uint64_t)id)) { + auto platformView = webViews.at(id).get(); + if (platformView) { + platformView->UnregisterMethodCallHandler(); + } webViews.erase(id); } result->Success(); @@ -84,6 +91,11 @@ namespace flutter_inappwebview_plugin { auto result_ = std::shared_ptr>(std::move(result)); + if (!plugin) { + result_->Error("0", "Cannot create the InAppWebView instance!"); + return; + } + auto settingsMap = get_fl_map_value(*arguments, "initialSettings"); auto urlRequestMap = get_optional_fl_map_value(*arguments, "initialUrlRequest"); auto initialFile = get_optional_fl_map_value(*arguments, "initialFile"); @@ -126,7 +138,7 @@ namespace flutter_inappwebview_plugin wil::com_ptr webViewController, wil::com_ptr webViewCompositionController) { - if (webViewEnv && webViewController && webViewCompositionController) { + if (plugin && webViewEnv && webViewController && webViewCompositionController) { std::optional>> initialUserScripts = initialUserScriptList.has_value() ? functional_map(initialUserScriptList.value(), [](const flutter::EncodableValue& map) { return std::make_shared(std::get(map)); }) : std::optional>>{}; @@ -186,6 +198,10 @@ namespace flutter_inappwebview_plugin void InAppWebViewManager::disposeKeepAlive(const std::string& keepAliveId) { if (map_contains(keepAliveWebViews, keepAliveId)) { + auto platformView = keepAliveWebViews.at(keepAliveId).get(); + if (platformView) { + platformView->UnregisterMethodCallHandler(); + } keepAliveWebViews.erase(keepAliveId); } } diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h index f48c799e7..f66d649dd 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h @@ -52,13 +52,13 @@ namespace flutter_inappwebview_plugin void createInAppWebView(const flutter::EncodableMap* arguments, std::unique_ptr> result); void disposeKeepAlive(const std::string& keepAliveId); private: - std::unique_ptr rohelper_; - winrt::com_ptr - dispatcher_queue_controller_; - std::unique_ptr graphics_context_; - winrt::com_ptr compositor_; + inline static std::shared_ptr rohelper_ = nullptr; + inline static winrt::com_ptr + dispatcher_queue_controller_ = nullptr; + inline static std::unique_ptr graphics_context_ = nullptr; + inline static winrt::com_ptr compositor_ = nullptr; WNDCLASS windowClass_ = {}; - bool valid_ = false; + inline static bool valid_ = false; }; } #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_WEBVIEW_MANAGER_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/channel_delegate.cpp b/flutter_inappwebview_windows/windows/types/channel_delegate.cpp index 983a2366f..b5db15048 100644 --- a/flutter_inappwebview_windows/windows/types/channel_delegate.cpp +++ b/flutter_inappwebview_windows/windows/types/channel_delegate.cpp @@ -24,12 +24,16 @@ namespace flutter_inappwebview_plugin std::unique_ptr> result) {} - ChannelDelegate::~ChannelDelegate() + void ChannelDelegate::UnregisterMethodCallHandler() const { - messenger = nullptr; - if (channel != nullptr) { + if (channel) { channel->SetMethodCallHandler(nullptr); } + } + + ChannelDelegate::~ChannelDelegate() + { + messenger = nullptr; channel.reset(); } } \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/channel_delegate.h b/flutter_inappwebview_windows/windows/types/channel_delegate.h index a412b7d10..5ccfdfa12 100644 --- a/flutter_inappwebview_windows/windows/types/channel_delegate.h +++ b/flutter_inappwebview_windows/windows/types/channel_delegate.h @@ -19,6 +19,8 @@ namespace flutter_inappwebview_plugin virtual void HandleMethodCall( const flutter::MethodCall& method_call, std::unique_ptr> result); + + void UnregisterMethodCallHandler() const; }; } From f67ae1f34868c7660c16a2473f53a7a7bfb6f784 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Wed, 9 Oct 2024 00:10:50 +0200 Subject: [PATCH 010/137] updated flutter_inappwebview_windows version to ^0.6.0 --- flutter_inappwebview/CHANGELOG.md | 10 ++++++++++ flutter_inappwebview/pubspec.yaml | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index c74465f00..e9b43100f 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -1,3 +1,13 @@ +## 6.1.5 + +- Updated dependencies to the latest versions for all platform implementations: + - `flutter_inappwebview_windows`: `^0.5.0` -> `^0.6.0` + +#### Windows Platform +- Updated code to support multiple flutter windows +- Fixed `InAppWebViewController.callAsyncJavaScript` not working with JSON objects +- Fixed `onLoadResourceWithCustomScheme` WebView event called every time + ## 6.1.4 - Updated dependencies to the latest versions for all platform implementations: diff --git a/flutter_inappwebview/pubspec.yaml b/flutter_inappwebview/pubspec.yaml index 35b7f83d5..2684b7dae 100755 --- a/flutter_inappwebview/pubspec.yaml +++ b/flutter_inappwebview/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. -version: 6.1.4 +version: 6.1.5 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -25,7 +25,7 @@ dependencies: flutter_inappwebview_ios: ^1.1.2 flutter_inappwebview_macos: ^1.1.2 flutter_inappwebview_web: ^1.1.2 - flutter_inappwebview_windows: ^0.5.0 + flutter_inappwebview_windows: ^0.6.0 dev_dependencies: flutter_test: From 22e492d823ee8d5bbef76d4b15420cb903cb7fa1 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Wed, 23 Oct 2024 12:03:39 +0200 Subject: [PATCH 011/137] platform_interface: Updated static fromMap implementation for some classes, ios and macos: Moved WKUserContentController initialization on preWKWebViewConfiguration to fix possible undefined is not an object (evaluating 'window.webkit.messageHandlers') javascript error --- .../src/exchangeable_object_generator.dart | 8 +++++ flutter_inappwebview/CHANGELOG.md | 19 ++++++++++++ .../example/test/widget_test.dart | 30 ------------------- flutter_inappwebview/pubspec.yaml | 4 +-- flutter_inappwebview_android/CHANGELOG.md | 4 +++ flutter_inappwebview_android/pubspec.yaml | 4 +-- flutter_inappwebview_ios/CHANGELOG.md | 5 ++++ .../Classes/InAppWebView/InAppWebView.swift | 4 +-- flutter_inappwebview_ios/pubspec.yaml | 4 +-- flutter_inappwebview_macos/CHANGELOG.md | 5 ++++ .../Classes/InAppWebView/InAppWebView.swift | 4 +-- flutter_inappwebview_macos/pubspec.yaml | 4 +-- .../CHANGELOG.md | 4 +++ .../chrome_safari_action_button.g.dart | 4 ++- ...me_safari_browser_secondary_toolbar.g.dart | 12 ++++---- .../context_menu/context_menu_settings.g.dart | 6 ++-- .../in_app_browser_menu_item.g.dart | 4 ++- .../lib/src/platform_proxy_controller.g.dart | 20 +++++++++---- .../src/platform_tracing_controller.g.dart | 4 ++- .../lib/src/types/console_message.g.dart | 10 +++++-- .../lib/src/types/content_world.dart | 8 +++++ .../src/types/custom_scheme_response.g.dart | 4 ++- ...ion_permission_show_prompt_response.g.dart | 4 ++- .../lib/src/types/http_auth_response.g.dart | 12 ++++++-- .../types/in_app_webview_initial_data.g.dart | 8 +++-- .../lib/src/types/js_alert_response.g.dart | 12 ++++++-- .../types/js_before_unload_response.g.dart | 16 +++++++--- .../lib/src/types/js_confirm_response.g.dart | 16 +++++++--- .../lib/src/types/js_prompt_response.g.dart | 20 +++++++++---- .../lib/src/types/permission_request.g.dart | 6 ++-- .../lib/src/types/permission_response.g.dart | 10 +++++-- .../src/types/safe_browsing_response.g.dart | 4 ++- .../src/types/screenshot_configuration.g.dart | 14 ++++++--- .../types/script_html_tag_attributes.g.dart | 4 ++- ...web_activity_immersive_display_mode.g.dart | 6 ++-- .../lib/src/types/user_script.g.dart | 15 +++++++--- .../pubspec.yaml | 2 +- flutter_inappwebview_web/CHANGELOG.md | 4 +++ flutter_inappwebview_web/pubspec.yaml | 4 +-- flutter_inappwebview_windows/CHANGELOG.md | 4 +++ .../example/pubspec.lock | 2 +- flutter_inappwebview_windows/pubspec.yaml | 4 +-- 42 files changed, 231 insertions(+), 107 deletions(-) diff --git a/dev_packages/generators/lib/src/exchangeable_object_generator.dart b/dev_packages/generators/lib/src/exchangeable_object_generator.dart index d399aaa12..ed5cb23e9 100644 --- a/dev_packages/generators/lib/src/exchangeable_object_generator.dart +++ b/dev_packages/generators/lib/src/exchangeable_object_generator.dart @@ -335,6 +335,7 @@ class ExchangeableObjectGenerator .trim(); value = "map['$newFieldName']"; } + final mapValue = value; final customDeserializer = _coreCheckerObjectProperty .firstAnnotationOf(fieldElement) @@ -361,7 +362,14 @@ class ExchangeableObjectGenerator if (isRequiredParameter || fieldElement.isFinal || annotation.read("fromMapForceAllInline").boolValue) { requiredFields.add('$fieldName: $value,'); } else { + final isFieldNullable = Util.typeIsNullable(fieldElement.type); + if (!isFieldNullable) { + nonRequiredFields.add("if ($mapValue != null) {"); + } nonRequiredFields.add("instance.$fieldName = $value;"); + if (!isFieldNullable) { + nonRequiredFields.add("}"); + } } } } diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index e9b43100f..631373fae 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -1,3 +1,22 @@ +## 6.2.0 + +- Updated dependencies to the latest versions for all platform implementations: + - `flutter_inappwebview_platform_interface`: `^1.3.0` -> `^1.4.0` + - `flutter_inappwebview_android`: `^1.1.3` -> `^1.2.0` + - `flutter_inappwebview_ios`: `^1.1.2` -> `^1.2.0` + - `flutter_inappwebview_macos`: `^1.1.2` -> `^1.2.0` + - `flutter_inappwebview_web`: `^1.1.2` -> `^1.2.0` + - `flutter_inappwebview_windows`: `^0.6.0` -> `^0.7.0` + +#### Platform Interface +- Updated static `fromMap` implementation for some classes + +#### iOS Platform +- Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error + +#### macOS Platform +- Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error + ## 6.1.5 - Updated dependencies to the latest versions for all platform implementations: diff --git a/flutter_inappwebview/example/test/widget_test.dart b/flutter_inappwebview/example/test/widget_test.dart index 092d222f7..e69de29bb 100644 --- a/flutter_inappwebview/example/test/widget_test.dart +++ b/flutter_inappwebview/example/test/widget_test.dart @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/flutter_inappwebview/pubspec.yaml b/flutter_inappwebview/pubspec.yaml index 2684b7dae..80e20c8df 100755 --- a/flutter_inappwebview/pubspec.yaml +++ b/flutter_inappwebview/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. -version: 6.1.5 +version: 6.2.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -20,7 +20,7 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_platform_interface: ^1.3.0 + flutter_inappwebview_platform_interface: ^1.4.0 flutter_inappwebview_android: ^1.1.3 flutter_inappwebview_ios: ^1.1.2 flutter_inappwebview_macos: ^1.1.2 diff --git a/flutter_inappwebview_android/CHANGELOG.md b/flutter_inappwebview_android/CHANGELOG.md index 3170f86a5..5fd6e2117 100644 --- a/flutter_inappwebview_android/CHANGELOG.md +++ b/flutter_inappwebview_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.0 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0 + ## 1.1.3 - Updated flutter_inappwebview_platform_interface version to ^1.3.0 diff --git a/flutter_inappwebview_android/pubspec.yaml b/flutter_inappwebview_android/pubspec.yaml index 912f92eef..f9fd161a3 100644 --- a/flutter_inappwebview_android/pubspec.yaml +++ b/flutter_inappwebview_android/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_android description: Android implementation of the flutter_inappwebview plugin. -version: 1.1.3 +version: 1.2.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_android issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -20,7 +20,7 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_platform_interface: ^1.3.0 + flutter_inappwebview_platform_interface: ^1.4.0 dev_dependencies: flutter_test: diff --git a/flutter_inappwebview_ios/CHANGELOG.md b/flutter_inappwebview_ios/CHANGELOG.md index 60e2bffdb..e164af8fc 100644 --- a/flutter_inappwebview_ios/CHANGELOG.md +++ b/flutter_inappwebview_ios/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.2.0 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0 +- Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error + ## 1.1.2 - Updated flutter_inappwebview_platform_interface version to ^1.3.0 diff --git a/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift b/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift index 43ac03776..12ff2a1a3 100755 --- a/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift @@ -546,7 +546,6 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, // This is a limitation of the official WebKit API. return } - configuration.userContentController = WKUserContentController() configuration.userContentController.initialize() if let applePayAPIEnabled = settings?.applePayAPIEnabled, applePayAPIEnabled { @@ -595,7 +594,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, public static func preWKWebViewConfiguration(settings: InAppWebViewSettings?) -> WKWebViewConfiguration { let configuration = WKWebViewConfiguration() - + // initialzie WKUserContentController here to fix possible "undefined is not an object (evaluating 'window.webkit.messageHandlers')" javascript error + configuration.userContentController = WKUserContentController() configuration.processPool = WKProcessPoolManager.sharedProcessPool if let settings = settings { diff --git a/flutter_inappwebview_ios/pubspec.yaml b/flutter_inappwebview_ios/pubspec.yaml index 06afb905a..1608e685a 100644 --- a/flutter_inappwebview_ios/pubspec.yaml +++ b/flutter_inappwebview_ios/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_ios description: iOS implementation of the flutter_inappwebview plugin. -version: 1.1.2 +version: 1.2.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_ios issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -20,7 +20,7 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_platform_interface: ^1.3.0 + flutter_inappwebview_platform_interface: ^1.4.0 dev_dependencies: flutter_test: diff --git a/flutter_inappwebview_macos/CHANGELOG.md b/flutter_inappwebview_macos/CHANGELOG.md index 7bd1ae744..de4edabbb 100644 --- a/flutter_inappwebview_macos/CHANGELOG.md +++ b/flutter_inappwebview_macos/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.2.0 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0 +- Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error + ## 1.1.2 - Updated flutter_inappwebview_platform_interface version to ^1.3.0 diff --git a/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift index 5e73f981c..d1cda14d3 100755 --- a/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift +++ b/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift @@ -193,7 +193,6 @@ public class InAppWebView: WKWebView, WKUIDelegate, // This is a limitation of the official WebKit API. return } - configuration.userContentController = WKUserContentController() configuration.userContentController.initialize() if let applePayAPIEnabled = settings?.applePayAPIEnabled, applePayAPIEnabled { @@ -242,7 +241,8 @@ public class InAppWebView: WKWebView, WKUIDelegate, public static func preWKWebViewConfiguration(settings: InAppWebViewSettings?) -> WKWebViewConfiguration { let configuration = WKWebViewConfiguration() - + // initialzie WKUserContentController here to fix possible "undefined is not an object (evaluating 'window.webkit.messageHandlers')" javascript error + configuration.userContentController = WKUserContentController() configuration.processPool = WKProcessPoolManager.sharedProcessPool if let settings = settings { diff --git a/flutter_inappwebview_macos/pubspec.yaml b/flutter_inappwebview_macos/pubspec.yaml index 0c7f6d6be..2e22bee5a 100644 --- a/flutter_inappwebview_macos/pubspec.yaml +++ b/flutter_inappwebview_macos/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_macos description: macOS implementation of the flutter_inappwebview plugin. -version: 1.1.2 +version: 1.2.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_macos issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -20,7 +20,7 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_platform_interface: ^1.3.0 + flutter_inappwebview_platform_interface: ^1.4.0 dev_dependencies: flutter_test: diff --git a/flutter_inappwebview_platform_interface/CHANGELOG.md b/flutter_inappwebview_platform_interface/CHANGELOG.md index 1ff5e50ac..8f5781b7f 100644 --- a/flutter_inappwebview_platform_interface/CHANGELOG.md +++ b/flutter_inappwebview_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +#### 1.4.0 + +- Updated static `fromMap` implementation for some classes + ## 1.3.0+1 - Fixed `X509Certificate.toMap` method diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart index 5080fec54..3383a065f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart @@ -55,7 +55,9 @@ class ChromeSafariBrowserActionButton { icon: Uint8List.fromList(map['icon'].cast()), id: map['id'], ); - instance.shouldTint = map['shouldTint']; + if (map['shouldTint'] != null) { + instance.shouldTint = map['shouldTint']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart index 7b1a7a3e8..453ac9aee 100644 --- a/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart @@ -43,11 +43,13 @@ class ChromeSafariBrowserSecondaryToolbar { final instance = ChromeSafariBrowserSecondaryToolbar( layout: AndroidResource.fromMap(map['layout']?.cast())!, ); - instance.clickableIDs = - List.from( - map['clickableIDs'].map((e) => - ChromeSafariBrowserSecondaryToolbarClickableID.fromMap( - e?.cast())!)); + if (map['clickableIDs'] != null) { + instance.clickableIDs = + List.from( + map['clickableIDs'].map((e) => + ChromeSafariBrowserSecondaryToolbarClickableID.fromMap( + e?.cast())!)); + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart index 046460726..1c91e9eca 100644 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart @@ -18,8 +18,10 @@ class ContextMenuSettings { return null; } final instance = ContextMenuSettings(); - instance.hideDefaultSystemContextMenuItems = - map['hideDefaultSystemContextMenuItems']; + if (map['hideDefaultSystemContextMenuItems'] != null) { + instance.hideDefaultSystemContextMenuItems = + map['hideDefaultSystemContextMenuItems']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.g.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.g.dart index 90620b746..8409511bf 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_browser/in_app_browser_menu_item.g.dart @@ -67,7 +67,9 @@ class InAppBrowserMenuItem { order: map['order'], title: map['title'], ); - instance.showAsAction = map['showAsAction']; + if (map['showAsAction'] != null) { + instance.showAsAction = map['showAsAction']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/platform_proxy_controller.g.dart b/flutter_inappwebview_platform_interface/lib/src/platform_proxy_controller.g.dart index 07f9de6cb..663fa52aa 100644 --- a/flutter_inappwebview_platform_interface/lib/src/platform_proxy_controller.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/platform_proxy_controller.g.dart @@ -76,12 +76,20 @@ class ProxySettings { bypassSimpleHostnames: map['bypassSimpleHostnames'], removeImplicitRules: map['removeImplicitRules'], ); - instance.bypassRules = - List.from(map['bypassRules']!.cast()); - instance.directs = List.from(map['directs']!.cast()); - instance.proxyRules = List.from(map['proxyRules'] - .map((e) => ProxyRule.fromMap(e?.cast())!)); - instance.reverseBypassEnabled = map['reverseBypassEnabled']; + if (map['bypassRules'] != null) { + instance.bypassRules = + List.from(map['bypassRules']!.cast()); + } + if (map['directs'] != null) { + instance.directs = List.from(map['directs']!.cast()); + } + if (map['proxyRules'] != null) { + instance.proxyRules = List.from(map['proxyRules'] + .map((e) => ProxyRule.fromMap(e?.cast())!)); + } + if (map['reverseBypassEnabled'] != null) { + instance.reverseBypassEnabled = map['reverseBypassEnabled']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/platform_tracing_controller.g.dart b/flutter_inappwebview_platform_interface/lib/src/platform_tracing_controller.g.dart index 9279c5e63..18345146c 100644 --- a/flutter_inappwebview_platform_interface/lib/src/platform_tracing_controller.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/platform_tracing_controller.g.dart @@ -42,7 +42,9 @@ class TracingSettings { final instance = TracingSettings( tracingMode: TracingMode.fromNativeValue(map['tracingMode']), ); - instance.categories = _deserializeCategories(map['categories']); + if (map['categories'] != null) { + instance.categories = _deserializeCategories(map['categories']); + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/console_message.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/console_message.g.dart index cf1192116..bd3870313 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/console_message.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/console_message.g.dart @@ -25,9 +25,13 @@ class ConsoleMessage { return null; } final instance = ConsoleMessage(); - instance.message = map['message']; - instance.messageLevel = - ConsoleMessageLevel.fromNativeValue(map['messageLevel'])!; + if (map['message'] != null) { + instance.message = map['message']; + } + if (map['messageLevel'] != null) { + instance.messageLevel = + ConsoleMessageLevel.fromNativeValue(map['messageLevel'])!; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/content_world.dart b/flutter_inappwebview_platform_interface/lib/src/types/content_world.dart index 84bfa35ef..5a788a706 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/content_world.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/content_world.dart @@ -33,6 +33,14 @@ class ContentWorld { ///If you modify a variable with the same name as one the webpage uses, you may unintentionally disrupt the normal operation of that page. static final ContentWorld PAGE = ContentWorld.world(name: "page"); + ///Gets a possible [ContentWorld] instance from a [Map] value. + static ContentWorld? fromMap(Map? map) { + if (map == null) { + return null; + } + return ContentWorld.world(name: map["name"]); + } + ///Converts instance to a map. Map toMap() { return {"name": name}; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_response.g.dart index c9bcfed65..cba4346b7 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/custom_scheme_response.g.dart @@ -31,7 +31,9 @@ class CustomSchemeResponse { contentType: map['contentType'], data: Uint8List.fromList(map['data'].cast()), ); - instance.contentEncoding = map['contentEncoding']; + if (map['contentEncoding'] != null) { + instance.contentEncoding = map['contentEncoding']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.g.dart index 37be906a5..1c31d1ecf 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.g.dart @@ -30,7 +30,9 @@ class GeolocationPermissionShowPromptResponse { allow: map['allow'], origin: map['origin'], ); - instance.retain = map['retain']; + if (map['retain'] != null) { + instance.retain = map['retain']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.g.dart index dfa18193a..bbfea393f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.g.dart @@ -32,9 +32,15 @@ class HttpAuthResponse { } final instance = HttpAuthResponse(); instance.action = HttpAuthResponseAction.fromNativeValue(map['action']); - instance.password = map['password']; - instance.permanentPersistence = map['permanentPersistence']; - instance.username = map['username']; + if (map['password'] != null) { + instance.password = map['password']; + } + if (map['permanentPersistence'] != null) { + instance.permanentPersistence = map['permanentPersistence']; + } + if (map['username'] != null) { + instance.username = map['username']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.g.dart index 4cfd6cc9f..d0495c21f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.g.dart @@ -52,8 +52,12 @@ class InAppWebViewInitialData { data: map['data'], historyUrl: map['historyUrl'] != null ? WebUri(map['historyUrl']) : null, ); - instance.encoding = map['encoding']; - instance.mimeType = map['mimeType']; + if (map['encoding'] != null) { + instance.encoding = map['encoding']; + } + if (map['mimeType'] != null) { + instance.mimeType = map['mimeType']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.g.dart index d6903df7c..7ebeed328 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.g.dart @@ -32,9 +32,15 @@ class JsAlertResponse { } final instance = JsAlertResponse(); instance.action = JsAlertResponseAction.fromNativeValue(map['action']); - instance.confirmButtonTitle = map['confirmButtonTitle']; - instance.handledByClient = map['handledByClient']; - instance.message = map['message']; + if (map['confirmButtonTitle'] != null) { + instance.confirmButtonTitle = map['confirmButtonTitle']; + } + if (map['handledByClient'] != null) { + instance.handledByClient = map['handledByClient']; + } + if (map['message'] != null) { + instance.message = map['message']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.g.dart index 885f2f573..cc7a3f268 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.g.dart @@ -37,10 +37,18 @@ class JsBeforeUnloadResponse { final instance = JsBeforeUnloadResponse(); instance.action = JsBeforeUnloadResponseAction.fromNativeValue(map['action']); - instance.cancelButtonTitle = map['cancelButtonTitle']; - instance.confirmButtonTitle = map['confirmButtonTitle']; - instance.handledByClient = map['handledByClient']; - instance.message = map['message']; + if (map['cancelButtonTitle'] != null) { + instance.cancelButtonTitle = map['cancelButtonTitle']; + } + if (map['confirmButtonTitle'] != null) { + instance.confirmButtonTitle = map['confirmButtonTitle']; + } + if (map['handledByClient'] != null) { + instance.handledByClient = map['handledByClient']; + } + if (map['message'] != null) { + instance.message = map['message']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.g.dart index ddd0bc9be..ab090462b 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.g.dart @@ -36,10 +36,18 @@ class JsConfirmResponse { } final instance = JsConfirmResponse(); instance.action = JsConfirmResponseAction.fromNativeValue(map['action']); - instance.cancelButtonTitle = map['cancelButtonTitle']; - instance.confirmButtonTitle = map['confirmButtonTitle']; - instance.handledByClient = map['handledByClient']; - instance.message = map['message']; + if (map['cancelButtonTitle'] != null) { + instance.cancelButtonTitle = map['cancelButtonTitle']; + } + if (map['confirmButtonTitle'] != null) { + instance.confirmButtonTitle = map['confirmButtonTitle']; + } + if (map['handledByClient'] != null) { + instance.handledByClient = map['handledByClient']; + } + if (map['message'] != null) { + instance.message = map['message']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.g.dart index abea1745f..90ace79ea 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.g.dart @@ -46,11 +46,21 @@ class JsPromptResponse { value: map['value'], ); instance.action = JsPromptResponseAction.fromNativeValue(map['action']); - instance.cancelButtonTitle = map['cancelButtonTitle']; - instance.confirmButtonTitle = map['confirmButtonTitle']; - instance.defaultValue = map['defaultValue']; - instance.handledByClient = map['handledByClient']; - instance.message = map['message']; + if (map['cancelButtonTitle'] != null) { + instance.cancelButtonTitle = map['cancelButtonTitle']; + } + if (map['confirmButtonTitle'] != null) { + instance.confirmButtonTitle = map['confirmButtonTitle']; + } + if (map['defaultValue'] != null) { + instance.defaultValue = map['defaultValue']; + } + if (map['handledByClient'] != null) { + instance.handledByClient = map['handledByClient']; + } + if (map['message'] != null) { + instance.message = map['message']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/permission_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/permission_request.g.dart index a52ea4d80..2f328253f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/permission_request.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/permission_request.g.dart @@ -31,8 +31,10 @@ class PermissionRequest { frame: FrameInfo.fromMap(map['frame']?.cast()), origin: WebUri(map['origin']), ); - instance.resources = List.from(map['resources'] - .map((e) => PermissionResourceType.fromNativeValue(e)!)); + if (map['resources'] != null) { + instance.resources = List.from(map['resources'] + .map((e) => PermissionResourceType.fromNativeValue(e)!)); + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/permission_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/permission_response.g.dart index 1cd597f28..76e3f60db 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/permission_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/permission_response.g.dart @@ -25,8 +25,10 @@ class PermissionResponse { } final instance = PermissionResponse(); instance.action = PermissionResponseAction.fromNativeValue(map['action']); - instance.resources = List.from(map['resources'] - .map((e) => PermissionResourceType.fromNativeValue(e)!)); + if (map['resources'] != null) { + instance.resources = List.from(map['resources'] + .map((e) => PermissionResourceType.fromNativeValue(e)!)); + } return instance; } @@ -70,7 +72,9 @@ class PermissionRequestResponse { final instance = PermissionRequestResponse(); instance.action = PermissionRequestResponseAction.fromNativeValue(map['action']); - instance.resources = List.from(map['resources']!.cast()); + if (map['resources'] != null) { + instance.resources = List.from(map['resources']!.cast()); + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.g.dart index 4c24640e5..0b1ec0af3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.g.dart @@ -25,7 +25,9 @@ class SafeBrowsingResponse { } final instance = SafeBrowsingResponse(); instance.action = SafeBrowsingResponseAction.fromNativeValue(map['action']); - instance.report = map['report']; + if (map['report'] != null) { + instance.report = map['report']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.g.dart index 460c7890d..edb541957 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.g.dart @@ -86,10 +86,16 @@ class ScreenshotConfiguration { rect: InAppWebViewRect.fromMap(map['rect']?.cast()), snapshotWidth: map['snapshotWidth'], ); - instance.afterScreenUpdates = map['afterScreenUpdates']; - instance.compressFormat = - CompressFormat.fromNativeValue(map['compressFormat'])!; - instance.quality = map['quality']; + if (map['afterScreenUpdates'] != null) { + instance.afterScreenUpdates = map['afterScreenUpdates']; + } + if (map['compressFormat'] != null) { + instance.compressFormat = + CompressFormat.fromNativeValue(map['compressFormat'])!; + } + if (map['quality'] != null) { + instance.quality = map['quality']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.g.dart index 4ca725079..25476b4cf 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.g.dart @@ -100,7 +100,9 @@ class ScriptHtmlTagAttributes { nonce: map['nonce'], referrerPolicy: ReferrerPolicy.fromNativeValue(map['referrerPolicy']), ); - instance.type = map['type']; + if (map['type'] != null) { + instance.type = map['type']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart index a5370c9eb..ad5ff7583 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart @@ -43,8 +43,10 @@ class TrustedWebActivityImmersiveDisplayMode AndroidLayoutInDisplayCutoutMode.fromNativeValue( map['displayCutoutMode']), ); - instance.displayCutoutMode = - LayoutInDisplayCutoutMode.fromNativeValue(map['displayCutoutMode'])!; + if (map['displayCutoutMode'] != null) { + instance.displayCutoutMode = + LayoutInDisplayCutoutMode.fromNativeValue(map['displayCutoutMode'])!; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart index 99f114be0..eef04c111 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart @@ -64,10 +64,17 @@ class UserScript { iosForMainFrameOnly: map['forMainFrameOnly'], source: map['source'], ); - instance.allowedOriginRules = - Set.from(map['allowedOriginRules']!.cast()); - instance.contentWorld = map['contentWorld']; - instance.forMainFrameOnly = map['forMainFrameOnly']; + if (map['allowedOriginRules'] != null) { + instance.allowedOriginRules = + Set.from(map['allowedOriginRules']!.cast()); + } + if (map['contentWorld'] != null) { + instance.contentWorld = + ContentWorld.fromMap(map['contentWorld']?.cast())!; + } + if (map['forMainFrameOnly'] != null) { + instance.forMainFrameOnly = map['forMainFrameOnly']; + } return instance; } diff --git a/flutter_inappwebview_platform_interface/pubspec.yaml b/flutter_inappwebview_platform_interface/pubspec.yaml index 16a58f358..78131c8e7 100644 --- a/flutter_inappwebview_platform_interface/pubspec.yaml +++ b/flutter_inappwebview_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_platform_interface description: A common platform interface for the flutter_inappwebview plugin. -version: 1.3.0+1 +version: 1.4.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_platform_interface issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues diff --git a/flutter_inappwebview_web/CHANGELOG.md b/flutter_inappwebview_web/CHANGELOG.md index c02525fc0..6a1c66e2a 100644 --- a/flutter_inappwebview_web/CHANGELOG.md +++ b/flutter_inappwebview_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.2.0 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0 + ## 1.1.2 - Updated flutter_inappwebview_platform_interface version to ^1.3.0 diff --git a/flutter_inappwebview_web/pubspec.yaml b/flutter_inappwebview_web/pubspec.yaml index d6557020c..212c24f96 100644 --- a/flutter_inappwebview_web/pubspec.yaml +++ b/flutter_inappwebview_web/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_web description: Web implementation of the flutter_inappwebview plugin. -version: 1.1.2 +version: 1.2.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_web issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -23,7 +23,7 @@ dependencies: flutter_web_plugins: sdk: flutter web: ^1.0.0 - flutter_inappwebview_platform_interface: ^1.3.0 + flutter_inappwebview_platform_interface: ^1.4.0 dev_dependencies: flutter_test: diff --git a/flutter_inappwebview_windows/CHANGELOG.md b/flutter_inappwebview_windows/CHANGELOG.md index dd1cc41a6..5776df728 100644 --- a/flutter_inappwebview_windows/CHANGELOG.md +++ b/flutter_inappwebview_windows/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0 + ## 0.6.0 - Updated code to support multiple flutter windows diff --git a/flutter_inappwebview_windows/example/pubspec.lock b/flutter_inappwebview_windows/example/pubspec.lock index 83bd88ac0..2f5993cf3 100644 --- a/flutter_inappwebview_windows/example/pubspec.lock +++ b/flutter_inappwebview_windows/example/pubspec.lock @@ -97,7 +97,7 @@ packages: path: ".." relative: true source: path - version: "0.5.0" + version: "0.6.0" flutter_lints: dependency: "direct dev" description: diff --git a/flutter_inappwebview_windows/pubspec.yaml b/flutter_inappwebview_windows/pubspec.yaml index d1c3ce45d..87282c4c5 100644 --- a/flutter_inappwebview_windows/pubspec.yaml +++ b/flutter_inappwebview_windows/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_windows description: Windows implementation of the flutter_inappwebview plugin. -version: 0.6.0 +version: 0.7.0 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_windows issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -20,7 +20,7 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_platform_interface: ^1.3.0 + flutter_inappwebview_platform_interface: ^1.4.0 dev_dependencies: flutter_test: From dc7bc505e42cedb1129202cde686985d966568a6 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Wed, 23 Oct 2024 19:19:41 +0200 Subject: [PATCH 012/137] android: Added InAppWebViewController.enableSlowWholeDocumentDraw static method, Added CookieManager.flush method, Updated InAppWebViewController.takeScreenshot implementation to support screenshot out of visible viewport when InAppWebViewController.enableSlowWholeDocumentDraw is called, fix #2354 --- flutter_inappwebview/CHANGELOG.md | 5 + .../lib/src/cookie_manager.dart | 3 + .../in_app_webview_controller.dart | 5 + flutter_inappwebview_android/CHANGELOG.md | 3 + .../MyCookieManager.java | 17 +++ .../webview/InAppWebViewManager.java | 8 ++ .../webview/in_app_webview/InAppWebView.java | 104 ++++++++++-------- .../lib/src/cookie_manager.dart | 6 + .../in_app_webview_controller.dart | 6 + .../platform_in_app_browser.dart | 3 + .../platform_inappwebview_controller.dart | 23 ++++ .../src/in_app_webview/platform_webview.dart | 3 + .../lib/src/platform_cookie_manager.dart | 12 ++ 13 files changed, 151 insertions(+), 47 deletions(-) diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index 631373fae..3adb5cf62 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -11,6 +11,11 @@ #### Platform Interface - Updated static `fromMap` implementation for some classes +#### Android Platform +- Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method +- Added `CookieManager.flush` method +- Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called + #### iOS Platform - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error diff --git a/flutter_inappwebview/lib/src/cookie_manager.dart b/flutter_inappwebview/lib/src/cookie_manager.dart index 3ab49df1e..bebf0f303 100755 --- a/flutter_inappwebview/lib/src/cookie_manager.dart +++ b/flutter_inappwebview/lib/src/cookie_manager.dart @@ -143,6 +143,9 @@ class CookieManager { ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.removeSessionCookies} Future removeSessionCookies() => platform.removeSessionCookies(); + + ///{@macro flutter_inappwebview_platform_interface.PlatformCookieManager.flush} + Future flush() => platform.flush(); } ///Class that contains only iOS-specific methods of [CookieManager]. diff --git a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart index 1544754d3..0232fac93 100644 --- a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart @@ -565,6 +565,11 @@ class InAppWebViewController { PlatformInAppWebViewController.static() .clearAllCache(includeDiskFiles: includeDiskFiles); + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.enableSlowWholeDocumentDraw} + static Future enableSlowWholeDocumentDraw() => + PlatformInAppWebViewController.static() + .enableSlowWholeDocumentDraw(); + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.tRexRunnerHtml} static Future get tRexRunnerHtml => PlatformInAppWebViewController.static().tRexRunnerHtml; diff --git a/flutter_inappwebview_android/CHANGELOG.md b/flutter_inappwebview_android/CHANGELOG.md index 5fd6e2117..4f9458f85 100644 --- a/flutter_inappwebview_android/CHANGELOG.md +++ b/flutter_inappwebview_android/CHANGELOG.md @@ -1,6 +1,9 @@ ## 1.2.0 - Updated flutter_inappwebview_platform_interface version to ^1.4.0 +- Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method +- Added `CookieManager.flush` method +- Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called ## 1.1.3 diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyCookieManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyCookieManager.java index ff4247e7e..e45b2789e 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyCookieManager.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/MyCookieManager.java @@ -103,6 +103,9 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result case "removeSessionCookies": removeSessionCookies(result); break; + case "flush": + flush(result); + break; default: result.notImplemented(); } @@ -423,6 +426,20 @@ else if (plugin != null) { } } + public void flush(MethodChannel.Result result) { + cookieManager = getCookieManager(); + if (cookieManager == null) { + result.success(false); + return; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + cookieManager.flush(); + } else if (plugin != null) { + CookieSyncManager cookieSyncMngr = CookieSyncManager.createInstance(plugin.applicationContext); + cookieSyncMngr.sync(); + } + } + public static String getCookieExpirationDate(Long timestamp) { final SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss z", Locale.US); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java index 623354aef..27a624ad2 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java @@ -162,6 +162,14 @@ public void onReceiveValue(Boolean value) { } result.success(true); break; + case "enableSlowWholeDocumentDraw": + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + WebView.enableSlowWholeDocumentDraw(); + } + } + result.success(true); + break; default: result.notImplemented(); } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java index b0bfd5509..fbabab3d4 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java @@ -215,8 +215,8 @@ public WebViewClient createWebViewClient(InAppBrowserDelegate inAppBrowserDelega } boolean isChromiumWebView = "com.android.webview".equals(packageInfo.packageName) || - "com.google.android.webview".equals(packageInfo.packageName) || - "com.android.chrome".equals(packageInfo.packageName); + "com.google.android.webview".equals(packageInfo.packageName) || + "com.android.chrome".equals(packageInfo.packageName); boolean isChromiumWebViewBugFixed = false; if (isChromiumWebView) { String versionName = packageInfo.versionName != null ? packageInfo.versionName : ""; @@ -224,7 +224,8 @@ public WebViewClient createWebViewClient(InAppBrowserDelegate inAppBrowserDelega int majorVersion = versionName.contains(".") ? Integer.parseInt(versionName.split("\\.")[0]) : 0; isChromiumWebViewBugFixed = majorVersion >= 73; - } catch (NumberFormatException ignored) {} + } catch (NumberFormatException ignored) { + } } if (isChromiumWebViewBugFixed || !isChromiumWebView) { @@ -704,36 +705,21 @@ public void takeScreenshot(final @Nullable Map screenshotConfigu @Override public void run() { try { - Bitmap screenshotBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(screenshotBitmap); - c.translate(-getScrollX(), -getScrollY()); - draw(c); + int bitmapWidth = getMeasuredWidth(); + int bitmapHeight = getMeasuredHeight(); + int bitmapScrollX = getScrollX(); + int bitmapScrollY = getScrollY(); - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.PNG; int quality = 100; if (screenshotConfiguration != null) { Map rect = (Map) screenshotConfiguration.get("rect"); if (rect != null) { - int rectX = (int) Math.floor(rect.get("x") * pixelDensity + 0.5); - int rectY = (int) Math.floor(rect.get("y") * pixelDensity + 0.5); - int rectWidth = Math.min(screenshotBitmap.getWidth(), (int) Math.floor(rect.get("width") * pixelDensity + 0.5)); - int rectHeight = Math.min(screenshotBitmap.getHeight(), (int) Math.floor(rect.get("height") * pixelDensity + 0.5)); - screenshotBitmap = Bitmap.createBitmap( - screenshotBitmap, - rectX, - rectY, - rectWidth, - rectHeight); - } - - Double snapshotWidth = (Double) screenshotConfiguration.get("snapshotWidth"); - if (snapshotWidth != null) { - int dstWidth = (int) Math.floor(snapshotWidth * pixelDensity + 0.5); - float ratioBitmap = (float) screenshotBitmap.getWidth() / (float) screenshotBitmap.getHeight(); - int dstHeight = (int) ((float) dstWidth / ratioBitmap); - screenshotBitmap = Bitmap.createScaledBitmap(screenshotBitmap, dstWidth, dstHeight, true); + bitmapScrollX = (int) Math.floor(rect.get("x") * pixelDensity + 0.5); + bitmapScrollY = (int) Math.floor(rect.get("y") * pixelDensity + 0.5); + bitmapWidth = (int) Math.floor(rect.get("width") * pixelDensity + 0.5); + bitmapHeight = (int) Math.floor(rect.get("height") * pixelDensity + 0.5); } try { @@ -745,10 +731,31 @@ public void run() { quality = (Integer) screenshotConfiguration.get("quality"); } - screenshotBitmap.compress( + Bitmap screenshotBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(screenshotBitmap); + c.translate(-bitmapScrollX, -bitmapScrollY); + draw(c); + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + if (screenshotConfiguration != null) { + Double snapshotWidth = (Double) screenshotConfiguration.get("snapshotWidth"); + if (snapshotWidth != null) { + int dstWidth = (int) Math.floor(snapshotWidth * pixelDensity + 0.5); + float ratioBitmap = (float) screenshotBitmap.getWidth() / (float) screenshotBitmap.getHeight(); + int dstHeight = (int) ((float) dstWidth / ratioBitmap); + screenshotBitmap = Bitmap.createScaledBitmap(screenshotBitmap, dstWidth, dstHeight, true); + } + } + + final boolean compressed = screenshotBitmap.compress( compressFormat, quality, byteArrayOutputStream); + if (!compressed) { + Log.e(LOG_TAG, "Screenshot cannot be compressed using compressFormat " + + compressFormat.name() + " with quality " + quality, null); + } try { byteArrayOutputStream.close(); @@ -932,7 +939,7 @@ else if (newSettingsMap.get("clearSessionCache") != null && newCustomSettings.cl if (newSettingsMap.get("disabledActionModeMenuItems") != null && (customSettings.disabledActionModeMenuItems == null || - !customSettings.disabledActionModeMenuItems.equals(newCustomSettings.disabledActionModeMenuItems))) { + !customSettings.disabledActionModeMenuItems.equals(newCustomSettings.disabledActionModeMenuItems))) { if (WebViewFeature.isFeatureSupported(WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS)) WebSettingsCompat.setDisabledActionModeMenuItems(settings, newCustomSettings.disabledActionModeMenuItems); else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) @@ -1164,7 +1171,7 @@ public void injectDeferredObject(String source, @Nullable final ContentWorld con if (resultUuid != null && resultCallback != null) { evaluateJavaScriptContentWorldCallbacks.put(resultUuid, resultCallback); scriptToInject = Util.replaceAll(PluginScriptsUtil.EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE, - PluginScriptsUtil.VAR_RANDOM_NAME, "_" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_" + Math.round(Math.random() * 1000000)) + PluginScriptsUtil.VAR_RANDOM_NAME, "_" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_" + Math.round(Math.random() * 1000000)) .replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, UserContentController.escapeCode(source)) .replace(PluginScriptsUtil.VAR_RESULT_UUID, resultUuid); } @@ -1209,15 +1216,15 @@ public void injectJavascriptFileFromUrl(String urlFile, @Nullable Map flush() async { + Map args = {}; + await channel?.invokeMethod('flush', args); + } + @override void dispose() { // empty diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart index ceb4bc9a9..0d269dc2e 100644 --- a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart @@ -2738,6 +2738,12 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController await _staticChannel.invokeMethod('clearAllCache', args); } + @override + Future enableSlowWholeDocumentDraw() async { + Map args = {}; + await _staticChannel.invokeMethod('enableSlowWholeDocumentDraw', args); + } + @override Future get tRexRunnerHtml async => await rootBundle.loadString( 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html'); 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 6c14c7180..45c9e24c7 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 @@ -1218,6 +1218,9 @@ abstract class PlatformInAppBrowserEvents { ///The application's implementation of this callback should only attempt to clean up the WebView. ///The WebView should be removed from the view hierarchy, all references to it should be cleaned up. /// + ///To cause an render process crash for test purpose, the application can call load url `"chrome://crash"` on the WebView. + ///Note that multiple WebView instances may be affected if they share a render process, not just the specific WebView which loaded `"chrome://crash"`. + /// ///[detail] the reason why it exited. /// ///**NOTE**: available only on Android 26+. 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 4026e6162..cc2c49176 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 @@ -749,6 +749,9 @@ abstract class PlatformInAppWebViewController extends PlatformInterface /// ///**NOTE for MacOS**: available on MacOS 10.13+. /// + ///**NOTE for Android**: To be able to take screenshots outside the visible viewport, + ///you must call [PlatformInAppWebViewController.enableSlowWholeDocumentDraw] before any WebViews are created. + /// ///**Officially Supported Platforms/Implementations**: ///- Android native WebView ///- iOS ([Official API - WKWebView.takeSnapshot](https://developer.apple.com/documentation/webkit/wkwebview/2873260-takesnapshot)) @@ -2335,6 +2338,26 @@ abstract class PlatformInAppWebViewController extends PlatformInterface 'clearAllCache is not implemented on the current platform'); } + ///{@template flutter_inappwebview_platform_interface.PlatformInAppWebViewController.enableSlowWholeDocumentDraw} + ///For apps targeting the L release, WebView has a new default behavior that reduces memory footprint and increases + ///performance by intelligently choosing the portion of the HTML document that needs to be drawn. + ///These optimizations are transparent to the developers. + ///However, under certain circumstances, an App developer may want to disable them, for example + ///when an app draws and accesses portions of the page that is way outside the visible portion of the page. + ///Enabling drawing the entire HTML document has a significant performance cost. + /// + ///**NOTE**: This method should be called before any WebViews are created. + /// + ///**NOTE for Android**: available only on Android 21+. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.getUrl](https://developer.android.com/reference/android/webkit/WebView#enableSlowWholeDocumentDraw())) + ///{@endtemplate} + Future enableSlowWholeDocumentDraw() { + throw UnimplementedError( + 'enableSlowWholeDocumentDraw is not implemented on the current platform'); + } + ///{@template flutter_inappwebview_platform_interface.PlatformInAppWebViewController.tRexRunnerHtml} ///Gets the html (with javascript) of the Chromium's t-rex runner game. Used in combination with [tRexRunnerCss]. /// 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 838911d2d..36d923eb7 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 @@ -812,6 +812,9 @@ class PlatformWebViewCreationParams { ///The application's implementation of this callback should only attempt to clean up the WebView. ///The WebView should be removed from the view hierarchy, all references to it should be cleaned up. /// + ///To cause an render process crash for test purpose, the application can call load url `"chrome://crash"` on the WebView. + ///Note that multiple WebView instances may be affected if they share a render process, not just the specific WebView which loaded `"chrome://crash"`. + /// ///[detail] the reason why it exited. /// ///**NOTE**: available only on Android 26+. diff --git a/flutter_inappwebview_platform_interface/lib/src/platform_cookie_manager.dart b/flutter_inappwebview_platform_interface/lib/src/platform_cookie_manager.dart index 700cc487c..9bb693320 100755 --- a/flutter_inappwebview_platform_interface/lib/src/platform_cookie_manager.dart +++ b/flutter_inappwebview_platform_interface/lib/src/platform_cookie_manager.dart @@ -302,4 +302,16 @@ abstract class PlatformCookieManager extends PlatformInterface { throw UnimplementedError( 'removeSessionCookies is not implemented on the current platform'); } + + ///{@template flutter_inappwebview_platform_interface.PlatformCookieManager.flush} + ///Ensures all cookies currently accessible through the getCookie API are written to persistent storage. + ///This call will block the caller until it is done and may perform I/O. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - CookieManager.flush](https://developer.android.com/reference/android/webkit/CookieManager#flush())) + ///{@endtemplate} + Future flush() { + throw UnimplementedError( + 'flush is not implemented on the current platform'); + } } From b1ada7eb639e36f95178de152ee307ab7a9e9ae0 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 22:35:01 +0000 Subject: [PATCH 013/137] update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fe2d03493..3326cf668 100755 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-84-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-85-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -191,6 +191,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Gray Mackall
Gray Mackall

đź’» Pavel Mazhnik
Pavel Mazhnik

đź’» + + nlog (solrin)
nlog (solrin)

đź’» + From 10d6b4f21027584f7aaaa0bcbc84a2610c03e21a Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 22:35:02 +0000 Subject: [PATCH 014/137] update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 27fa03dad..3188af3a3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -766,6 +766,15 @@ "contributions": [ "code" ] + }, + { + "login": "nnnlog", + "name": "nlog (solrin)", + "avatar_url": "https://avatars.githubusercontent.com/u/20399222?v=4", + "profile": "https://nlog.dev", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, From b96fe38082bd68e4224f96360964ff2d4693041b Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Thu, 24 Oct 2024 00:38:40 +0200 Subject: [PATCH 015/137] updated CHANGELOG files --- flutter_inappwebview/CHANGELOG.md | 6 ++---- flutter_inappwebview/README.md | 5 ++++- .../example/ios/Runner.xcodeproj/project.pbxproj | 8 ++++---- flutter_inappwebview_ios/CHANGELOG.md | 1 + flutter_inappwebview_macos/CHANGELOG.md | 1 + 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index 3adb5cf62..46030aae7 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -16,11 +16,9 @@ - Added `CookieManager.flush` method - Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called -#### iOS Platform -- Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error - -#### macOS Platform +#### macOS and iOS Platforms - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error +- Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) ## 6.1.5 diff --git a/flutter_inappwebview/README.md b/flutter_inappwebview/README.md index fe2d03493..3326cf668 100755 --- a/flutter_inappwebview/README.md +++ b/flutter_inappwebview/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-84-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-85-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -191,6 +191,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Gray Mackall
Gray Mackall

đź’» Pavel Mazhnik
Pavel Mazhnik

đź’» + + nlog (solrin)
nlog (solrin)

đź’» + diff --git a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.pbxproj b/flutter_inappwebview/example/ios/Runner.xcodeproj/project.pbxproj index 6e356e166..bef2e71bd 100644 --- a/flutter_inappwebview/example/ios/Runner.xcodeproj/project.pbxproj +++ b/flutter_inappwebview/example/ios/Runner.xcodeproj/project.pbxproj @@ -481,7 +481,7 @@ MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example2.test"; + PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example3.test"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -518,7 +518,7 @@ ); MARKETING_VERSION = 1.0; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example2.test"; + PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example3.test"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; @@ -667,7 +667,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example2"; + PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example3"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -702,7 +702,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example2"; + PRODUCT_BUNDLE_IDENTIFIER = "com.pichillilorenzo.flutterinappwebview-ios-example3"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/flutter_inappwebview_ios/CHANGELOG.md b/flutter_inappwebview_ios/CHANGELOG.md index e164af8fc..38838414f 100644 --- a/flutter_inappwebview_ios/CHANGELOG.md +++ b/flutter_inappwebview_ios/CHANGELOG.md @@ -2,6 +2,7 @@ - Updated flutter_inappwebview_platform_interface version to ^1.4.0 - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error +- Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) ## 1.1.2 diff --git a/flutter_inappwebview_macos/CHANGELOG.md b/flutter_inappwebview_macos/CHANGELOG.md index de4edabbb..c364077c8 100644 --- a/flutter_inappwebview_macos/CHANGELOG.md +++ b/flutter_inappwebview_macos/CHANGELOG.md @@ -2,6 +2,7 @@ - Updated flutter_inappwebview_platform_interface version to ^1.4.0 - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error +- Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) ## 1.1.2 From 4ba6e22848aae9c2ca16bc784023b7fa98cf61e3 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 25 Oct 2024 16:54:41 +0200 Subject: [PATCH 016/137] fix #2025 --- flutter_inappwebview/CHANGELOG.md | 1 + flutter_inappwebview_android/CHANGELOG.md | 1 + .../webview/InAppWebViewManager.java | 8 +++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index 46030aae7..afed9dc21 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -15,6 +15,7 @@ - Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method - Added `CookieManager.flush` method - Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called +- Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) #### macOS and iOS Platforms - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error diff --git a/flutter_inappwebview_android/CHANGELOG.md b/flutter_inappwebview_android/CHANGELOG.md index 4f9458f85..fec6738d9 100644 --- a/flutter_inappwebview_android/CHANGELOG.md +++ b/flutter_inappwebview_android/CHANGELOG.md @@ -4,6 +4,7 @@ - Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method - Added `CookieManager.flush` method - Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called +- Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) ## 1.1.3 diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java index 27a624ad2..7463c5a9a 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java @@ -215,9 +215,11 @@ public void dispose() { super.dispose(); Collection flutterWebViews = keepAliveWebViews.values(); for (FlutterWebView flutterWebView : flutterWebViews) { - String keepAliveId = flutterWebView.keepAliveId; - if (keepAliveId != null) { - disposeKeepAlive(flutterWebView.keepAliveId); + if (flutterWebView != null) { + String keepAliveId = flutterWebView.keepAliveId; + if (keepAliveId != null) { + disposeKeepAlive(keepAliveId); + } } } keepAliveWebViews.clear(); From 2f2a86e96c3a7c860a8f33b70d7098f73f613572 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:57:47 +0000 Subject: [PATCH 017/137] update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3326cf668..fb5173719 100755 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-85-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-86-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -193,6 +193,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d nlog (solrin)
nlog (solrin)

đź’» + Murmurl912
Murmurl912

đź’» From 83ee929c288ac2c749642f5f1048177859acc50e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:57:48 +0000 Subject: [PATCH 018/137] update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3188af3a3..8e9972114 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -775,6 +775,15 @@ "contributions": [ "code" ] + }, + { + "login": "Murmurl912", + "name": "Murmurl912", + "avatar_url": "https://avatars.githubusercontent.com/u/36264246?v=4", + "profile": "https://github.com/Murmurl912", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, From ecebeefd953082121ed34dc30c4dd6bd5e11a488 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 16:38:28 +0000 Subject: [PATCH 019/137] update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fb5173719..413b1099f 100755 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-86-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-87-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -194,6 +194,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d nlog (solrin)
nlog (solrin)

đź’» Murmurl912
Murmurl912

đź’» + Benjamin Schulz
Benjamin Schulz

🤔 From 56f79d6ced2ed3c5bee5597cdcdb82d230f3f3bc Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 16:38:29 +0000 Subject: [PATCH 020/137] update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 8e9972114..3de04dfc7 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -784,6 +784,15 @@ "contributions": [ "code" ] + }, + { + "login": "bschulz87", + "name": "Benjamin Schulz", + "avatar_url": "https://avatars.githubusercontent.com/u/30199362?v=4", + "profile": "https://github.com/bschulz87", + "contributions": [ + "ideas" + ] } ], "contributorsPerLine": 7, From b2b1ddda57a86aff28cbd31234244f409da1fae6 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 25 Oct 2024 18:42:17 +0200 Subject: [PATCH 021/137] Added PlatformInAppLocalhostServer.onData parameter to set a custom on data server callback #2188 --- flutter_inappwebview/CHANGELOG.md | 4 +++ flutter_inappwebview/README.md | 4 ++- flutter_inappwebview/example/lib/main.dart | 5 +-- .../lib/src/in_app_localhost_server.dart | 8 ++++- .../CHANGELOG.md | 1 + .../lib/src/in_app_localhost_server.dart | 32 ++++++++++++++++--- .../src/platform_in_app_localhost_server.dart | 14 ++++++++ flutter_inappwebview_web/CHANGELOG.md | 1 + 8 files changed, 60 insertions(+), 9 deletions(-) diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index afed9dc21..bb06d1818 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -10,6 +10,7 @@ #### Platform Interface - Updated static `fromMap` implementation for some classes +- Added `PlatformInAppLocalhostServer.onData` parameter to set a custom on data server callback #### Android Platform - Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method @@ -21,6 +22,9 @@ - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error - Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) +#### Web Platform +- Merged "[web] support iframe role and aria-hidden attributes" [2293](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2293) (thanks to [p-mazhnik](https://github.com/p-mazhnik)) + ## 6.1.5 - Updated dependencies to the latest versions for all platform implementations: diff --git a/flutter_inappwebview/README.md b/flutter_inappwebview/README.md index 3326cf668..413b1099f 100755 --- a/flutter_inappwebview/README.md +++ b/flutter_inappwebview/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-85-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-87-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -193,6 +193,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d nlog (solrin)
nlog (solrin)

đź’» + Murmurl912
Murmurl912

đź’» + Benjamin Schulz
Benjamin Schulz

🤔 diff --git a/flutter_inappwebview/example/lib/main.dart b/flutter_inappwebview/example/lib/main.dart index ebb77618f..737612fcf 100755 --- a/flutter_inappwebview/example/lib/main.dart +++ b/flutter_inappwebview/example/lib/main.dart @@ -3,11 +3,10 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; - import 'package:flutter_inappwebview_example/chrome_safari_browser_example.screen.dart'; import 'package:flutter_inappwebview_example/headless_in_app_webview.screen.dart'; -import 'package:flutter_inappwebview_example/in_app_webiew_example.screen.dart'; import 'package:flutter_inappwebview_example/in_app_browser_example.screen.dart'; +import 'package:flutter_inappwebview_example/in_app_webiew_example.screen.dart'; import 'package:flutter_inappwebview_example/web_authentication_session_example.screen.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; @@ -23,6 +22,8 @@ Future main() async { // await Permission.microphone.request(); // await Permission.storage.request(); + await localhostServer.start(); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows) { final availableVersion = await WebViewEnvironment.getAvailableVersion(); assert(availableVersion != null, diff --git a/flutter_inappwebview/lib/src/in_app_localhost_server.dart b/flutter_inappwebview/lib/src/in_app_localhost_server.dart index daae11b7b..841f0cc29 100755 --- a/flutter_inappwebview/lib/src/in_app_localhost_server.dart +++ b/flutter_inappwebview/lib/src/in_app_localhost_server.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer} @@ -9,12 +10,14 @@ class InAppLocalhostServer { String directoryIndex = 'index.html', String documentRoot = './', bool shared = false, + Future Function(HttpRequest request)? onData, }) : this.fromPlatformCreationParams( PlatformInAppLocalhostServerCreationParams( port: port, directoryIndex: directoryIndex, documentRoot: documentRoot, - shared: shared), + shared: shared, + onData: onData), ); /// Constructs a [InAppLocalhostServer] from creation params for a specific @@ -42,6 +45,9 @@ class InAppLocalhostServer { ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.shared} bool get shared => platform.shared; + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.onData} + Future Function(HttpRequest request)? get onData => platform.onData; + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.start} Future start() => platform.start(); diff --git a/flutter_inappwebview_platform_interface/CHANGELOG.md b/flutter_inappwebview_platform_interface/CHANGELOG.md index 8f5781b7f..18e127b0c 100644 --- a/flutter_inappwebview_platform_interface/CHANGELOG.md +++ b/flutter_inappwebview_platform_interface/CHANGELOG.md @@ -1,6 +1,7 @@ #### 1.4.0 - Updated static `fromMap` implementation for some classes +- Added `PlatformInAppLocalhostServer.onData` parameter to set a custom on data server callback ## 1.3.0+1 diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_localhost_server.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_localhost_server.dart index f1805c109..3cd048b90 100755 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_localhost_server.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_localhost_server.dart @@ -38,6 +38,7 @@ class DefaultInAppLocalhostServer extends PlatformInAppLocalhostServer { bool _shared = false; String _directoryIndex = 'index.html'; String _documentRoot = './'; + Future Function(HttpRequest)? _customOnData; /// Creates a new [DefaultInAppLocalhostServer]. DefaultInAppLocalhostServer(PlatformInAppLocalhostServerCreationParams params) @@ -53,6 +54,7 @@ class DefaultInAppLocalhostServer extends PlatformInAppLocalhostServer { ? params.documentRoot : '${params.documentRoot}/'; this._shared = params.shared; + this._customOnData = params.onData; } @override @@ -67,6 +69,9 @@ class DefaultInAppLocalhostServer extends PlatformInAppLocalhostServer { @override bool get shared => _shared; + @override + Future Function(HttpRequest request)? get onData => _customOnData; + @override Future start() async { if (this._started) { @@ -78,11 +83,19 @@ class DefaultInAppLocalhostServer extends PlatformInAppLocalhostServer { runZonedGuarded(() { HttpServer.bind('127.0.0.1', _port, shared: _shared).then((server) { - print('Server running on http://localhost:' + _port.toString()); + if (kDebugMode) { + print('Server running on http://localhost:' + _port.toString()); + } this._server = server; server.listen((HttpRequest request) async { + if (await _customOnData?.call(request) ?? false) { + // if _customOnData returns true, + // it means that the request has been handled + return; + } + Uint8List body = Uint8List(0); var path = request.requestedUri.path; @@ -99,8 +112,10 @@ class DefaultInAppLocalhostServer extends PlatformInAppLocalhostServer { .buffer .asUint8List(); } catch (e) { - print(Uri.decodeFull(path)); - print(e.toString()); + if (kDebugMode) { + print(Uri.decodeFull(path)); + print(e.toString()); + } request.response.close(); return; } @@ -115,13 +130,18 @@ class DefaultInAppLocalhostServer extends PlatformInAppLocalhostServer { } request.response.headers.contentType = contentType; + print(request.response.headers); request.response.add(body); request.response.close(); }); completer.complete(); }); - }, (e, stackTrace) => print('Error: $e $stackTrace')); + }, (e, stackTrace) { + if (kDebugMode) { + print('Error: $e $stackTrace'); + } + }); return completer.future; } @@ -132,7 +152,9 @@ class DefaultInAppLocalhostServer extends PlatformInAppLocalhostServer { return; } await this._server!.close(force: true); - print('Server running on http://localhost:$_port closed'); + if (kDebugMode) { + print('Server running on http://localhost:$_port closed'); + } this._started = false; this._server = null; } diff --git a/flutter_inappwebview_platform_interface/lib/src/platform_in_app_localhost_server.dart b/flutter_inappwebview_platform_interface/lib/src/platform_in_app_localhost_server.dart index 39e004d4d..72a60dc8c 100755 --- a/flutter_inappwebview_platform_interface/lib/src/platform_in_app_localhost_server.dart +++ b/flutter_inappwebview_platform_interface/lib/src/platform_in_app_localhost_server.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; @@ -16,6 +17,7 @@ class PlatformInAppLocalhostServerCreationParams { this.directoryIndex = 'index.html', this.documentRoot = './', this.shared = false, + this.onData = null, }); ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.port} @@ -29,6 +31,9 @@ class PlatformInAppLocalhostServerCreationParams { ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.shared} final bool shared; + + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.onData} + final Future Function(HttpRequest request)? onData; } ///{@template flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer} @@ -40,6 +45,7 @@ class PlatformInAppLocalhostServerCreationParams { ///- Android native WebView ///- iOS ///- MacOS +///- Windows ///{@endtemplate} abstract class PlatformInAppLocalhostServer extends PlatformInterface { /// Creates a new [PlatformInAppLocalhostServer] @@ -98,6 +104,14 @@ abstract class PlatformInAppLocalhostServer extends PlatformInterface { ///{@endtemplate} bool get shared => params.shared; + ///{@template flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.onData} + ///A custom callback that is called when a new request is received by the server + ///that can be used to send or modify the response, for example adding custom headers. + ///If this callback returns `true`, it means that the request has been handled by this callback. + ///Otherwise, if this callback returns `false`, the server will continue to process the request using the default implementation. + ///{@endtemplate} + Future Function(HttpRequest request)? get onData => params.onData; + ///{@template flutter_inappwebview_platform_interface.PlatformInAppLocalhostServer.start} ///Starts the server on `http://localhost:[port]/`. /// diff --git a/flutter_inappwebview_web/CHANGELOG.md b/flutter_inappwebview_web/CHANGELOG.md index 6a1c66e2a..01f42810f 100644 --- a/flutter_inappwebview_web/CHANGELOG.md +++ b/flutter_inappwebview_web/CHANGELOG.md @@ -1,6 +1,7 @@ ## 1.2.0 - Updated flutter_inappwebview_platform_interface version to ^1.4.0 +- Merged "[web] support iframe role and aria-hidden attributes" [2293](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2293) (thanks to [p-mazhnik](https://github.com/p-mazhnik)) ## 1.1.2 From bd80276e4c31886e7169173a81b823758d0f2bd3 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:20:11 +0000 Subject: [PATCH 022/137] update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 413b1099f..40b6a54d6 100755 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-87-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-88-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -195,6 +195,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d nlog (solrin)
nlog (solrin)

đź’» Murmurl912
Murmurl912

đź’» Benjamin Schulz
Benjamin Schulz

🤔 + seal-app
seal-app

🤔 From b0938cac1e2d190b8ad151a039103a0b2c08451e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:20:12 +0000 Subject: [PATCH 023/137] update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3de04dfc7..02b905b32 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -793,6 +793,15 @@ "contributions": [ "ideas" ] + }, + { + "login": "ShuheiSuzuki-07", + "name": "seal-app", + "avatar_url": "https://avatars.githubusercontent.com/u/118415919?v=4", + "profile": "https://github.com/ShuheiSuzuki-07", + "contributions": [ + "ideas" + ] } ], "contributorsPerLine": 7, From 64c507247b0769037068e8c04b5e6b3d14c7f23a Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:20:56 +0000 Subject: [PATCH 024/137] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40b6a54d6..60c5094c6 100755 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d nlog (solrin)
nlog (solrin)

đź’» Murmurl912
Murmurl912

đź’» Benjamin Schulz
Benjamin Schulz

🤔 - seal-app
seal-app

🤔 + seal-app
seal-app

🤔 💻 From 4342a0154b804ab59e7c6a28118061afe290d1dc Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:20:57 +0000 Subject: [PATCH 025/137] update .all-contributorsrc --- .all-contributorsrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 02b905b32..657a7e112 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -800,7 +800,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/118415919?v=4", "profile": "https://github.com/ShuheiSuzuki-07", "contributions": [ - "ideas" + "ideas", + "code" ] } ], From 8813830b78d9878eb6a6e289a1479c81a72a5b9d Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 25 Oct 2024 19:24:09 +0200 Subject: [PATCH 026/137] Update .all-contributorsrc --- .all-contributorsrc | 1 - 1 file changed, 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 657a7e112..b62b3eaa3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -800,7 +800,6 @@ "avatar_url": "https://avatars.githubusercontent.com/u/118415919?v=4", "profile": "https://github.com/ShuheiSuzuki-07", "contributions": [ - "ideas", "code" ] } From 261e6a652c9e3662c7fd8f7e0dd3c4131843755f Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 25 Oct 2024 19:25:17 +0200 Subject: [PATCH 027/137] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 60c5094c6..5ddfc4b01 100755 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d nlog (solrin)
nlog (solrin)

đź’» Murmurl912
Murmurl912

đź’» Benjamin Schulz
Benjamin Schulz

🤔 - seal-app
seal-app

🤔 💻 + seal-app
seal-app

💻 From fa1ee68a284ce47cc1d0359fbb80e4becf1ee10e Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Fri, 25 Oct 2024 22:30:20 +0200 Subject: [PATCH 028/137] androi: Fixed crash when trying to open InAppBrowser with R.menu.menu_main on release mode, updated android activities restore from savedInstanceState --- flutter_inappwebview/CHANGELOG.md | 2 + .../example/android/app/build.gradle | 4 ++ flutter_inappwebview/example/lib/main.dart | 2 - flutter_inappwebview/pubspec.yaml | 10 ++-- flutter_inappwebview_android/CHANGELOG.md | 2 + .../ChromeCustomTabsActivity.java | 14 +++++- .../in_app_browser/InAppBrowserActivity.java | 46 +++++++++++-------- 7 files changed, 53 insertions(+), 27 deletions(-) diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index bb06d1818..43076a33c 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -17,6 +17,8 @@ - Added `CookieManager.flush` method - Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called - Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) +- Fixed crash when trying to open InAppBrowser with R.menu.menu_main on release mode +- Merged "Prevent blank InAppBrowser Activity from being restored" [#1984](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1984) (thanks to [ShuheiSuzuki-07](https://github.com/ShuheiSuzuki-07)) #### macOS and iOS Platforms - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error diff --git a/flutter_inappwebview/example/android/app/build.gradle b/flutter_inappwebview/example/android/app/build.gradle index 50bdc4636..a50a94003 100755 --- a/flutter_inappwebview/example/android/app/build.gradle +++ b/flutter_inappwebview/example/android/app/build.gradle @@ -45,6 +45,10 @@ android { buildTypes { release { + // only for com.pichillilorenzo.flutter_inappwebview_android.R.menu.menu_main + minifyEnabled false + shrinkResources false + // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.debug diff --git a/flutter_inappwebview/example/lib/main.dart b/flutter_inappwebview/example/lib/main.dart index 737612fcf..b6c8efec9 100755 --- a/flutter_inappwebview/example/lib/main.dart +++ b/flutter_inappwebview/example/lib/main.dart @@ -22,8 +22,6 @@ Future main() async { // await Permission.microphone.request(); // await Permission.storage.request(); - await localhostServer.start(); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows) { final availableVersion = await WebViewEnvironment.getAvailableVersion(); assert(availableVersion != null, diff --git a/flutter_inappwebview/pubspec.yaml b/flutter_inappwebview/pubspec.yaml index 80e20c8df..a1306454b 100755 --- a/flutter_inappwebview/pubspec.yaml +++ b/flutter_inappwebview/pubspec.yaml @@ -21,11 +21,11 @@ dependencies: flutter: sdk: flutter flutter_inappwebview_platform_interface: ^1.4.0 - flutter_inappwebview_android: ^1.1.3 - flutter_inappwebview_ios: ^1.1.2 - flutter_inappwebview_macos: ^1.1.2 - flutter_inappwebview_web: ^1.1.2 - flutter_inappwebview_windows: ^0.6.0 + flutter_inappwebview_android: ^1.2.0 + flutter_inappwebview_ios: ^1.2.0 + flutter_inappwebview_macos: ^1.2.0 + flutter_inappwebview_web: ^1.2.0 + flutter_inappwebview_windows: ^0.7.0 dev_dependencies: flutter_test: diff --git a/flutter_inappwebview_android/CHANGELOG.md b/flutter_inappwebview_android/CHANGELOG.md index fec6738d9..6c7cb27ab 100644 --- a/flutter_inappwebview_android/CHANGELOG.md +++ b/flutter_inappwebview_android/CHANGELOG.md @@ -5,6 +5,8 @@ - Added `CookieManager.flush` method - Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called - Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) +- Fixed crash when trying to open InAppBrowser with R.menu.menu_main on release mode +- Merged "Prevent blank InAppBrowser Activity from being restored" [#1984](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1984) (thanks to [ShuheiSuzuki-07](https://github.com/ShuheiSuzuki-07)) ## 1.1.3 diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivity.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivity.java index 444bc25d5..aae335ebb 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivity.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/chrome_custom_tabs/ChromeCustomTabsActivity.java @@ -78,13 +78,23 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.chrome_custom_tabs_layout); Bundle b = getIntent().getExtras(); - if (b == null) return; + if (b == null) { + if (savedInstanceState != null) { + close(); + } + return; + } id = b.getString("id"); String managerId = b.getString("managerId"); manager = ChromeSafariBrowserManager.shared.get(managerId); - if (manager == null || manager.plugin == null || manager.plugin.messenger == null) return; + if (manager == null || manager.plugin == null || manager.plugin.messenger == null) { + if (savedInstanceState != null) { + close(); + } + return; + } manager.browsers.put(id, this); diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java index d2c193b4b..78c763661 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java @@ -51,7 +51,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrowserDelegate, Disposable { protected static final String LOG_TAG = "InAppBrowserActivity"; public static final String METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappbrowser_"; - + @Nullable public Integer windowId; public String id; @@ -77,24 +77,29 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow @Nullable public InAppBrowserChannelDelegate channelDelegate; public List menuItems = new ArrayList<>(); - + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (savedInstanceState != null) { - finish(); + Bundle b = getIntent().getExtras(); + if (b == null) { + if (savedInstanceState != null) { + finish(); + } return; } - Bundle b = getIntent().getExtras(); - if (b == null) return; - id = b.getString("id"); String managerId = b.getString("managerId"); manager = InAppBrowserManager.shared.get(managerId); - if (manager == null || manager.plugin == null|| manager.plugin.messenger == null) return; + if (manager == null || manager.plugin == null || manager.plugin.messenger == null) { + if (savedInstanceState != null) { + finish(); + } + return; + } Map settingsMap = (Map) b.getSerializable("settings"); customSettings.parse(settingsMap); @@ -111,7 +116,7 @@ protected void onCreate(Bundle savedInstanceState) { pullToRefreshLayout.channelDelegate = new PullToRefreshChannelDelegate(pullToRefreshLayout, pullToRefreshLayoutChannel); pullToRefreshLayout.settings = pullToRefreshSettings; pullToRefreshLayout.prepare(); - + webView = findViewById(R.id.webView); webView.id = id; webView.windowId = windowId; @@ -171,15 +176,13 @@ protected void onCreate(Bundle savedInstanceState) { Log.e(LOG_TAG, initialFile + " asset file cannot be found!", e); return; } - } - else if (initialData != null) { + } else if (initialData != null) { String mimeType = b.getString("initialMimeType"); String encoding = b.getString("initialEncoding"); String baseUrl = b.getString("initialBaseUrl"); String historyUrl = b.getString("initialHistoryUrl"); webView.loadDataWithBaseURL(baseUrl, initialData, mimeType, encoding, historyUrl); - } - else if (initialUrlRequest != null) { + } else if (initialUrlRequest != null) { URLRequest urlRequest = URLRequest.fromMap(initialUrlRequest); if (urlRequest != null) { webView.loadUrl(urlRequest); @@ -242,8 +245,15 @@ public boolean onCreateOptionsMenu(Menu m) { } MenuInflater inflater = getMenuInflater(); - // Inflate menu to add items to action bar if it is present. - inflater.inflate(R.menu.menu_main, menu); + try { + // Inflate menu to add items to action bar if it is present. + inflater.inflate(R.menu.menu_main, menu); + } catch (Exception e) { + e.printStackTrace(); + Log.e(LOG_TAG, "Cannot inflate com.pichillilorenzo.flutter_inappwebview_android.R.menu.menu_main." + + "To make it work, you need to set minifyEnabled false and shrinkResources false in your build.gradle file."); + return super.onCreateOptionsMenu(m); + } MenuItem menuSearchItem = menu.findItem(R.id.menu_search); if (menuSearchItem != null) { @@ -607,9 +617,9 @@ public List getActivityResultListeners() { } @Override - protected void onActivityResult (int requestCode, - int resultCode, - Intent data) { + protected void onActivityResult(int requestCode, + int resultCode, + Intent data) { for (ActivityResultListener listener : activityResultListeners) { if (listener.onActivityResult(requestCode, resultCode, data)) { return; From 33af65b1d77d80bd7890e0ed02c5ae3d7a8d3c73 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sun, 27 Oct 2024 00:55:22 +0200 Subject: [PATCH 029/137] Added javaScriptHandlerOriginAllowList, pluginScriptsOriginAllowList, pluginScriptsForMainFrameOnly InAppWebViewSettings parameters, Added setJavaScriptBridgeName, getJavaScriptBridgeName static WebView controller methods, Added JavaScriptHandlerFunctionData type, Deprecated JavaScriptHandlerCallback type in favor of JavaScriptHandlerFunction type, android: Added support for UserScript.forMainFrameOnly parameter, Updated UserScript at document end implementation --- flutter_inappwebview/CHANGELOG.md | 6 + .../lib/in_app_webiew_example.screen.dart | 22 +- flutter_inappwebview/example/lib/main.dart | 2 + .../Flutter/GeneratedPluginRegistrant.swift | 2 - flutter_inappwebview/example/pubspec.yaml | 16 +- .../flutter/generated_plugin_registrant.cc | 3 - .../windows/flutter/generated_plugins.cmake | 1 - .../in_app_webview_controller.dart | 14 +- flutter_inappwebview/pubspec.yaml | 14 +- flutter_inappwebview_android/CHANGELOG.md | 2 + .../ContentBlockerHandler.java | 4 +- .../in_app_browser/InAppBrowserActivity.java | 4 +- .../InterceptAjaxRequestJS.java | 513 +++++++++-------- .../InterceptFetchRequestJS.java | 298 +++++----- .../plugin_scripts_js/JavaScriptBridgeJS.java | 544 ++++++++++-------- .../plugin_scripts_js/OnLoadResourceJS.java | 67 ++- .../OnWindowBlurEventJS.java | 38 +- .../OnWindowFocusEventJS.java | 38 +- .../plugin_scripts_js/PluginScriptsUtil.java | 78 ++- .../plugin_scripts_js/PrintJS.java | 42 +- .../plugin_scripts_js/PromisePolyfillJS.java | 24 +- .../types/JavaScriptHandlerFunctionData.java | 92 +++ .../types/PluginScript.java | 5 +- .../types/UserContentController.java | 185 ++++-- .../types/UserScript.java | 28 +- .../types/WebMessagePort.java | 10 +- .../webview/InAppWebViewInterface.java | 3 +- .../webview/InAppWebViewManager.java | 24 +- .../webview/JavaScriptBridgeInterface.java | 66 ++- .../webview/WebViewChannelDelegate.java | 9 +- .../webview/in_app_webview/InAppWebView.java | 76 ++- .../in_app_webview/InAppWebViewClient.java | 15 +- .../InAppWebViewClientCompat.java | 15 +- .../in_app_webview/InAppWebViewSettings.java | 30 +- .../web_message/WebMessageChannel.java | 2 +- .../web_message/WebMessageListener.java | 5 +- .../example/pubspec.lock | 11 +- .../in_app_webview_controller.dart | 71 ++- flutter_inappwebview_android/pubspec.yaml | 3 +- .../CHANGELOG.md | 3 + .../in_app_webview_keep_alive.dart | 2 +- .../in_app_webview_settings.dart | 38 ++ .../in_app_webview_settings.g.dart | 54 +- .../platform_inappwebview_controller.dart | 32 +- .../types/javascript_handler_callback.dart | 19 +- .../types/javascript_handler_callback.g.dart | 50 ++ .../lib/src/types/main.dart | 9 +- .../lib/src/types/user_script.dart | 12 +- .../lib/src/types/user_script.g.dart | 8 +- 49 files changed, 1652 insertions(+), 957 deletions(-) create mode 100644 flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JavaScriptHandlerFunctionData.java create mode 100644 flutter_inappwebview_platform_interface/lib/src/types/javascript_handler_callback.g.dart diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index 43076a33c..8e1f2980f 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -11,10 +11,16 @@ #### Platform Interface - Updated static `fromMap` implementation for some classes - Added `PlatformInAppLocalhostServer.onData` parameter to set a custom on data server callback +- Added `javaScriptHandlerOriginAllowList`, `pluginScriptsOriginAllowList`, `pluginScriptsForMainFrameOnly` InAppWebViewSettings parameters +- Added `setJavaScriptBridgeName`, `getJavaScriptBridgeName` static WebView controller methods +- Added `JavaScriptHandlerFunctionData` type +- Deprecated `JavaScriptHandlerCallback` type in favor of `JavaScriptHandlerFunction` type #### Android Platform - Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method - Added `CookieManager.flush` method +- Added support for `UserScript.forMainFrameOnly` parameter +- Updated UserScript at document end implementation - Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called - Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) - Fixed crash when trying to open InAppBrowser with R.menu.menu_main on release mode diff --git a/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart b/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart index ce3dbcfd5..48ff62f11 100755 --- a/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart +++ b/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart @@ -21,6 +21,9 @@ class _InAppWebViewExampleScreenState extends State { mediaPlaybackRequiresUserGesture: false, allowsInlineMediaPlayback: true, iframeAllow: "camera; microphone", + javaScriptHandlerOriginAllowList: {".*"}, + pluginScriptsForMainFrameOnly: false, + pluginScriptsOriginAllowList: {"*"}, iframeAllowFullscreen: true); PullToRefreshController? pullToRefreshController; @@ -116,16 +119,31 @@ class _InAppWebViewExampleScreenState extends State { key: webViewKey, webViewEnvironment: webViewEnvironment, initialUrlRequest: - URLRequest(url: WebUri('https://flutter.dev')), + URLRequest(url: WebUri('https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_iframe')), // initialUrlRequest: // URLRequest(url: WebUri(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')), // initialFile: "assets/index.html", - initialUserScripts: UnmodifiableListView([]), + // initialUserScripts: UnmodifiableListView([]), initialSettings: settings, contextMenu: contextMenu, pullToRefreshController: pullToRefreshController, + initialUserScripts: UnmodifiableListView([ + UserScript( + source: "console.log('loaded'); window.custom_js_bridge.callHandler('handlerName', 1, 4, true, {\"foo\": \"bar\"});", + injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END, + allowedOriginRules: {"https://www.w3schools.com", "https://www.example.com"}, + forMainFrameOnly: false), + ]), onWebViewCreated: (controller) async { webViewController = controller; + controller.addJavaScriptHandler(handlerName: 'handlerName', callback: (JavaScriptHandlerFunctionData handlerData) { + print(handlerData); + return handlerData.args; + }); + controller.addJavaScriptHandler(handlerName: 'handlerName2', callback: (arguments) { + print(arguments); + return arguments; + }); }, onLoadStart: (controller, url) async { setState(() { diff --git a/flutter_inappwebview/example/lib/main.dart b/flutter_inappwebview/example/lib/main.dart index b6c8efec9..70ef5ae02 100755 --- a/flutter_inappwebview/example/lib/main.dart +++ b/flutter_inappwebview/example/lib/main.dart @@ -35,6 +35,8 @@ Future main() async { await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode); } + await InAppWebViewController.setJavaScriptBridgeName('custom_js_bridge'); + runApp(MyApp()); } diff --git a/flutter_inappwebview/example/macos/Flutter/GeneratedPluginRegistrant.swift b/flutter_inappwebview/example/macos/Flutter/GeneratedPluginRegistrant.swift index 959e5aa02..a1cdfd0cd 100644 --- a/flutter_inappwebview/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/flutter_inappwebview/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,12 +5,10 @@ import FlutterMacOS import Foundation -import flutter_inappwebview_macos import path_provider_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/flutter_inappwebview/example/pubspec.yaml b/flutter_inappwebview/example/pubspec.yaml index 0efca4a07..60f326604 100755 --- a/flutter_inappwebview/example/pubspec.yaml +++ b/flutter_inappwebview/example/pubspec.yaml @@ -37,14 +37,14 @@ dependency_overrides: path: ../../flutter_inappwebview_platform_interface flutter_inappwebview_android: path: ../../flutter_inappwebview_android - flutter_inappwebview_ios: - path: ../../flutter_inappwebview_ios - flutter_inappwebview_macos: - path: ../../flutter_inappwebview_macos - flutter_inappwebview_web: - path: ../../flutter_inappwebview_web - flutter_inappwebview_windows: - path: ../../flutter_inappwebview_windows +# flutter_inappwebview_ios: +# path: ../../flutter_inappwebview_ios +# flutter_inappwebview_macos: +# path: ../../flutter_inappwebview_macos +# flutter_inappwebview_web: +# path: ../../flutter_inappwebview_web +# flutter_inappwebview_windows: +# path: ../../flutter_inappwebview_windows dev_dependencies: flutter_test: diff --git a/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.cc b/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.cc index 031b86957..a0d0bbebf 100644 --- a/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.cc +++ b/flutter_inappwebview/example/windows/flutter/generated_plugin_registrant.cc @@ -6,13 +6,10 @@ #include "generated_plugin_registrant.h" -#include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { - FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/flutter_inappwebview/example/windows/flutter/generated_plugins.cmake b/flutter_inappwebview/example/windows/flutter/generated_plugins.cmake index 997d0b803..c20a586d1 100644 --- a/flutter_inappwebview/example/windows/flutter/generated_plugins.cmake +++ b/flutter_inappwebview/example/windows/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - flutter_inappwebview_windows permission_handler_windows url_launcher_windows ) diff --git a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart index 0232fac93..12d3efa97 100644 --- a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart @@ -167,12 +167,12 @@ class InAppWebViewController { ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.addJavaScriptHandler} void addJavaScriptHandler( {required String handlerName, - required JavaScriptHandlerCallback callback}) => + required Function callback}) => platform.addJavaScriptHandler( handlerName: handlerName, callback: callback); ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.removeJavaScriptHandler} - JavaScriptHandlerCallback? removeJavaScriptHandler( + Function? removeJavaScriptHandler( {required String handlerName}) => platform.removeJavaScriptHandler(handlerName: handlerName); @@ -570,6 +570,16 @@ class InAppWebViewController { PlatformInAppWebViewController.static() .enableSlowWholeDocumentDraw(); + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.setJavaScriptBridgeName} + static Future setJavaScriptBridgeName(String bridgeName) => + PlatformInAppWebViewController.static() + .setJavaScriptBridgeName(bridgeName); + + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.getJavaScriptBridgeName} + static Future getJavaScriptBridgeName() => + PlatformInAppWebViewController.static() + .getJavaScriptBridgeName(); + ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.tRexRunnerHtml} static Future get tRexRunnerHtml => PlatformInAppWebViewController.static().tRexRunnerHtml; diff --git a/flutter_inappwebview/pubspec.yaml b/flutter_inappwebview/pubspec.yaml index a1306454b..b498bbfed 100755 --- a/flutter_inappwebview/pubspec.yaml +++ b/flutter_inappwebview/pubspec.yaml @@ -20,12 +20,14 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_platform_interface: ^1.4.0 - flutter_inappwebview_android: ^1.2.0 - flutter_inappwebview_ios: ^1.2.0 - flutter_inappwebview_macos: ^1.2.0 - flutter_inappwebview_web: ^1.2.0 - flutter_inappwebview_windows: ^0.7.0 + flutter_inappwebview_platform_interface: #^1.4.0 + path: ../flutter_inappwebview_platform_interface + flutter_inappwebview_android: #^1.2.0 + path: ../flutter_inappwebview_android +# flutter_inappwebview_ios: ^1.2.0 +# flutter_inappwebview_macos: ^1.2.0 +# flutter_inappwebview_web: ^1.2.0 +# flutter_inappwebview_windows: ^0.7.0 dev_dependencies: flutter_test: diff --git a/flutter_inappwebview_android/CHANGELOG.md b/flutter_inappwebview_android/CHANGELOG.md index 6c7cb27ab..7de8e4034 100644 --- a/flutter_inappwebview_android/CHANGELOG.md +++ b/flutter_inappwebview_android/CHANGELOG.md @@ -3,6 +3,8 @@ - Updated flutter_inappwebview_platform_interface version to ^1.4.0 - Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method - Added `CookieManager.flush` method +- Added support for `UserScript.forMainFrameOnly` parameter +- Updated UserScript at document end implementation - Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called - Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) - Fixed crash when trying to open InAppBrowser with R.menu.menu_main on release mode diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerHandler.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerHandler.java index 8564dbe82..8a3e862a8 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerHandler.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/content_blocker/ContentBlockerHandler.java @@ -157,9 +157,9 @@ public void run() { final String cssSelector = action.getSelector(); final String jsScript = "(function(d) { " + " function hide () { " + - " if (d.body != null && !d.getElementById('" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "-css-display-none-style')) { " + + " if (d.body != null && !d.getElementById('" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "-css-display-none-style')) { " + " var c = d.createElement('style'); " + - " c.id = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "-css-display-none-style'; " + + " c.id = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "-css-display-none-style'; " + " c.innerHTML = '" + cssSelector + " { display: none !important; }'; " + " d.body.appendChild(c); " + " }" + diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java index 78c763661..0fee8e3cf 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/in_app_browser/InAppBrowserActivity.java @@ -541,8 +541,8 @@ public void setSettings(InAppBrowserSettings newSettings, HashMap getCustomSettings() { - Map webViewSettingsMap = webView != null ? webView.getCustomSettings() : null; + public Map getCustomSettingsMap() { + Map webViewSettingsMap = webView != null ? webView.getCustomSettingsMap() : null; if (customSettings == null || webViewSettingsMap == null) return null; diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptAjaxRequestJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptAjaxRequestJS.java index 2ec2e0178..c1b26fb40 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptAjaxRequestJS.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptAjaxRequestJS.java @@ -1,266 +1,285 @@ package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; +import androidx.annotation.Nullable; + import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; +import java.util.Set; + public class InterceptAjaxRequestJS { public static final String INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT"; - public static final String FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE = JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._useShouldInterceptAjaxRequest"; - public static final String FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE = JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._interceptOnlyAsyncAjaxRequests"; - public static final PluginScript INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = new PluginScript( - InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - true, - null - ); + public static String FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() { + return + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._useShouldInterceptAjaxRequest"; + } + public static String FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE() { + return + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._interceptOnlyAsyncAjaxRequests"; + } + public static PluginScript INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, + boolean forMainFrameOnly) { + return + new PluginScript( + InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, + InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_SOURCE(), + UserScriptInjectionTime.AT_DOCUMENT_START, + null, + true, + allowedOriginRules, + forMainFrameOnly + ); + } public static PluginScript createInterceptOnlyAsyncAjaxRequestsPluginScript(boolean onlyAsync) { return new PluginScript( InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - "window." + FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE + " = " + onlyAsync +";", + "window." + FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE() + " = " + onlyAsync +";", UserScriptInjectionTime.AT_DOCUMENT_START, null, true, - null + null, + false ); } - public static final String INTERCEPT_AJAX_REQUEST_JS_SOURCE = "(function(ajax) {" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " = true;" + - " var send = ajax.prototype.send;" + - " var open = ajax.prototype.open;" + - " var setRequestHeader = ajax.prototype.setRequestHeader;" + - " ajax.prototype._flutter_inappwebview_url = null;" + - " ajax.prototype._flutter_inappwebview_method = null;" + - " ajax.prototype._flutter_inappwebview_isAsync = null;" + - " ajax.prototype._flutter_inappwebview_user = null;" + - " ajax.prototype._flutter_inappwebview_password = null;" + - " ajax.prototype._flutter_inappwebview_password = null;" + - " ajax.prototype._flutter_inappwebview_already_onreadystatechange_wrapped = false;" + - " ajax.prototype._flutter_inappwebview_request_headers = {};" + - " function convertRequestResponse(request, callback) {" + - " if (request.response != null && request.responseType != null) {" + - " switch (request.responseType) {" + - " case 'arraybuffer':" + - " callback(new Uint8Array(request.response));" + - " return;" + - " case 'blob':" + - " const reader = new FileReader();" + - " reader.addEventListener('loadend', function() { " + - " callback(new Uint8Array(reader.result));" + - " });" + - " reader.readAsArrayBuffer(blob);" + - " return;" + - " case 'document':" + - " callback(request.response.documentElement.outerHTML);" + - " return;" + - " case 'json':" + - " callback(request.response);" + - " return;" + - " };" + - " }" + - " callback(null);" + - " };" + - " ajax.prototype.open = function(method, url, isAsync, user, password) {" + - " isAsync = (isAsync != null) ? isAsync : true;" + - " this._flutter_inappwebview_url = url;" + - " this._flutter_inappwebview_method = method;" + - " this._flutter_inappwebview_isAsync = isAsync;" + - " this._flutter_inappwebview_user = user;" + - " this._flutter_inappwebview_password = password;" + - " this._flutter_inappwebview_request_headers = {};" + - " open.call(this, method, url, isAsync, user, password);" + - " };" + - " ajax.prototype.setRequestHeader = function(header, value) {" + - " this._flutter_inappwebview_request_headers[header] = value;" + - " setRequestHeader.call(this, header, value);" + - " };" + - " function handleEvent(e) {" + - " var self = this;" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == true) {" + - " var headers = this.getAllResponseHeaders();" + - " var responseHeaders = {};" + - " if (headers != null) {" + - " var arr = headers.trim().split(/[\\r\\n]+/);" + - " arr.forEach(function (line) {" + - " var parts = line.split(': ');" + - " var header = parts.shift();" + - " var value = parts.join(': ');" + - " responseHeaders[header] = value;" + - " });" + - " }" + - " convertRequestResponse(this, function(response) {" + - " var ajaxRequest = {" + - " method: self._flutter_inappwebview_method," + - " url: self._flutter_inappwebview_url," + - " isAsync: self._flutter_inappwebview_isAsync," + - " user: self._flutter_inappwebview_user," + - " password: self._flutter_inappwebview_password," + - " withCredentials: self.withCredentials," + - " headers: self._flutter_inappwebview_request_headers," + - " readyState: self.readyState," + - " status: self.status," + - " responseURL: self.responseURL," + - " responseType: self.responseType," + - " response: response," + - " responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null," + - " responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null," + - " statusText: self.statusText," + - " responseHeaders, responseHeaders," + - " event: {" + - " type: e.type," + - " loaded: e.loaded," + - " lengthComputable: e.lengthComputable," + - " total: e.total" + - " }" + - " };" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onAjaxProgress', ajaxRequest).then(function(result) {" + - " if (result != null) {" + - " switch (result) {" + - " case 0:" + - " self.abort();" + - " return;" + - " };" + - " }" + - " });" + - " });" + - " }" + - " };" + - " ajax.prototype.send = function(data) {" + - " var self = this;" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " var canBeIntercepted = self._flutter_inappwebview_isAsync || w." + FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE + " === false;" + - " if (canBeIntercepted && (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == true)) {" + - " if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) {" + - " this._flutter_inappwebview_already_onreadystatechange_wrapped = true;" + - " var onreadystatechange = this.onreadystatechange;" + - " this.onreadystatechange = function() {" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " == true) {" + - " var headers = this.getAllResponseHeaders();" + - " var responseHeaders = {};" + - " if (headers != null) {" + - " var arr = headers.trim().split(/[\\r\\n]+/);" + - " arr.forEach(function (line) {" + - " var parts = line.split(': ');" + - " var header = parts.shift();" + - " var value = parts.join(': ');" + - " responseHeaders[header] = value;" + - " });" + - " }" + - " convertRequestResponse(this, function(response) {" + - " var ajaxRequest = {" + - " method: self._flutter_inappwebview_method," + - " url: self._flutter_inappwebview_url," + - " isAsync: self._flutter_inappwebview_isAsync," + - " user: self._flutter_inappwebview_user," + - " password: self._flutter_inappwebview_password," + - " withCredentials: self.withCredentials," + - " headers: self._flutter_inappwebview_request_headers," + - " readyState: self.readyState," + - " status: self.status," + - " responseURL: self.responseURL," + - " responseType: self.responseType," + - " response: response," + - " responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null," + - " responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null," + - " statusText: self.statusText," + - " responseHeaders: responseHeaders" + - " };" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) {" + - " if (result != null) {" + - " switch (result) {" + - " case 0:" + - " self.abort();" + - " return;" + - " };" + - " }" + - " if (onreadystatechange != null) {" + - " onreadystatechange();" + - " }" + - " });" + - " });" + - " } else if (onreadystatechange != null) {" + - " onreadystatechange();" + - " }" + - " };" + - " }" + - " this.addEventListener('loadstart', handleEvent);" + - " this.addEventListener('load', handleEvent);" + - " this.addEventListener('loadend', handleEvent);" + - " this.addEventListener('progress', handleEvent);" + - " this.addEventListener('error', handleEvent);" + - " this.addEventListener('abort', handleEvent);" + - " this.addEventListener('timeout', handleEvent);" + - " " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".convertBodyRequest(data).then(function(data) {" + - " var ajaxRequest = {" + - " data: data," + - " method: self._flutter_inappwebview_method," + - " url: self._flutter_inappwebview_url," + - " isAsync: self._flutter_inappwebview_isAsync," + - " user: self._flutter_inappwebview_user," + - " password: self._flutter_inappwebview_password," + - " withCredentials: self.withCredentials," + - " headers: self._flutter_inappwebview_request_headers," + - " responseType: self.responseType" + - " };" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('shouldInterceptAjaxRequest', ajaxRequest).then(function(result) {" + - " if (result != null) {" + - " switch (result) {" + - " case 0:" + - " self.abort();" + - " return;" + - " };" + - " if (result.data != null && !" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".isString(result.data) && result.data.length > 0) {" + - " var bodyString = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".arrayBufferToString(result.data);" + - " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".isBodyFormData(bodyString)) {" + - " var formDataContentType = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".getFormDataContentType(bodyString);" + - " if (result.headers != null) {" + - " result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type'];" + - " } else {" + - " result.headers = { 'Content-Type': formDataContentType };" + - " }" + - " }" + - " }" + - " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".isString(result.data) || result.data == null) {" + - " data = result.data;" + - " } else if (result.data.length > 0) {" + - " data = new Uint8Array(result.data);" + - " }" + - " self.withCredentials = result.withCredentials;" + - " if (result.responseType != null && self._flutter_inappwebview_isAsync) {" + - " self.responseType = result.responseType;" + - " };" + - " for (var header in result.headers) {" + - " var value = result.headers[header];" + - " var flutter_inappwebview_value = self._flutter_inappwebview_request_headers[header];" + - " if (flutter_inappwebview_value == null) {" + - " self._flutter_inappwebview_request_headers[header] = value;" + - " } else {" + - " self._flutter_inappwebview_request_headers[header] += ', ' + value;" + - " }" + - " setRequestHeader.call(self, header, value);" + - " };" + - " if ((self._flutter_inappwebview_method != result.method && result.method != null) ||" + - " (self._flutter_inappwebview_url != result.url && result.url != null) ||" + - " (self._flutter_inappwebview_isAsync != result.isAsync && result.isAsync != null) ||" + - " (self._flutter_inappwebview_user != result.user && result.user != null) ||" + - " (self._flutter_inappwebview_password != result.password && result.password != null)) {" + - " self.abort();" + - " self.open(result.method, result.url, result.isAsync, result.user, result.password);" + - " }" + - " }" + - " send.call(self, data);" + - " });" + - " });" + - " } else {" + - " send.call(this, data);" + - " }" + - " };" + - "})(window.XMLHttpRequest);"; + public static String INTERCEPT_AJAX_REQUEST_JS_SOURCE() { + return + "(function(ajax) {" + + " var w = (window.top == null || window.top === window) ? window : window.top;" + + " w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " = true;" + + " var send = ajax.prototype.send;" + + " var open = ajax.prototype.open;" + + " var setRequestHeader = ajax.prototype.setRequestHeader;" + + " ajax.prototype._flutter_inappwebview_url = null;" + + " ajax.prototype._flutter_inappwebview_method = null;" + + " ajax.prototype._flutter_inappwebview_isAsync = null;" + + " ajax.prototype._flutter_inappwebview_user = null;" + + " ajax.prototype._flutter_inappwebview_password = null;" + + " ajax.prototype._flutter_inappwebview_password = null;" + + " ajax.prototype._flutter_inappwebview_already_onreadystatechange_wrapped = false;" + + " ajax.prototype._flutter_inappwebview_request_headers = {};" + + " function convertRequestResponse(request, callback) {" + + " if (request.response != null && request.responseType != null) {" + + " switch (request.responseType) {" + + " case 'arraybuffer':" + + " callback(new Uint8Array(request.response));" + + " return;" + + " case 'blob':" + + " const reader = new FileReader();" + + " reader.addEventListener('loadend', function() { " + + " callback(new Uint8Array(reader.result));" + + " });" + + " reader.readAsArrayBuffer(blob);" + + " return;" + + " case 'document':" + + " callback(request.response.documentElement.outerHTML);" + + " return;" + + " case 'json':" + + " callback(request.response);" + + " return;" + + " };" + + " }" + + " callback(null);" + + " };" + + " ajax.prototype.open = function(method, url, isAsync, user, password) {" + + " isAsync = (isAsync != null) ? isAsync : true;" + + " this._flutter_inappwebview_url = url;" + + " this._flutter_inappwebview_method = method;" + + " this._flutter_inappwebview_isAsync = isAsync;" + + " this._flutter_inappwebview_user = user;" + + " this._flutter_inappwebview_password = password;" + + " this._flutter_inappwebview_request_headers = {};" + + " open.call(this, method, url, isAsync, user, password);" + + " };" + + " ajax.prototype.setRequestHeader = function(header, value) {" + + " this._flutter_inappwebview_request_headers[header] = value;" + + " setRequestHeader.call(this, header, value);" + + " };" + + " function handleEvent(e) {" + + " var self = this;" + + " var w = (window.top == null || window.top === window) ? window : window.top;" + + " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == true) {" + + " var headers = this.getAllResponseHeaders();" + + " var responseHeaders = {};" + + " if (headers != null) {" + + " var arr = headers.trim().split(/[\\r\\n]+/);" + + " arr.forEach(function (line) {" + + " var parts = line.split(': ');" + + " var header = parts.shift();" + + " var value = parts.join(': ');" + + " responseHeaders[header] = value;" + + " });" + + " }" + + " convertRequestResponse(this, function(response) {" + + " var ajaxRequest = {" + + " method: self._flutter_inappwebview_method," + + " url: self._flutter_inappwebview_url," + + " isAsync: self._flutter_inappwebview_isAsync," + + " user: self._flutter_inappwebview_user," + + " password: self._flutter_inappwebview_password," + + " withCredentials: self.withCredentials," + + " headers: self._flutter_inappwebview_request_headers," + + " readyState: self.readyState," + + " status: self.status," + + " responseURL: self.responseURL," + + " responseType: self.responseType," + + " response: response," + + " responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null," + + " responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null," + + " statusText: self.statusText," + + " responseHeaders, responseHeaders," + + " event: {" + + " type: e.type," + + " loaded: e.loaded," + + " lengthComputable: e.lengthComputable," + + " total: e.total" + + " }" + + " };" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onAjaxProgress', ajaxRequest).then(function(result) {" + + " if (result != null) {" + + " switch (result) {" + + " case 0:" + + " self.abort();" + + " return;" + + " };" + + " }" + + " });" + + " });" + + " }" + + " };" + + " ajax.prototype.send = function(data) {" + + " var self = this;" + + " var w = (window.top == null || window.top === window) ? window : window.top;" + + " var canBeIntercepted = self._flutter_inappwebview_isAsync || w." + FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE() + " === false;" + + " if (canBeIntercepted && (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == true)) {" + + " if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) {" + + " this._flutter_inappwebview_already_onreadystatechange_wrapped = true;" + + " var onreadystatechange = this.onreadystatechange;" + + " this.onreadystatechange = function() {" + + " var w = (window.top == null || window.top === window) ? window : window.top;" + + " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE() + " == true) {" + + " var headers = this.getAllResponseHeaders();" + + " var responseHeaders = {};" + + " if (headers != null) {" + + " var arr = headers.trim().split(/[\\r\\n]+/);" + + " arr.forEach(function (line) {" + + " var parts = line.split(': ');" + + " var header = parts.shift();" + + " var value = parts.join(': ');" + + " responseHeaders[header] = value;" + + " });" + + " }" + + " convertRequestResponse(this, function(response) {" + + " var ajaxRequest = {" + + " method: self._flutter_inappwebview_method," + + " url: self._flutter_inappwebview_url," + + " isAsync: self._flutter_inappwebview_isAsync," + + " user: self._flutter_inappwebview_user," + + " password: self._flutter_inappwebview_password," + + " withCredentials: self.withCredentials," + + " headers: self._flutter_inappwebview_request_headers," + + " readyState: self.readyState," + + " status: self.status," + + " responseURL: self.responseURL," + + " responseType: self.responseType," + + " response: response," + + " responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null," + + " responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null," + + " statusText: self.statusText," + + " responseHeaders: responseHeaders" + + " };" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) {" + + " if (result != null) {" + + " switch (result) {" + + " case 0:" + + " self.abort();" + + " return;" + + " };" + + " }" + + " if (onreadystatechange != null) {" + + " onreadystatechange();" + + " }" + + " });" + + " });" + + " } else if (onreadystatechange != null) {" + + " onreadystatechange();" + + " }" + + " };" + + " }" + + " this.addEventListener('loadstart', handleEvent);" + + " this.addEventListener('load', handleEvent);" + + " this.addEventListener('loadend', handleEvent);" + + " this.addEventListener('progress', handleEvent);" + + " this.addEventListener('error', handleEvent);" + + " this.addEventListener('abort', handleEvent);" + + " this.addEventListener('timeout', handleEvent);" + + " " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertBodyRequest(data).then(function(data) {" + + " var ajaxRequest = {" + + " data: data," + + " method: self._flutter_inappwebview_method," + + " url: self._flutter_inappwebview_url," + + " isAsync: self._flutter_inappwebview_isAsync," + + " user: self._flutter_inappwebview_user," + + " password: self._flutter_inappwebview_password," + + " withCredentials: self.withCredentials," + + " headers: self._flutter_inappwebview_request_headers," + + " responseType: self.responseType" + + " };" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('shouldInterceptAjaxRequest', ajaxRequest).then(function(result) {" + + " if (result != null) {" + + " switch (result) {" + + " case 0:" + + " self.abort();" + + " return;" + + " };" + + " if (result.data != null && !" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isString(result.data) && result.data.length > 0) {" + + " var bodyString = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".arrayBufferToString(result.data);" + + " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isBodyFormData(bodyString)) {" + + " var formDataContentType = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".getFormDataContentType(bodyString);" + + " if (result.headers != null) {" + + " result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type'];" + + " } else {" + + " result.headers = { 'Content-Type': formDataContentType };" + + " }" + + " }" + + " }" + + " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isString(result.data) || result.data == null) {" + + " data = result.data;" + + " } else if (result.data.length > 0) {" + + " data = new Uint8Array(result.data);" + + " }" + + " self.withCredentials = result.withCredentials;" + + " if (result.responseType != null && self._flutter_inappwebview_isAsync) {" + + " self.responseType = result.responseType;" + + " };" + + " for (var header in result.headers) {" + + " var value = result.headers[header];" + + " var flutter_inappwebview_value = self._flutter_inappwebview_request_headers[header];" + + " if (flutter_inappwebview_value == null) {" + + " self._flutter_inappwebview_request_headers[header] = value;" + + " } else {" + + " self._flutter_inappwebview_request_headers[header] += ', ' + value;" + + " }" + + " setRequestHeader.call(self, header, value);" + + " };" + + " if ((self._flutter_inappwebview_method != result.method && result.method != null) ||" + + " (self._flutter_inappwebview_url != result.url && result.url != null) ||" + + " (self._flutter_inappwebview_isAsync != result.isAsync && result.isAsync != null) ||" + + " (self._flutter_inappwebview_user != result.user && result.user != null) ||" + + " (self._flutter_inappwebview_password != result.password && result.password != null)) {" + + " self.abort();" + + " self.open(result.method, result.url, result.isAsync, result.user, result.password);" + + " }" + + " }" + + " send.call(self, data);" + + " });" + + " });" + + " } else {" + + " send.call(this, data);" + + " }" + + " };" + + "})(window.XMLHttpRequest);"; + } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptFetchRequestJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptFetchRequestJS.java index eebff12cb..316f62244 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptFetchRequestJS.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/InterceptFetchRequestJS.java @@ -1,152 +1,166 @@ package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; +import androidx.annotation.Nullable; + import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; +import java.util.Set; + public class InterceptFetchRequestJS { public static final String INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT"; - public static final String FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE = JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._useShouldInterceptFetchRequest"; - public static final PluginScript INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT = new PluginScript( - InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, - InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - true, - null - ); - public static final String INTERCEPT_FETCH_REQUEST_JS_SOURCE = "(function(fetch) {" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE + " = true;" + - " if (fetch == null) {" + - " return;" + - " }" + - " window.fetch = async function(resource, init) {" + - " var w = (window.top == null || window.top === window) ? window : window.top;" + - " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE + " == true) {" + - " var fetchRequest = {" + - " url: null," + - " method: null," + - " headers: null," + - " body: null," + - " mode: null," + - " credentials: null," + - " cache: null," + - " redirect: null," + - " referrer: null," + - " referrerPolicy: null," + - " integrity: null," + - " keepalive: null" + - " };" + - " if (resource instanceof Request) {" + - " fetchRequest.url = resource.url;" + - " fetchRequest.method = resource.method;" + - " fetchRequest.headers = resource.headers;" + - " fetchRequest.body = resource.body;" + - " fetchRequest.mode = resource.mode;" + - " fetchRequest.credentials = resource.credentials;" + - " fetchRequest.cache = resource.cache;" + - " fetchRequest.redirect = resource.redirect;" + - " fetchRequest.referrer = resource.referrer;" + - " fetchRequest.referrerPolicy = resource.referrerPolicy;" + - " fetchRequest.integrity = resource.integrity;" + - " fetchRequest.keepalive = resource.keepalive;" + - " } else {" + - " fetchRequest.url = resource != null ? resource.toString() : null;" + - " if (init != null) {" + - " fetchRequest.method = init.method;" + - " fetchRequest.headers = init.headers;" + - " fetchRequest.body = init.body;" + - " fetchRequest.mode = init.mode;" + - " fetchRequest.credentials = init.credentials;" + - " fetchRequest.cache = init.cache;" + - " fetchRequest.redirect = init.redirect;" + - " fetchRequest.referrer = init.referrer;" + - " fetchRequest.referrerPolicy = init.referrerPolicy;" + - " fetchRequest.integrity = init.integrity;" + - " fetchRequest.keepalive = init.keepalive;" + - " }" + - " }" + - " if (fetchRequest.headers instanceof Headers) {" + - " fetchRequest.headers = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".convertHeadersToJson(fetchRequest.headers);" + - " }" + - " fetchRequest.credentials = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".convertCredentialsToJson(fetchRequest.credentials);" + - " return " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".convertBodyRequest(fetchRequest.body).then(function(body) {" + - " fetchRequest.body = body;" + - " return window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('shouldInterceptFetchRequest', fetchRequest).then(function(result) {" + - " if (result != null) {" + - " switch (result.action) {" + - " case 0:" + - " var controller = new AbortController();" + - " if (init != null) {" + - " init.signal = controller.signal;" + - " } else {" + - " init = {" + - " signal: controller.signal" + - " };" + - " }" + - " controller.abort();" + - " break;" + - " }" + - " if (result.body != null && !" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".isString(result.body) && result.body.length > 0) {" + - " var bodyString = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".arrayBufferToString(result.body);" + - " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".isBodyFormData(bodyString)) {" + - " var formDataContentType = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".getFormDataContentType(bodyString);" + - " if (result.headers != null) {" + - " result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type'];" + - " } else {" + - " result.headers = { 'Content-Type': formDataContentType };" + - " }" + - " }" + - " }" + - " resource = result.url;" + - " if (init == null) {" + - " init = {};" + - " }" + - " if (result.method != null && result.method.length > 0) {" + - " init.method = result.method;" + - " }" + - " if (result.headers != null && Object.keys(result.headers).length > 0) {" + - " init.headers = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".convertJsonToHeaders(result.headers);" + - " }" + - " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".isString(result.body) || result.body == null) {" + - " init.body = result.body;" + - " } else if (result.body.length > 0) {" + - " init.body = new Uint8Array(result.body);" + - " }" + - " if (result.mode != null && result.mode.length > 0) {" + - " init.mode = result.mode;" + - " }" + - " if (result.credentials != null) {" + - " init.credentials = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME + ".convertJsonToCredential(result.credentials);" + - " }" + - " if (result.cache != null && result.cache.length > 0) {" + - " init.cache = result.cache;" + - " }" + - " if (result.redirect != null && result.redirect.length > 0) {" + - " init.redirect = result.redirect;" + - " }" + - " if (result.referrer != null && result.referrer.length > 0) {" + - " init.referrer = result.referrer;" + - " }" + - " if (result.referrerPolicy != null && result.referrerPolicy.length > 0) {" + - " init.referrerPolicy = result.referrerPolicy;" + - " }" + - " if (result.integrity != null && result.integrity.length > 0) {" + - " init.integrity = result.integrity;" + - " }" + - " if (result.keepalive != null) {" + - " init.keepalive = result.keepalive;" + - " }" + - " return fetch(resource, init);" + - " }" + - " return fetch(resource, init);" + - " });" + - " });" + - " } else {" + - " return fetch(resource, init);" + - " }" + - " };" + - "})(window.fetch);"; + public static String FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() { + return JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._useShouldInterceptFetchRequest"; + } + + public static PluginScript INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, + boolean forMainFrameOnly) { + return new PluginScript( + InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, + InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_SOURCE(), + UserScriptInjectionTime.AT_DOCUMENT_START, + null, + true, + allowedOriginRules, + forMainFrameOnly + ); + } + + public static String INTERCEPT_FETCH_REQUEST_JS_SOURCE() { + return "(function(fetch) {" + + " var w = (window.top == null || window.top === window) ? window : window.top;" + + " w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() + " = true;" + + " if (fetch == null) {" + + " return;" + + " }" + + " window.fetch = async function(resource, init) {" + + " var w = (window.top == null || window.top === window) ? window : window.top;" + + " if (w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() + " == null || w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE() + " == true) {" + + " var fetchRequest = {" + + " url: null," + + " method: null," + + " headers: null," + + " body: null," + + " mode: null," + + " credentials: null," + + " cache: null," + + " redirect: null," + + " referrer: null," + + " referrerPolicy: null," + + " integrity: null," + + " keepalive: null" + + " };" + + " if (resource instanceof Request) {" + + " fetchRequest.url = resource.url;" + + " fetchRequest.method = resource.method;" + + " fetchRequest.headers = resource.headers;" + + " fetchRequest.body = resource.body;" + + " fetchRequest.mode = resource.mode;" + + " fetchRequest.credentials = resource.credentials;" + + " fetchRequest.cache = resource.cache;" + + " fetchRequest.redirect = resource.redirect;" + + " fetchRequest.referrer = resource.referrer;" + + " fetchRequest.referrerPolicy = resource.referrerPolicy;" + + " fetchRequest.integrity = resource.integrity;" + + " fetchRequest.keepalive = resource.keepalive;" + + " } else {" + + " fetchRequest.url = resource != null ? resource.toString() : null;" + + " if (init != null) {" + + " fetchRequest.method = init.method;" + + " fetchRequest.headers = init.headers;" + + " fetchRequest.body = init.body;" + + " fetchRequest.mode = init.mode;" + + " fetchRequest.credentials = init.credentials;" + + " fetchRequest.cache = init.cache;" + + " fetchRequest.redirect = init.redirect;" + + " fetchRequest.referrer = init.referrer;" + + " fetchRequest.referrerPolicy = init.referrerPolicy;" + + " fetchRequest.integrity = init.integrity;" + + " fetchRequest.keepalive = init.keepalive;" + + " }" + + " }" + + " if (fetchRequest.headers instanceof Headers) {" + + " fetchRequest.headers = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertHeadersToJson(fetchRequest.headers);" + + " }" + + " fetchRequest.credentials = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertCredentialsToJson(fetchRequest.credentials);" + + " return " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertBodyRequest(fetchRequest.body).then(function(body) {" + + " fetchRequest.body = body;" + + " return window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('shouldInterceptFetchRequest', fetchRequest).then(function(result) {" + + " if (result != null) {" + + " switch (result.action) {" + + " case 0:" + + " var controller = new AbortController();" + + " if (init != null) {" + + " init.signal = controller.signal;" + + " } else {" + + " init = {" + + " signal: controller.signal" + + " };" + + " }" + + " controller.abort();" + + " break;" + + " }" + + " if (result.body != null && !" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isString(result.body) && result.body.length > 0) {" + + " var bodyString = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".arrayBufferToString(result.body);" + + " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isBodyFormData(bodyString)) {" + + " var formDataContentType = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".getFormDataContentType(bodyString);" + + " if (result.headers != null) {" + + " result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type'];" + + " } else {" + + " result.headers = { 'Content-Type': formDataContentType };" + + " }" + + " }" + + " }" + + " resource = result.url;" + + " if (init == null) {" + + " init = {};" + + " }" + + " if (result.method != null && result.method.length > 0) {" + + " init.method = result.method;" + + " }" + + " if (result.headers != null && Object.keys(result.headers).length > 0) {" + + " init.headers = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertJsonToHeaders(result.headers);" + + " }" + + " if (" + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".isString(result.body) || result.body == null) {" + + " init.body = result.body;" + + " } else if (result.body.length > 0) {" + + " init.body = new Uint8Array(result.body);" + + " }" + + " if (result.mode != null && result.mode.length > 0) {" + + " init.mode = result.mode;" + + " }" + + " if (result.credentials != null) {" + + " init.credentials = " + JavaScriptBridgeJS.JAVASCRIPT_UTIL_VAR_NAME() + ".convertJsonToCredential(result.credentials);" + + " }" + + " if (result.cache != null && result.cache.length > 0) {" + + " init.cache = result.cache;" + + " }" + + " if (result.redirect != null && result.redirect.length > 0) {" + + " init.redirect = result.redirect;" + + " }" + + " if (result.referrer != null && result.referrer.length > 0) {" + + " init.referrer = result.referrer;" + + " }" + + " if (result.referrerPolicy != null && result.referrerPolicy.length > 0) {" + + " init.referrerPolicy = result.referrerPolicy;" + + " }" + + " if (result.integrity != null && result.integrity.length > 0) {" + + " init.integrity = result.integrity;" + + " }" + + " if (result.keepalive != null) {" + + " init.keepalive = result.keepalive;" + + " }" + + " return fetch(resource, init);" + + " }" + + " return fetch(resource, init);" + + " });" + + " });" + + " } else {" + + " return fetch(resource, init);" + + " }" + + " };" + + "})(window.fetch);"; + } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java index 55659d479..58c58517e 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java @@ -1,250 +1,318 @@ package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.pichillilorenzo.flutter_inappwebview_android.Util; import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; +import java.util.Set; + public class JavaScriptBridgeJS { - public static final String JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"; + @NonNull + private static String _JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"; + + public static void set_JAVASCRIPT_BRIDGE_NAME(@NonNull String bridgeName) { + _JAVASCRIPT_BRIDGE_NAME = bridgeName; + } + + @NonNull + public static String JAVASCRIPT_BRIDGE_NAME() { + return _JAVASCRIPT_BRIDGE_NAME; + } + public static final String JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT"; - public static final PluginScript JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT = new PluginScript( - JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME, - JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - true, - null - ); - public static final String JAVASCRIPT_UTIL_VAR_NAME = "window." + JAVASCRIPT_BRIDGE_NAME + "._Util"; - public static final String WEB_MESSAGE_CHANNELS_VARIABLE_NAME = "window." + JAVASCRIPT_BRIDGE_NAME + "._webMessageChannels"; + private static final String VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET = "$IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_BRIDGE_SECRET"; + + public static PluginScript JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(@NonNull String expectedBridgeSecret, + @Nullable Set allowedOriginRules, + boolean forMainFrameOnly) { + String source = Util.replaceAll(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_SOURCE(), VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET, expectedBridgeSecret); + return new PluginScript( + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME, + source, + UserScriptInjectionTime.AT_DOCUMENT_START, + null, + true, + allowedOriginRules, + forMainFrameOnly + ); + } + + public static String JAVASCRIPT_UTIL_VAR_NAME() { + return "window." + JAVASCRIPT_BRIDGE_NAME() + "._Util"; + } + + public static String WEB_MESSAGE_CHANNELS_VARIABLE_NAME() { + return "window." + JAVASCRIPT_BRIDGE_NAME() + "._webMessageChannels"; + } - public static final String UTIL_JS_SOURCE = JAVASCRIPT_UTIL_VAR_NAME + " = {" + - " support: {" + - " searchParams: 'URLSearchParams' in window," + - " iterable: 'Symbol' in window && 'iterator' in Symbol," + - " blob:" + - " 'FileReader' in window &&" + - " 'Blob' in window &&" + - " (function() {" + - " try {" + - " new Blob();" + - " return true;" + - " } catch (e) {" + - " return false;" + - " }" + - " })()," + - " formData: 'FormData' in window," + - " arrayBuffer: 'ArrayBuffer' in window" + - " }," + - " isDataView: function(obj) {" + - " return obj && DataView.prototype.isPrototypeOf(obj);" + - " }," + - " fileReaderReady: function(reader) {" + - " return new Promise(function(resolve, reject) {" + - " reader.onload = function() {" + - " resolve(reader.result);" + - " };" + - " reader.onerror = function() {" + - " reject(reader.error);" + - " };" + - " });" + - " }," + - " readBlobAsArrayBuffer: function(blob) {" + - " var reader = new FileReader();" + - " var promise = " + JAVASCRIPT_UTIL_VAR_NAME + ".fileReaderReady(reader);" + - " reader.readAsArrayBuffer(blob);" + - " return promise;" + - " }," + - " convertBodyToArrayBuffer: function(body) {" + - " var viewClasses = [" + - " '[object Int8Array]'," + - " '[object Uint8Array]'," + - " '[object Uint8ClampedArray]'," + - " '[object Int16Array]'," + - " '[object Uint16Array]'," + - " '[object Int32Array]'," + - " '[object Uint32Array]'," + - " '[object Float32Array]'," + - " '[object Float64Array]'" + - " ];" + - " var isArrayBufferView = null;" + - " if (" + JAVASCRIPT_UTIL_VAR_NAME + ".support.arrayBuffer) {" + - " isArrayBufferView =" + - " ArrayBuffer.isView ||" + - " function(obj) {" + - " return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;" + - " };" + - " }" + - " var bodyUsed = false;" + - " this._bodyInit = body;" + - " if (!body) {" + - " this._bodyText = '';" + - " } else if (typeof body === 'string') {" + - " this._bodyText = body;" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME + ".support.blob && Blob.prototype.isPrototypeOf(body)) {" + - " this._bodyBlob = body;" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME + ".support.formData && FormData.prototype.isPrototypeOf(body)) {" + - " this._bodyFormData = body;" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME + ".support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {" + - " this._bodyText = body.toString();" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME + ".support.arrayBuffer && " + JAVASCRIPT_UTIL_VAR_NAME + ".support.blob && " + JAVASCRIPT_UTIL_VAR_NAME + ".isDataView(body)) {" + - " this._bodyArrayBuffer = bufferClone(body.buffer);" + - " this._bodyInit = new Blob([this._bodyArrayBuffer]);" + - " } else if (" + JAVASCRIPT_UTIL_VAR_NAME + ".support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {" + - " this._bodyArrayBuffer = bufferClone(body);" + - " } else {" + - " this._bodyText = body = Object.prototype.toString.call(body);" + - " }" + - " this.blob = function () {" + - " if (bodyUsed) {" + - " return Promise.reject(new TypeError('Already read'));" + - " }" + - " bodyUsed = true;" + - " if (this._bodyBlob) {" + - " return Promise.resolve(this._bodyBlob);" + - " } else if (this._bodyArrayBuffer) {" + - " return Promise.resolve(new Blob([this._bodyArrayBuffer]));" + - " } else if (this._bodyFormData) {" + - " throw new Error('could not read FormData body as blob');" + - " } else {" + - " return Promise.resolve(new Blob([this._bodyText]));" + - " }" + - " };" + - " if (this._bodyArrayBuffer) {" + - " if (bodyUsed) {" + - " return Promise.reject(new TypeError('Already read'));" + - " }" + - " bodyUsed = true;" + - " if (ArrayBuffer.isView(this._bodyArrayBuffer)) {" + - " return Promise.resolve(" + - " this._bodyArrayBuffer.buffer.slice(" + - " this._bodyArrayBuffer.byteOffset," + - " this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength" + - " )" + - " );" + - " } else {" + - " return Promise.resolve(this._bodyArrayBuffer);" + - " }" + - " }" + - " return this.blob().then(" + JAVASCRIPT_UTIL_VAR_NAME + ".readBlobAsArrayBuffer);" + - " }," + - " isString: function(variable) {" + - " return typeof variable === 'string' || variable instanceof String;" + - " }," + - " convertBodyRequest: function(body) {" + - " if (body == null) {" + - " return new Promise(function(resolve, reject) { resolve(null); });" + - " }" + - " if (" + JAVASCRIPT_UTIL_VAR_NAME + ".isString(body) || (" + JAVASCRIPT_UTIL_VAR_NAME + ".support.searchParams && body instanceof URLSearchParams)) {" + - " return new Promise(function(resolve, reject) { resolve(body.toString()); });" + - " }" + - " if (window.Response != null) {" + - " return new Response(body).arrayBuffer().then(function(arrayBuffer) {" + - " return Array.from(new Uint8Array(arrayBuffer));" + - " });" + - " }" + - " return " + JAVASCRIPT_UTIL_VAR_NAME + ".convertBodyToArrayBuffer(body).then(function(arrayBuffer) {" + - " return Array.from(new Uint8Array(arrayBuffer));" + - " });" + - " }," + - " arrayBufferToString: function(arrayBuffer) {" + - " var uint8Array = new Uint8Array(arrayBuffer);" + - " return uint8Array.reduce(function(acc, i) { return acc += String.fromCharCode.apply(null, [i]); }, '');" + - " }," + - " isBodyFormData: function(bodyString) {" + - " return bodyString.indexOf('------WebKitFormBoundary') >= 0;" + - " }," + - " getFormDataContentType: function(bodyString) {" + - " var boundary = bodyString.substr(2, 40);" + - " return 'multipart/form-data; boundary=' + boundary;" + - " }," + - " convertHeadersToJson: function(headers) {" + - " var headersObj = {};" + - " for (var header of headers.keys()) {" + - " var value = headers.get(header);" + - " headersObj[header] = value;" + - " }" + - " return headersObj;" + - " }," + - " convertJsonToHeaders: function(headersJson) {" + - " return new Headers(headersJson);" + - " }," + - " convertCredentialsToJson: function(credentials) {" + - " var credentialsObj = {};" + - " if (window.FederatedCredential != null && credentials instanceof FederatedCredential) {" + - " credentialsObj.type = credentials.type;" + - " credentialsObj.id = credentials.id;" + - " credentialsObj.name = credentials.name;" + - " credentialsObj.protocol = credentials.protocol;" + - " credentialsObj.provider = credentials.provider;" + - " credentialsObj.iconURL = credentials.iconURL;" + - " } else if (window.PasswordCredential != null && credentials instanceof PasswordCredential) {" + - " credentialsObj.type = credentials.type;" + - " credentialsObj.id = credentials.id;" + - " credentialsObj.name = credentials.name;" + - " credentialsObj.password = credentials.password;" + - " credentialsObj.iconURL = credentials.iconURL;" + - " } else {" + - " credentialsObj.type = 'default';" + - " credentialsObj.value = credentials;" + - " }" + - " return credentialsObj;" + - " }," + - " convertJsonToCredential: function(credentialsJson) {" + - " var credentials;" + - " if (window.FederatedCredential != null && credentialsJson.type === 'federated') {" + - " credentials = new FederatedCredential({" + - " id: credentialsJson.id," + - " name: credentialsJson.name," + - " protocol: credentialsJson.protocol," + - " provider: credentialsJson.provider," + - " iconURL: credentialsJson.iconURL" + - " });" + - " } else if (window.PasswordCredential != null && credentialsJson.type === 'password') {" + - " credentials = new PasswordCredential({" + - " id: credentialsJson.id," + - " name: credentialsJson.name," + - " password: credentialsJson.password," + - " iconURL: credentialsJson.iconURL" + - " });" + - " } else {" + - " credentials = credentialsJson.value == null ? undefined : credentialsJson.value;" + - " }" + - " return credentials;" + - " }" + - "};"; + public static String UTIL_JS_SOURCE() { + return JAVASCRIPT_UTIL_VAR_NAME() + " = {" + + " support: {" + + " searchParams: 'URLSearchParams' in window," + + " iterable: 'Symbol' in window && 'iterator' in Symbol," + + " blob:" + + " 'FileReader' in window &&" + + " 'Blob' in window &&" + + " (function() {" + + " try {" + + " new Blob();" + + " return true;" + + " } catch (e) {" + + " return false;" + + " }" + + " })()," + + " formData: 'FormData' in window," + + " arrayBuffer: 'ArrayBuffer' in window" + + " }," + + " isDataView: function(obj) {" + + " return obj && DataView.prototype.isPrototypeOf(obj);" + + " }," + + " fileReaderReady: function(reader) {" + + " return new Promise(function(resolve, reject) {" + + " reader.onload = function() {" + + " resolve(reader.result);" + + " };" + + " reader.onerror = function() {" + + " reject(reader.error);" + + " };" + + " });" + + " }," + + " readBlobAsArrayBuffer: function(blob) {" + + " var reader = new FileReader();" + + " var promise = " + JAVASCRIPT_UTIL_VAR_NAME() + ".fileReaderReady(reader);" + + " reader.readAsArrayBuffer(blob);" + + " return promise;" + + " }," + + " convertBodyToArrayBuffer: function(body) {" + + " var viewClasses = [" + + " '[object Int8Array]'," + + " '[object Uint8Array]'," + + " '[object Uint8ClampedArray]'," + + " '[object Int16Array]'," + + " '[object Uint16Array]'," + + " '[object Int32Array]'," + + " '[object Uint32Array]'," + + " '[object Float32Array]'," + + " '[object Float64Array]'" + + " ];" + + " var isArrayBufferView = null;" + + " if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.arrayBuffer) {" + + " isArrayBufferView =" + + " ArrayBuffer.isView ||" + + " function(obj) {" + + " return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;" + + " };" + + " }" + + " var bodyUsed = false;" + + " this._bodyInit = body;" + + " if (!body) {" + + " this._bodyText = '';" + + " } else if (typeof body === 'string') {" + + " this._bodyText = body;" + + " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.blob && Blob.prototype.isPrototypeOf(body)) {" + + " this._bodyBlob = body;" + + " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.formData && FormData.prototype.isPrototypeOf(body)) {" + + " this._bodyFormData = body;" + + " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {" + + " this._bodyText = body.toString();" + + " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.arrayBuffer && " + JAVASCRIPT_UTIL_VAR_NAME() + ".support.blob && " + JAVASCRIPT_UTIL_VAR_NAME() + ".isDataView(body)) {" + + " this._bodyArrayBuffer = bufferClone(body.buffer);" + + " this._bodyInit = new Blob([this._bodyArrayBuffer]);" + + " } else if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {" + + " this._bodyArrayBuffer = bufferClone(body);" + + " } else {" + + " this._bodyText = body = Object.prototype.toString.call(body);" + + " }" + + " this.blob = function () {" + + " if (bodyUsed) {" + + " return Promise.reject(new TypeError('Already read'));" + + " }" + + " bodyUsed = true;" + + " if (this._bodyBlob) {" + + " return Promise.resolve(this._bodyBlob);" + + " } else if (this._bodyArrayBuffer) {" + + " return Promise.resolve(new Blob([this._bodyArrayBuffer]));" + + " } else if (this._bodyFormData) {" + + " throw new Error('could not read FormData body as blob');" + + " } else {" + + " return Promise.resolve(new Blob([this._bodyText]));" + + " }" + + " };" + + " if (this._bodyArrayBuffer) {" + + " if (bodyUsed) {" + + " return Promise.reject(new TypeError('Already read'));" + + " }" + + " bodyUsed = true;" + + " if (ArrayBuffer.isView(this._bodyArrayBuffer)) {" + + " return Promise.resolve(" + + " this._bodyArrayBuffer.buffer.slice(" + + " this._bodyArrayBuffer.byteOffset," + + " this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength" + + " )" + + " );" + + " } else {" + + " return Promise.resolve(this._bodyArrayBuffer);" + + " }" + + " }" + + " return this.blob().then(" + JAVASCRIPT_UTIL_VAR_NAME() + ".readBlobAsArrayBuffer);" + + " }," + + " isString: function(variable) {" + + " return typeof variable === 'string' || variable instanceof String;" + + " }," + + " convertBodyRequest: function(body) {" + + " if (body == null) {" + + " return new Promise(function(resolve, reject) { resolve(null); });" + + " }" + + " if (" + JAVASCRIPT_UTIL_VAR_NAME() + ".isString(body) || (" + JAVASCRIPT_UTIL_VAR_NAME() + ".support.searchParams && body instanceof URLSearchParams)) {" + + " return new Promise(function(resolve, reject) { resolve(body.toString()); });" + + " }" + + " if (window.Response != null) {" + + " return new Response(body).arrayBuffer().then(function(arrayBuffer) {" + + " return Array.from(new Uint8Array(arrayBuffer));" + + " });" + + " }" + + " return " + JAVASCRIPT_UTIL_VAR_NAME() + ".convertBodyToArrayBuffer(body).then(function(arrayBuffer) {" + + " return Array.from(new Uint8Array(arrayBuffer));" + + " });" + + " }," + + " arrayBufferToString: function(arrayBuffer) {" + + " var uint8Array = new Uint8Array(arrayBuffer);" + + " return uint8Array.reduce(function(acc, i) { return acc += String.fromCharCode.apply(null, [i]); }, '');" + + " }," + + " isBodyFormData: function(bodyString) {" + + " return bodyString.indexOf('------WebKitFormBoundary') >= 0;" + + " }," + + " getFormDataContentType: function(bodyString) {" + + " var boundary = bodyString.substr(2, 40);" + + " return 'multipart/form-data; boundary=' + boundary;" + + " }," + + " convertHeadersToJson: function(headers) {" + + " var headersObj = {};" + + " for (var header of headers.keys()) {" + + " var value = headers.get(header);" + + " headersObj[header] = value;" + + " }" + + " return headersObj;" + + " }," + + " convertJsonToHeaders: function(headersJson) {" + + " return new Headers(headersJson);" + + " }," + + " convertCredentialsToJson: function(credentials) {" + + " var credentialsObj = {};" + + " if (window.FederatedCredential != null && credentials instanceof FederatedCredential) {" + + " credentialsObj.type = credentials.type;" + + " credentialsObj.id = credentials.id;" + + " credentialsObj.name = credentials.name;" + + " credentialsObj.protocol = credentials.protocol;" + + " credentialsObj.provider = credentials.provider;" + + " credentialsObj.iconURL = credentials.iconURL;" + + " } else if (window.PasswordCredential != null && credentials instanceof PasswordCredential) {" + + " credentialsObj.type = credentials.type;" + + " credentialsObj.id = credentials.id;" + + " credentialsObj.name = credentials.name;" + + " credentialsObj.password = credentials.password;" + + " credentialsObj.iconURL = credentials.iconURL;" + + " } else {" + + " credentialsObj.type = 'default';" + + " credentialsObj.value = credentials;" + + " }" + + " return credentialsObj;" + + " }," + + " convertJsonToCredential: function(credentialsJson) {" + + " var credentials;" + + " if (window.FederatedCredential != null && credentialsJson.type === 'federated') {" + + " credentials = new FederatedCredential({" + + " id: credentialsJson.id," + + " name: credentialsJson.name," + + " protocol: credentialsJson.protocol," + + " provider: credentialsJson.provider," + + " iconURL: credentialsJson.iconURL" + + " });" + + " } else if (window.PasswordCredential != null && credentialsJson.type === 'password') {" + + " credentials = new PasswordCredential({" + + " id: credentialsJson.id," + + " name: credentialsJson.name," + + " password: credentialsJson.password," + + " iconURL: credentialsJson.iconURL" + + " });" + + " } else {" + + " credentials = credentialsJson.value == null ? undefined : credentialsJson.value;" + + " }" + + " return credentials;" + + " }" + + "};"; + } - public static final String JAVASCRIPT_BRIDGE_JS_SOURCE = "if (window." + JAVASCRIPT_BRIDGE_NAME + " != null) {" + - " window." + JAVASCRIPT_BRIDGE_NAME + ".callHandler = function() {" + - " var _callHandlerID = setTimeout(function(){});" + - " window." + JAVASCRIPT_BRIDGE_NAME + "._callHandler(arguments[0], _callHandlerID, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" + - " return new Promise(function(resolve, reject) {" + - " window." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = {resolve: resolve, reject: reject};" + - " });" + - " };" + - "}"+ - "if (window.top != null && window.top !== window && window." + JAVASCRIPT_BRIDGE_NAME + " == null) {" + - " window." + JAVASCRIPT_BRIDGE_NAME + " = {};" + - " window." + JAVASCRIPT_BRIDGE_NAME + ".callHandler = function() {" + - " var _callHandlerID = setTimeout(function(){});" + - " try {" + - " window.top." + JAVASCRIPT_BRIDGE_NAME + "._callHandler(arguments[0], _callHandlerID, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" + - " return new Promise(function(resolve, reject) {" + - " window.top." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = {resolve: resolve, reject: reject};" + - " });" + - " } catch (error) {" + - " return new Promise(function(resolve, reject) { reject(error); });" + - " }" + - " };" + - "}" + - "if (window." + JAVASCRIPT_BRIDGE_NAME + " != null) {" + - " " + UTIL_JS_SOURCE + - "}"; + public static String JAVASCRIPT_BRIDGE_JS_SOURCE() { + return "if (window." + JAVASCRIPT_BRIDGE_NAME() + " != null) {" + + " (function (window) {" + + " var bridgeSecret = '" + VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET + "';" + + " var origin = '';" + + " var isMainFrame = false;" + + " try {" + + " origin = window.location.origin;" + + " } catch (_) {}" + + " try {" + + " isMainFrame = window.self === window.top;" + + " } catch (_) {}" + + " window." + JAVASCRIPT_BRIDGE_NAME() + ".callHandler = function() {" + + " if (arguments == null || arguments[0] == null || arguments[0] === '') {" + + " return new Promise(function(resolve, reject) { reject('Handler name is undefined, null or empty'); });" + + " }" + + " var _callHandlerID = setTimeout(function(){});" + + " window." + JAVASCRIPT_BRIDGE_NAME() + "._callHandler(arguments[0], _callHandlerID, bridgeSecret, origin, isMainFrame, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" + + " return new Promise(function(resolve, reject) {" + + " try {" + + " (isMainFrame ? window : window.top)." + JAVASCRIPT_BRIDGE_NAME() + "[_callHandlerID] = {resolve: resolve, reject: reject};" + + " } catch(e) { reject(e); }" + + " });" + + " };" + + " })(window);" + + "}" + + "if (window.top != null && window.top !== window && window." + JAVASCRIPT_BRIDGE_NAME() + " == null) {" + + " window." + JAVASCRIPT_BRIDGE_NAME() + " = {};" + + " (function (window) {" + + " var bridgeSecret = '" + VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET + "';" + + " var origin = '';" + + " var isMainFrame = false;" + + " try {" + + " origin = window.location.origin;" + + " } catch (_) {}" + + " try {" + + " isMainFrame = window.self === window.top;" + + " } catch (_) {}" + + " window." + JAVASCRIPT_BRIDGE_NAME() + ".callHandler = function() {" + + " if (arguments == null || arguments[0] == null || arguments[0] === '') {" + + " return new Promise(function(resolve, reject) { reject('Handler name is undefined, null or empty'); });" + + " }" + + " var _callHandlerID = setTimeout(function(){});" + + " console.log(window.self === window.top, window.location.href, 'TEST TEST', window.top." + JAVASCRIPT_BRIDGE_NAME() + ");" + + " try {" + + " window.top." + JAVASCRIPT_BRIDGE_NAME() + "._callHandler(arguments[0], _callHandlerID, bridgeSecret, origin, isMainFrame, JSON.stringify(Array.prototype.slice.call(arguments, 1)));" + + " return new Promise(function(resolve, reject) {" + + " window.top." + JAVASCRIPT_BRIDGE_NAME() + "[_callHandlerID] = {resolve: resolve, reject: reject};" + + " });" + + " } catch (error) {" + + " return new Promise(function(resolve, reject) { reject(error); });" + + " }" + + " };" + + " })(window);" + + "}" + + "if (window." + JAVASCRIPT_BRIDGE_NAME() + " != null) {" + + " " + UTIL_JS_SOURCE() + + "}"; + } - public static final String PLATFORM_READY_JS_SOURCE = "(function() {" + - " if ((window.top == null || window.top === window) && window." + JAVASCRIPT_BRIDGE_NAME + " != null && window." + JAVASCRIPT_BRIDGE_NAME + "._platformReady == null) {" + - " window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady'));" + - " window." + JAVASCRIPT_BRIDGE_NAME + "._platformReady = true;" + - " }" + - "})();"; + public static String PLATFORM_READY_JS_SOURCE() { + return "(function() {" + + " if ((window.top == null || window.top === window) && window." + JAVASCRIPT_BRIDGE_NAME() + " != null && window." + JAVASCRIPT_BRIDGE_NAME() + "._platformReady == null) {" + + " window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady'));" + + " window." + JAVASCRIPT_BRIDGE_NAME() + "._platformReady = true;" + + " }" + + "})();"; + } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnLoadResourceJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnLoadResourceJS.java index b386bd7de..c7501031a 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnLoadResourceJS.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnLoadResourceJS.java @@ -1,35 +1,50 @@ package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; +import androidx.annotation.Nullable; + import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; +import java.util.Set; + public class OnLoadResourceJS { public static final String ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT"; - public static final String FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE = JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._useOnLoadResource"; - public static final PluginScript ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT = new PluginScript( - OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME, - OnLoadResourceJS.ON_LOAD_RESOURCE_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - null - ); + public static String FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() { + return + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._useOnLoadResource"; + } + public static PluginScript ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, + boolean forMainFrameOnly) { + return + new PluginScript( + OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT_GROUP_NAME, + OnLoadResourceJS.ON_LOAD_RESOURCE_JS_SOURCE(), + UserScriptInjectionTime.AT_DOCUMENT_START, + null, + false, + allowedOriginRules, + forMainFrameOnly + ); + } - public static final String ON_LOAD_RESOURCE_JS_SOURCE = "window." + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE + " = true;" + - "(function() {" + - " var observer = new PerformanceObserver(function(list) {" + - " list.getEntries().forEach(function(entry) {" + - " if (" + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE + " == null || " + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE + " == true) {" + - " var resource = {" + - " 'url': entry.name," + - " 'initiatorType': entry.initiatorType," + - " 'startTime': entry.startTime," + - " 'duration': entry.duration" + - " };" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onLoadResource', resource);" + - " }" + - " });" + - " });" + - " observer.observe({entryTypes: ['resource']});" + - "})();"; + public static String ON_LOAD_RESOURCE_JS_SOURCE() { + return + "window." + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() + " = true;" + + "(function() {" + + " var observer = new PerformanceObserver(function(list) {" + + " list.getEntries().forEach(function(entry) {" + + " if (" + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() + " == null || " + FLAG_VARIABLE_FOR_ON_LOAD_RESOURCE_JS_SOURCE() + " == true) {" + + " var resource = {" + + " 'url': entry.name," + + " 'initiatorType': entry.initiatorType," + + " 'startTime': entry.startTime," + + " 'duration': entry.duration" + + " };" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onLoadResource', resource);" + + " }" + + " });" + + " });" + + " observer.observe({entryTypes: ['resource']});" + + "})();"; + } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowBlurEventJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowBlurEventJS.java index 746f8782a..35a25d704 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowBlurEventJS.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowBlurEventJS.java @@ -1,22 +1,34 @@ package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; +import androidx.annotation.Nullable; + import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; +import java.util.Set; + public class OnWindowBlurEventJS { public static final String ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT"; - public static final PluginScript ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT = new PluginScript( - OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - null - ); + public static PluginScript ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, + boolean forMainFrameOnly) { + return + new PluginScript( + OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, + OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_SOURCE(), + UserScriptInjectionTime.AT_DOCUMENT_START, + null, + false, + allowedOriginRules, + forMainFrameOnly + ); + } - public static final String ON_WINDOW_BLUR_EVENT_JS_SOURCE = "(function(){" + - " window.addEventListener('blur', function(e) {" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onWindowBlur');" + - " });" + - "})();"; + public static String ON_WINDOW_BLUR_EVENT_JS_SOURCE() { + return + "(function(){" + + " window.addEventListener('blur', function(e) {" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onWindowBlur');" + + " });" + + "})();"; + } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowFocusEventJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowFocusEventJS.java index cfdae9a26..7cf3bfe97 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowFocusEventJS.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/OnWindowFocusEventJS.java @@ -1,22 +1,34 @@ package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; +import androidx.annotation.Nullable; + import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; +import java.util.Set; + public class OnWindowFocusEventJS { public static final String ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT"; - public static final PluginScript ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT = new PluginScript( - OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, - OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - null - ); + public static PluginScript ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, + boolean forMainFrameOnly) { + return + new PluginScript( + OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT_GROUP_NAME, + OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_SOURCE(), + UserScriptInjectionTime.AT_DOCUMENT_START, + null, + false, + allowedOriginRules, + forMainFrameOnly + ); + } - public static final String ON_WINDOW_FOCUS_EVENT_JS_SOURCE = "(function(){" + - " window.addEventListener('focus', function(e) {" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onWindowFocus');" + - " });" + - "})();"; + public static String ON_WINDOW_FOCUS_EVENT_JS_SOURCE() { + return + "(function(){" + + " window.addEventListener('focus', function(e) {" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onWindowFocus');" + + " });" + + "})();"; + } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PluginScriptsUtil.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PluginScriptsUtil.java index 91af1fdd1..362378e76 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PluginScriptsUtil.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PluginScriptsUtil.java @@ -1,8 +1,12 @@ package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; +import androidx.annotation.Nullable; + import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; +import java.util.Set; + public class PluginScriptsUtil { public static final String VAR_PLACEHOLDER_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_VALUE"; @@ -16,24 +20,30 @@ public class PluginScriptsUtil { public static final String VAR_RESULT_UUID = "$IN_APP_WEBVIEW_RESULT_UUID"; public static final String VAR_RANDOM_NAME = "$IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME"; - public static final String CALL_ASYNC_JAVA_SCRIPT_WRAPPER_JS_SOURCE = "(function(obj) {" + - " (async function(" + VAR_FUNCTION_ARGUMENT_NAMES + ") {" + - " \n" + VAR_FUNCTION_BODY + "\n" + - " })(" + VAR_FUNCTION_ARGUMENT_VALUES + ").then(function(value) {" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('callAsyncJavaScript', {'value': value, 'error': null, 'resultUuid': '" + VAR_RESULT_UUID + "'});" + - " }).catch(function(error) {" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('callAsyncJavaScript', {'value': null, 'error': error + '', 'resultUuid': '" + VAR_RESULT_UUID + "'});" + - " });" + - " return null;" + - "})(" + VAR_FUNCTION_ARGUMENTS_OBJ + ");"; + public static String CALL_ASYNC_JAVA_SCRIPT_WRAPPER_JS_SOURCE() { + return + "(function(obj) {" + + " (async function(" + VAR_FUNCTION_ARGUMENT_NAMES + ") {" + + " \n" + VAR_FUNCTION_BODY + "\n" + + " })(" + VAR_FUNCTION_ARGUMENT_VALUES + ").then(function(value) {" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('callAsyncJavaScript', {'value': value, 'error': null, 'resultUuid': '" + VAR_RESULT_UUID + "'});" + + " }).catch(function(error) {" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('callAsyncJavaScript', {'value': null, 'error': error + '', 'resultUuid': '" + VAR_RESULT_UUID + "'});" + + " });" + + " return null;" + + "})(" + VAR_FUNCTION_ARGUMENTS_OBJ + ");"; + } - public static final String EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE = "var $IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME = null;" + - "try {" + - " $IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME = eval(" + VAR_PLACEHOLDER_VALUE + ");" + - "} catch(e) {" + - " console.error(e);" + - "}" + - "window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('evaluateJavaScriptWithContentWorld', {'value': $IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME, 'resultUuid': '" + VAR_RESULT_UUID + "'});"; + public static String EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE() { + return + "var $IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME = null;" + + "try {" + + " $IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME = eval(" + VAR_PLACEHOLDER_VALUE + ");" + + "} catch(e) {" + + " console.error(e);" + + "}" + + "window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('evaluateJavaScriptWithContentWorld', {'value': $IN_APP_WEBVIEW_VARIABLE_RANDOM_NAME, 'resultUuid': '" + VAR_RESULT_UUID + "'});"; + } public static final String IS_ACTIVE_ELEMENT_INPUT_EDITABLE_JS_SOURCE = "var activeEl = document.activeElement;" + @@ -71,19 +81,27 @@ public class PluginScriptsUtil { "})();"; public static final String CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT_GROUP_NAME = "CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT"; - public static final PluginScript CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT = new PluginScript( - PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT_GROUP_NAME, - PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - null - ); + public static PluginScript CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, + boolean forMainFrameOnly) { + return + new PluginScript( + PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT_GROUP_NAME, + PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_SOURCE(), + UserScriptInjectionTime.AT_DOCUMENT_START, + null, + false, + allowedOriginRules, + forMainFrameOnly + ); + } // android Workaround to hide context menu when user emit a keydown event - public static final String CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_SOURCE = "(function(){" + - " document.addEventListener('keydown', function(e) {" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._hideContextMenu();" + - " });" + - "})();"; + public static String CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_SOURCE() { + return + "(function(){" + + " document.addEventListener('keydown', function(e) {" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._hideContextMenu();" + + " });" + + "})();"; + } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PrintJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PrintJS.java index bb1084815..c20eeea05 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PrintJS.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PrintJS.java @@ -1,24 +1,36 @@ package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; +import androidx.annotation.Nullable; + import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; +import java.util.Set; + public class PrintJS { public static final String PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_PRINT_JS_PLUGIN_SCRIPT"; - public static final PluginScript PRINT_JS_PLUGIN_SCRIPT = new PluginScript( - PrintJS.PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME, - PrintJS.PRINT_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - false, - null - ); + public static PluginScript PRINT_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, + boolean forMainFrameOnly) { + return + new PluginScript( + PrintJS.PRINT_JS_PLUGIN_SCRIPT_GROUP_NAME, + PrintJS.PRINT_JS_SOURCE(), + UserScriptInjectionTime.AT_DOCUMENT_START, + null, + false, + allowedOriginRules, + forMainFrameOnly + ); + } - public static final String PRINT_JS_SOURCE = "window.print = function() {" + - " if (window.top == null || window.top === window) {" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onPrintRequest', window.location.href);" + - " } else {" + - " window.top.print();" + - " }" + - "};"; + public static String PRINT_JS_SOURCE() { + return + "window.print = function() {" + + " if (window.top == null || window.top === window) {" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onPrintRequest', window.location.href);" + + " } else {" + + " window.top.print();" + + " }" + + "};"; + } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PromisePolyfillJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PromisePolyfillJS.java index af10c5d84..3331c63a0 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PromisePolyfillJS.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/PromisePolyfillJS.java @@ -1,18 +1,26 @@ package com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js; +import androidx.annotation.Nullable; + import com.pichillilorenzo.flutter_inappwebview_android.types.PluginScript; import com.pichillilorenzo.flutter_inappwebview_android.types.UserScriptInjectionTime; +import java.util.Set; + public class PromisePolyfillJS { public static final String PROMISE_POLYFILL_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_PROMISE_POLYFILL_JS_PLUGIN_SCRIPT"; - public static final PluginScript PROMISE_POLYFILL_JS_PLUGIN_SCRIPT = new PluginScript( - PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT_GROUP_NAME, - PromisePolyfillJS.PROMISE_POLYFILL_JS_SOURCE, - UserScriptInjectionTime.AT_DOCUMENT_START, - null, - true, - null - ); + public static final PluginScript PROMISE_POLYFILL_JS_PLUGIN_SCRIPT(@Nullable Set allowedOriginRules, + boolean forMainFrameOnly) { + return new PluginScript( + PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT_GROUP_NAME, + PromisePolyfillJS.PROMISE_POLYFILL_JS_SOURCE, + UserScriptInjectionTime.AT_DOCUMENT_START, + null, + true, + allowedOriginRules, + forMainFrameOnly + ); + } // https://github.com/tildeio/rsvp.js public static final String PROMISE_POLYFILL_JS_SOURCE = "if (window.Promise == null) {" + diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JavaScriptHandlerFunctionData.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JavaScriptHandlerFunctionData.java new file mode 100644 index 000000000..feccffe2e --- /dev/null +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/JavaScriptHandlerFunctionData.java @@ -0,0 +1,92 @@ +package com.pichillilorenzo.flutter_inappwebview_android.types; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class JavaScriptHandlerFunctionData { + @NonNull + private String origin; + private boolean isMainFrame; + @NonNull + private String args; + + public JavaScriptHandlerFunctionData(@NonNull String origin, boolean isMainFrame, @NonNull String args) { + this.origin = origin; + this.isMainFrame = isMainFrame; + this.args = args; + } + + @Nullable + public static JavaScriptHandlerFunctionData fromMap(@Nullable Map map) { + if (map == null) { + return null; + } + String origin = (String) map.get("origin"); + boolean isMainFrame = (boolean) map.get("isMainFrame"); + String args = (String) map.get("args"); + return new JavaScriptHandlerFunctionData(origin, isMainFrame, args); + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("origin", origin); + map.put("isMainFrame", isMainFrame); + map.put("args", args); + return map; + } + + @NonNull + public String getOrigin() { + return origin; + } + + public void setOrigin(@NonNull String origin) { + this.origin = origin; + } + + public boolean isMainFrame() { + return isMainFrame; + } + + public void setMainFrame(boolean mainFrame) { + isMainFrame = mainFrame; + } + + @NonNull + public String getArgs() { + return args; + } + + public void setArgs(@NonNull String args) { + this.args = args; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JavaScriptHandlerFunctionData that = (JavaScriptHandlerFunctionData) o; + return isMainFrame == that.isMainFrame && origin.equals(that.origin) && args.equals(that.args); + } + + @Override + public int hashCode() { + int result = origin.hashCode(); + result = 31 * result + Boolean.hashCode(isMainFrame); + result = 31 * result + args.hashCode(); + return result; + } + + @Override + public String toString() { + return "JavaScriptHandlerFunctionData{" + + "origin='" + origin + '\'' + + ", isMainFrame=" + isMainFrame + + ", args='" + args + '\'' + + '}'; + } +} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PluginScript.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PluginScript.java index b16f22803..a5a95e4ea 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PluginScript.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/PluginScript.java @@ -8,8 +8,9 @@ public class PluginScript extends UserScript { private boolean requiredInAllContentWorlds; - public PluginScript(@Nullable String groupName, @NonNull String source, @NonNull UserScriptInjectionTime injectionTime, @Nullable ContentWorld contentWorld, boolean requiredInAllContentWorlds, @Nullable Set allowedOriginRules) { - super(groupName, source, injectionTime, contentWorld, allowedOriginRules); + public PluginScript(@Nullable String groupName, @NonNull String source, @NonNull UserScriptInjectionTime injectionTime, + @Nullable ContentWorld contentWorld, boolean requiredInAllContentWorlds, @Nullable Set allowedOriginRules, boolean forMainFrameOnly) { + super(groupName, source, injectionTime, contentWorld, allowedOriginRules, forMainFrameOnly); this.requiredInAllContentWorlds = requiredInAllContentWorlds; } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java index f51dd1b93..c392fe6fc 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java @@ -2,6 +2,7 @@ import android.annotation.SuppressLint; import android.text.TextUtils; +import android.util.Log; import android.webkit.WebView; import androidx.annotation.NonNull; @@ -18,6 +19,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; @@ -73,7 +75,7 @@ public String generateWrappedCodeForDocumentEnd() { } js += generatePluginScriptsCodeAt(injectionTime); js += generateUserOnlyScriptsCodeAt(injectionTime); - js = USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE.replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, js); + js = USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE().replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, js); return js; } @@ -83,7 +85,7 @@ public String generateCodeForDocumentStart() { js += generatePluginScriptsCodeAt(injectionTime); js += generateContentWorldsCreatorCode(); js += generateUserOnlyScriptsCodeAt(injectionTime); - js = USER_SCRIPTS_AT_DOCUMENT_START_WRAPPER_JS_SOURCE.replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, js); + js = USER_SCRIPTS_AT_DOCUMENT_START_WRAPPER_JS_SOURCE().replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, js); return js; } @@ -105,7 +107,7 @@ public String generateContentWorldsCreatorCode() { contentWorldsNames.add("'" + escapeContentWorldName(contentWorld.getName()) + "'"); } - return CONTENT_WORLDS_GENERATOR_JS_SOURCE + return CONTENT_WORLDS_GENERATOR_JS_SOURCE() .replace(PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY, TextUtils.join(", ", contentWorldsNames)) .replace(PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED, escapeCode(source.toString())); @@ -116,6 +118,7 @@ public String generatePluginScriptsCodeAt(UserScriptInjectionTime injectionTime) LinkedHashSet scripts = this.getPluginScriptsAt(injectionTime); for (PluginScript script : scripts) { String source = ";" + script.getSource(); + source = wrapSourceCodeAddChecks(script, source); source = wrapSourceCodeInContentWorld(script.getContentWorld(), source); js.append(source); } @@ -127,12 +130,38 @@ public String generateUserOnlyScriptsCodeAt(UserScriptInjectionTime injectionTim LinkedHashSet scripts = this.getUserOnlyScriptsAt(injectionTime); for (UserScript script : scripts) { String source = ";" + script.getSource(); + source = wrapSourceCodeAddChecks(script, source); source = wrapSourceCodeInContentWorld(script.getContentWorld(), source); js.append(source); } return js.toString(); } + private String wrapSourceCodeAddChecks(UserScript script, String source) { + Set allowedOriginRules = script.getAllowedOriginRules(); + StringBuilder ifStatement = new StringBuilder("if ("); + if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT) && (!allowedOriginRules.isEmpty() && !allowedOriginRules.contains("*"))) { + StringBuilder jsRegExpArray = new StringBuilder("["); + for (String allowedOriginRule : allowedOriginRules) { + if (jsRegExpArray.length() > 1) { + jsRegExpArray.append(", "); + } + jsRegExpArray.append("new RegExp(").append(escapeCode(allowedOriginRule)).append(")"); + } + if (jsRegExpArray.length() > 1) { + jsRegExpArray.append("]"); + ifStatement.append(jsRegExpArray).append(".some(function(rx) { return rx.test(window.location.origin); })"); + } + } + if (script.isForMainFrameOnly()) { + if (ifStatement.length() > 4) { + ifStatement.append(" && "); + } + ifStatement.append("window.self === window.top"); + } + return ifStatement.length() > 4 ? ifStatement.append(") {").append(source).append("}").toString() : source; + } + public String generateCodeForScriptEvaluation(String source, @Nullable ContentWorld contentWorld) { if (contentWorld != null && !contentWorld.equals(ContentWorld.PAGE)) { StringBuilder sourceWrapped = new StringBuilder(); @@ -144,7 +173,7 @@ public String generateCodeForScriptEvaluation(String source, @Nullable ContentWo for (PluginScript script : pluginScriptsRequired) { pluginScriptsSource.append(script.getSource()); } - String contentWorldCreatorCode = CONTENT_WORLDS_GENERATOR_JS_SOURCE + String contentWorldCreatorCode = CONTENT_WORLDS_GENERATOR_JS_SOURCE() .replace(PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY, "'" + escapeContentWorldName(contentWorld.getName()) + "'") .replace(PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED, escapeCode(pluginScriptsSource.toString())); sourceWrapped.append(contentWorldCreatorCode).append(";"); @@ -156,7 +185,7 @@ public String generateCodeForScriptEvaluation(String source, @Nullable ContentWo public String wrapSourceCodeInContentWorld(@Nullable ContentWorld contentWorld, String source) { String sourceWrapped = contentWorld == null || contentWorld.equals(ContentWorld.PAGE) ? source : - CONTENT_WORLD_WRAPPER_JS_SOURCE + CONTENT_WORLD_WRAPPER_JS_SOURCE() .replace(PluginScriptsUtil.VAR_CONTENT_WORLD_NAME, escapeContentWorldName(contentWorld.getName())) .replace(PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED, escapeCode(source)); @@ -201,8 +230,14 @@ public boolean addUserOnlyScript(UserScript userOnlyScript) { contentWorlds.add(contentWorld); } this.updateContentWorldsCreatorScript(); - if (webView != null && userOnlyScript.getInjectionTime() == UserScriptInjectionTime.AT_DOCUMENT_START - && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { + if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { + String source = userOnlyScript.getSource(); + if (userOnlyScript.getInjectionTime() == UserScriptInjectionTime.AT_DOCUMENT_END) { + source = "if (document.readyState === 'complete') { " + source + "} else { window.addEventListener('load', function() { " + source + " }); }"; + } + source = wrapSourceCodeAddChecks(userOnlyScript, source); + userOnlyScript.setSource(source); + ScriptHandler scriptHandler = WebViewCompat.addDocumentStartJavaScript( webView, wrapSourceCodeInContentWorld(userOnlyScript.getContentWorld(), userOnlyScript.getSource()), @@ -245,6 +280,13 @@ public void removeAllUserOnlyScripts() { this.scriptHandlerMap.remove(userOnlyScript); } } + for (UserScript userOnlyScript : this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END)) { + ScriptHandler scriptHandler = this.scriptHandlerMap.get(userOnlyScript); + if (scriptHandler != null) { + scriptHandler.remove(); + this.scriptHandlerMap.remove(userOnlyScript); + } + } } this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear(); this.userOnlyScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear(); @@ -271,8 +313,14 @@ public boolean addPluginScript(PluginScript pluginScript) { contentWorlds.add(contentWorld); } this.updateContentWorldsCreatorScript(); - if (webView != null && pluginScript.getInjectionTime() == UserScriptInjectionTime.AT_DOCUMENT_START - && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { + if (webView != null && WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { + String source = pluginScript.getSource(); + if (pluginScript.getInjectionTime() == UserScriptInjectionTime.AT_DOCUMENT_END) { + source = "if (document.readyState === 'complete') { " + source + "} else { window.addEventListener('load', function() { " + source + " }); }"; + } + source = wrapSourceCodeAddChecks(pluginScript, source); + pluginScript.setSource(source); + ScriptHandler scriptHandler = WebViewCompat.addDocumentStartJavaScript( webView, wrapSourceCodeInContentWorld(pluginScript.getContentWorld(), pluginScript.getSource()), @@ -310,6 +358,13 @@ public void removeAllPluginScripts() { this.scriptHandlerMap.remove(pluginScript); } } + for (PluginScript pluginScript : this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END)) { + ScriptHandler scriptHandler = this.scriptHandlerMap.get(pluginScript); + if (scriptHandler != null) { + scriptHandler.remove(); + this.scriptHandlerMap.remove(pluginScript); + } + } } this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear(); this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear(); @@ -402,60 +457,68 @@ public LinkedHashSet getContentWorlds() { return new LinkedHashSet<>(this.contentWorlds); } - private static final String USER_SCRIPTS_AT_DOCUMENT_START_WRAPPER_JS_SOURCE = "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + " != null && (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentStartLoaded == null || !window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentStartLoaded)) {" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentStartLoaded = true;" + - " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + - "}"; + private static String USER_SCRIPTS_AT_DOCUMENT_START_WRAPPER_JS_SOURCE() { + return "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + " != null && (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._userScriptsAtDocumentStartLoaded == null || !window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._userScriptsAtDocumentStartLoaded)) {" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._userScriptsAtDocumentStartLoaded = true;" + + " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + + "}"; + } - private static final String USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE = "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + " != null && (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentEndLoaded == null || !window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentEndLoaded)) {" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._userScriptsAtDocumentEndLoaded = true;" + - " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + - "}"; + private static String USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE() { + return "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + " != null && (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._userScriptsAtDocumentEndLoaded == null || !window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._userScriptsAtDocumentEndLoaded)) {" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._userScriptsAtDocumentEndLoaded = true;" + + " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + + "}"; + } + + private static String CONTENT_WORLDS_GENERATOR_JS_SOURCE() { + return "(function() {" + + " var interval = setInterval(function() {" + + " if (document.body == null) {return;}" + + " var contentWorldNames = [" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY + "];" + + " for (var contentWorldName of contentWorldNames) {" + + " var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "_' + contentWorldName;" + + " var iframe = document.getElementById(iframeId);" + + " if (iframe == null) {" + + " iframe = document.createElement('iframe');" + + " iframe.id = iframeId;" + + " iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" + + " document.body.append(iframe);" + + " }" + + " if (iframe.contentWindow.document.getElementById('" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "_plugin_scripts') == null) {" + + " var script = iframe.contentWindow.document.createElement('script');" + + " script.id = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "_plugin_scripts';" + + " script.innerHTML = " + PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" + + " iframe.contentWindow.document.body.append(script);" + + " }" + + " }" + + " clearInterval(interval);" + + " });" + + "})();"; + } - private static final String CONTENT_WORLDS_GENERATOR_JS_SOURCE = "(function() {" + - " var interval = setInterval(function() {" + - " if (document.body == null) {return;}" + - " var contentWorldNames = [" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME_ARRAY + "];" + - " for (var contentWorldName of contentWorldNames) {" + - " var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_' + contentWorldName;" + - " var iframe = document.getElementById(iframeId);" + - " if (iframe == null) {" + - " iframe = document.createElement('iframe');" + - " iframe.id = iframeId;" + - " iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" + - " document.body.append(iframe);" + - " }" + - " if (iframe.contentWindow.document.getElementById('" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_plugin_scripts') == null) {" + - " var script = iframe.contentWindow.document.createElement('script');" + - " script.id = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_plugin_scripts';" + - " script.innerHTML = " + PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" + - " iframe.contentWindow.document.body.append(script);" + - " }" + - " }" + - " clearInterval(interval);" + - " });" + - "})();"; - - private static final String CONTENT_WORLD_WRAPPER_JS_SOURCE = "(function() {" + - " var interval = setInterval(function() {" + - " if (document.body == null) {return;}" + - " var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME + "';" + - " var iframe = document.getElementById(iframeId);" + - " if (iframe == null) {" + - " iframe = document.createElement('iframe');" + - " iframe.id = iframeId;" + - " iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" + - " document.body.append(iframe);" + - " }" + - " if (iframe.contentWindow.document.querySelector('#" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_plugin_scripts') == null) {" + - " return;" + - " }" + - " var script = iframe.contentWindow.document.createElement('script');" + - " script.innerHTML = " + PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" + - " iframe.contentWindow.document.body.append(script);" + - " clearInterval(interval);" + - " });" + - "})();"; + private static String CONTENT_WORLD_WRAPPER_JS_SOURCE() { + return "(function() {" + + " var interval = setInterval(function() {" + + " if (document.body == null) {return;}" + + " var iframeId = '" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "_" + PluginScriptsUtil.VAR_CONTENT_WORLD_NAME + "';" + + " var iframe = document.getElementById(iframeId);" + + " if (iframe == null) {" + + " iframe = document.createElement('iframe');" + + " iframe.id = iframeId;" + + " iframe.style = 'display: none; z-index: 0; position: absolute; width: 0px; height: 0px';" + + " document.body.append(iframe);" + + " }" + + " if (iframe.contentWindow.document.querySelector('#" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "_plugin_scripts') == null) {" + + " return;" + + " }" + + " var script = iframe.contentWindow.document.createElement('script');" + + " script.innerHTML = " + PluginScriptsUtil.VAR_JSON_SOURCE_ENCODED + ";" + + " iframe.contentWindow.document.body.append(script);" + + " clearInterval(interval);" + + " });" + + "})();"; + } private static final String DOCUMENT_READY_WRAPPER_JS_SOURCE = "if (document.readyState === 'interactive' || document.readyState === 'complete') { " + " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScript.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScript.java index 1f8e5604b..19ecdf5da 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScript.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserScript.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; public class UserScript { @@ -19,10 +20,11 @@ public class UserScript { private ContentWorld contentWorld; @NonNull private Set allowedOriginRules = new HashSet<>(); + private boolean forMainFrameOnly = true; public UserScript(@Nullable String groupName, @NonNull String source, @NonNull UserScriptInjectionTime injectionTime, @Nullable ContentWorld contentWorld, - @Nullable Set allowedOriginRules) { + @Nullable Set allowedOriginRules, boolean forMainFrameOnly) { this.groupName = groupName; this.source = source; this.injectionTime = injectionTime; @@ -30,6 +32,7 @@ public UserScript(@Nullable String groupName, @NonNull String source, this.allowedOriginRules = allowedOriginRules == null ? new HashSet() {{ add("*"); }} : allowedOriginRules; + this.forMainFrameOnly = forMainFrameOnly; } @Nullable @@ -42,8 +45,9 @@ public static UserScript fromMap(@Nullable Map map) { UserScriptInjectionTime injectionTime = UserScriptInjectionTime.fromValue((int) map.get("injectionTime")); ContentWorld contentWorld = ContentWorld.fromMap((Map) map.get("contentWorld")); Set allowedOriginRules = new HashSet<>((List) map.get("allowedOriginRules")); + boolean forMainFrameOnly = (boolean) map.get("forMainFrameOnly"); assert source != null; - return new UserScript(groupName, source, injectionTime, contentWorld, allowedOriginRules); + return new UserScript(groupName, source, injectionTime, contentWorld, allowedOriginRules, forMainFrameOnly); } @Nullable @@ -91,28 +95,31 @@ public void setAllowedOriginRules(@NonNull Set allowedOriginRules) { this.allowedOriginRules = allowedOriginRules; } + public boolean isForMainFrameOnly() { + return forMainFrameOnly; + } + + public void setForMainFrameOnly(boolean forMainFrameOnly) { + this.forMainFrameOnly = forMainFrameOnly; + } + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UserScript that = (UserScript) o; - - if (groupName != null ? !groupName.equals(that.groupName) : that.groupName != null) - return false; - if (!source.equals(that.source)) return false; - if (injectionTime != that.injectionTime) return false; - if (!contentWorld.equals(that.contentWorld)) return false; - return allowedOriginRules.equals(that.allowedOriginRules); + return forMainFrameOnly == that.forMainFrameOnly && Objects.equals(groupName, that.groupName) && source.equals(that.source) && injectionTime == that.injectionTime && contentWorld.equals(that.contentWorld) && allowedOriginRules.equals(that.allowedOriginRules); } @Override public int hashCode() { - int result = groupName != null ? groupName.hashCode() : 0; + int result = Objects.hashCode(groupName); result = 31 * result + source.hashCode(); result = 31 * result + injectionTime.hashCode(); result = 31 * result + contentWorld.hashCode(); result = 31 * result + allowedOriginRules.hashCode(); + result = 31 * result + Boolean.hashCode(forMainFrameOnly); return result; } @@ -124,6 +131,7 @@ public String toString() { ", injectionTime=" + injectionTime + ", contentWorld=" + contentWorld + ", allowedOriginRules=" + allowedOriginRules + + ", forMainFrameOnly=" + forMainFrameOnly + '}'; } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePort.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePort.java index a9b6cdf2e..d8bdc5649 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePort.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/WebMessagePort.java @@ -36,10 +36,10 @@ public void setWebMessageCallback(final ValueCallback callback) throws Exc if (webView != null) { int index = name.equals("port1") ? 0 : 1; webView.evaluateJavascript("(function() {" + - " var webMessageChannel = " + JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME + "['" + webMessageChannel.id + "'];" + + " var webMessageChannel = " + JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + webMessageChannel.id + "'];" + " if (webMessageChannel != null) {" + " webMessageChannel." + this.name + ".onmessage = function (event) {" + - " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + ".callHandler('onWebMessagePortMessageReceived', {" + + " window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + ".callHandler('onWebMessagePortMessageReceived', {" + " 'webMessageChannelId': '" + webMessageChannel.id + "'," + " 'index': " + index + "," + " 'message': event.data" + @@ -82,13 +82,13 @@ public void postMessage(WebMessage message, final ValueCallback callback) throw new Exception("Port is already closed or transferred"); } port.isTransferred = true; - portArrayString.add(JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME + "['" + webMessageChannel.id + "']." + port.name); + portArrayString.add(JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + webMessageChannel.id + "']." + port.name); } portsString = "[" + TextUtils.join(", ", portArrayString) + "]"; } String data = message.data != null ? Util.replaceAll(message.data, "\'", "\\'") : "null"; String source = "(function() {" + - " var webMessageChannel = " + JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME + "['" + webMessageChannel.id + "'];" + + " var webMessageChannel = " + JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + webMessageChannel.id + "'];" + " if (webMessageChannel != null) {" + " webMessageChannel." + this.name + ".postMessage('" + data + "', " + portsString + ");" + " }" + @@ -113,7 +113,7 @@ public void close(final ValueCallback callback) throws Exception { InAppWebViewInterface webView = webMessageChannel != null && webMessageChannel.webView != null ? webMessageChannel.webView : null; if (webView != null) { String source = "(function() {" + - " var webMessageChannel = " + JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME + "['" + webMessageChannel.id + "'];" + + " var webMessageChannel = " + JavaScriptBridgeJS.WEB_MESSAGE_CHANNELS_VARIABLE_NAME() + "['" + webMessageChannel.id + "'];" + " if (webMessageChannel != null) {" + " webMessageChannel." + this.name + ".close();" + " }" + diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewInterface.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewInterface.java index ece312921..1f88e9f26 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewInterface.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewInterface.java @@ -52,7 +52,8 @@ void loadDataWithBaseURL(String baseUrl, String data, boolean isLoading(); void takeScreenshot(Map screenshotConfiguration, MethodChannel.Result result); void setSettings(InAppWebViewSettings newSettings, HashMap newSettingsMap); - Map getCustomSettings(); + InAppWebViewSettings getCustomSettings(); + Map getCustomSettingsMap(); HashMap getCopyBackForwardList(); void clearAllCache(); void clearSslPreferences(); diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java index 7463c5a9a..ed2530cbc 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/InAppWebViewManager.java @@ -16,6 +16,7 @@ import androidx.webkit.WebViewFeature; import com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFlutterPlugin; +import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; import com.pichillilorenzo.flutter_inappwebview_android.types.ChannelDelegateImpl; import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.FlutterWebView; @@ -32,7 +33,7 @@ public class InAppWebViewManager extends ChannelDelegateImpl { protected static final String LOG_TAG = "InAppWebViewManager"; public static final String METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_manager"; - + @Nullable public InAppWebViewFlutterPlugin plugin; @@ -163,13 +164,22 @@ public void onReceiveValue(Boolean value) { result.success(true); break; case "enableSlowWholeDocumentDraw": - { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - WebView.enableSlowWholeDocumentDraw(); + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + WebView.enableSlowWholeDocumentDraw(); + } } - } - result.success(true); - break; + result.success(true); + break; + case "setJavaScriptBridgeName": + JavaScriptBridgeJS.set_JAVASCRIPT_BRIDGE_NAME((String) call.argument("bridgeName")); + result.success(true); + break; + case "getJavaScriptBridgeName": + { + result.success(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME()); + } + break; default: result.notImplemented(); } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/JavaScriptBridgeInterface.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/JavaScriptBridgeInterface.java index 615a1f86e..4e5ff4112 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/JavaScriptBridgeInterface.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/JavaScriptBridgeInterface.java @@ -9,21 +9,27 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; import com.pichillilorenzo.flutter_inappwebview_android.print_job.PrintJobController; import com.pichillilorenzo.flutter_inappwebview_android.print_job.PrintJobSettings; +import com.pichillilorenzo.flutter_inappwebview_android.types.JavaScriptHandlerFunctionData; import com.pichillilorenzo.flutter_inappwebview_android.webview.in_app_webview.InAppWebView; -import com.pichillilorenzo.flutter_inappwebview_android.plugin_scripts_js.JavaScriptBridgeJS; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.util.regex.Pattern; + public class JavaScriptBridgeInterface { private static final String LOG_TAG = "JSBridgeInterface"; private InAppWebView inAppWebView; - - public JavaScriptBridgeInterface(InAppWebView inAppWebView) { + @NonNull + private final String expectedBridgeSecret; + + public JavaScriptBridgeInterface(InAppWebView inAppWebView, @NonNull String expectedBridgeSecret) { this.inAppWebView = inAppWebView; + this.expectedBridgeSecret = expectedBridgeSecret; } @JavascriptInterface @@ -44,11 +50,40 @@ public void run() { } @JavascriptInterface - public void _callHandler(final String handlerName, final String _callHandlerID, final String args) { + public void _callHandler(final String handlerName, final String _callHandlerID, + final String bridgeSecret, final String origin, final boolean isMainFrame, + final String args) { if (inAppWebView == null) { return; } + if (handlerName == null || handlerName.isEmpty()) { + Log.d(LOG_TAG, "handlerName is null or empty"); + return; + } + + if (!expectedBridgeSecret.equals(bridgeSecret)) { + Log.e(LOG_TAG, "Bridge access attempt with wrong secret token, possibly from malicious code!"); + return; + } + + boolean isOriginAllowed = false; + if (inAppWebView.customSettings.javaScriptHandlerOriginAllowList != null) { + for (Pattern allowedOrigin : inAppWebView.customSettings.javaScriptHandlerOriginAllowList) { + if (allowedOrigin.matcher(origin).matches()) { + isOriginAllowed = true; + break; + } + } + } else { + // origin is by default allowed if the allow list is null + isOriginAllowed = true; + } + if (!isOriginAllowed) { + Log.e(LOG_TAG, "Bridge access attempt from an origin not allowed: " + origin); + return; + } + // java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. // https://github.com/pichillilorenzo/flutter_inappwebview/issues/98 final Handler handler = new Handler(inAppWebView.getWebViewLooper()); @@ -120,22 +155,22 @@ public void error(String errorCode, @Nullable String errorMessage, @Nullable Obj } if (inAppWebView.channelDelegate != null) { + JavaScriptHandlerFunctionData data = new JavaScriptHandlerFunctionData(origin, isMainFrame, args); // invoke flutter javascript handler and send back flutter data as a JSON Object to javascript - inAppWebView.channelDelegate.onCallJsHandler(handlerName, args, new WebViewChannelDelegate.CallJsHandlerCallback() { + inAppWebView.channelDelegate.onCallJsHandler(handlerName, data, new WebViewChannelDelegate.CallJsHandlerCallback() { @Override public void defaultBehaviour(@Nullable Object json) { if (inAppWebView == null) { // The webview has already been disposed, ignore. return; } - String sourceCode = "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "] != null) { " + - "window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "].resolve(" + json + "); " + - "delete window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "]; " + - "}"; + String sourceCode = "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "] != null) { " + + "window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "].resolve(" + json + "); " + + "delete window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "]; " + + "}"; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { inAppWebView.evaluateJavascript(sourceCode, (ValueCallback) null); - } - else { + } else { inAppWebView.loadUrl("javascript:" + sourceCode); } } @@ -150,14 +185,13 @@ public void error(String errorCode, @Nullable String errorMessage, @Nullable Obj return; } - String sourceCode = "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "] != null) { " + - "window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "].reject(new Error(" + JSONObject.quote(message) + ")); " + - "delete window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "[" + _callHandlerID + "]; " + + String sourceCode = "if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "] != null) { " + + "window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "].reject(new Error(" + JSONObject.quote(message) + ")); " + + "delete window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "[" + _callHandlerID + "]; " + "}"; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { inAppWebView.evaluateJavascript(sourceCode, (ValueCallback) null); - } - else { + } else { inAppWebView.loadUrl("javascript:" + sourceCode); } } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java index 5f87b93c0..9d2e76eb7 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java @@ -29,6 +29,7 @@ import com.pichillilorenzo.flutter_inappwebview_android.types.HitTestResult; import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthResponse; import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthenticationChallenge; +import com.pichillilorenzo.flutter_inappwebview_android.types.JavaScriptHandlerFunctionData; import com.pichillilorenzo.flutter_inappwebview_android.types.JsAlertResponse; import com.pichillilorenzo.flutter_inappwebview_android.types.JsBeforeUnloadResponse; import com.pichillilorenzo.flutter_inappwebview_android.types.JsConfirmResponse; @@ -231,9 +232,9 @@ public void onReceiveValue(String value) { case getSettings: if (webView != null && webView.getInAppBrowserDelegate() instanceof InAppBrowserActivity) { InAppBrowserActivity inAppBrowserActivity = (InAppBrowserActivity) webView.getInAppBrowserDelegate(); - result.success(inAppBrowserActivity.getCustomSettings()); + result.success(inAppBrowserActivity.getCustomSettingsMap()); } else { - result.success((webView != null) ? webView.getCustomSettings() : null); + result.success((webView != null) ? webView.getCustomSettingsMap() : null); } break; case close: @@ -1271,7 +1272,7 @@ public Object decodeResult(@Nullable Object obj) { } } - public void onCallJsHandler(String handlerName, String args, @NonNull CallJsHandlerCallback callback) { + public void onCallJsHandler(String handlerName, JavaScriptHandlerFunctionData data, @NonNull CallJsHandlerCallback callback) { MethodChannel channel = getChannel(); if (channel == null) { callback.defaultBehaviour(null); @@ -1279,7 +1280,7 @@ public void onCallJsHandler(String handlerName, String args, @NonNull CallJsHand } Map obj = new HashMap<>(); obj.put("handlerName", handlerName); - obj.put("args", args); + obj.put("data", data.toMap()); channel.invokeMethod("onCallJsHandler", obj, callback); } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java index fbabab3d4..2033e0b60 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java @@ -102,6 +102,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -188,6 +189,9 @@ public InAppWebView(Context context, AttributeSet attrs, int defaultStyle) { super(context, attrs, defaultStyle); } + @NonNull + private final String expectedBridgeSecret = UUID.randomUUID().toString(); + public InAppWebView(Context context, @NonNull InAppWebViewFlutterPlugin plugin, @NonNull Object id, @Nullable Integer windowId, InAppWebViewSettings customSettings, @Nullable Map contextMenu, View containerView, @@ -243,8 +247,8 @@ public void prepare() { webViewAssetLoaderExt = WebViewAssetLoaderExt.fromMap(customSettings.webViewAssetLoader, plugin, getContext()); } - javaScriptBridgeInterface = new JavaScriptBridgeInterface(this); - addJavascriptInterface(javaScriptBridgeInterface, JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME); + javaScriptBridgeInterface = new JavaScriptBridgeInterface(this, expectedBridgeSecret); + addJavascriptInterface(javaScriptBridgeInterface, JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME()); inAppWebViewChromeClient = new InAppWebViewChromeClient(plugin, this, inAppBrowserDelegate); setWebChromeClient(inAppWebViewChromeClient); @@ -561,24 +565,34 @@ public boolean onLongClick(View v) { } public void prepareAndAddUserScripts() { - userContentController.addPluginScript(PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT); - userContentController.addPluginScript(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT); - userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT); - userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT); - userContentController.addPluginScript(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT); + userContentController.addPluginScript(PromisePolyfillJS.PROMISE_POLYFILL_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, + customSettings.pluginScriptsForMainFrameOnly)); + userContentController.addPluginScript(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(expectedBridgeSecret, + customSettings.pluginScriptsOriginAllowList, + customSettings.pluginScriptsForMainFrameOnly)); + userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, + customSettings.pluginScriptsForMainFrameOnly)); + userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, + customSettings.pluginScriptsForMainFrameOnly)); + userContentController.addPluginScript(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, + customSettings.pluginScriptsForMainFrameOnly)); interceptOnlyAsyncAjaxRequestsPluginScript = InterceptAjaxRequestJS.createInterceptOnlyAsyncAjaxRequestsPluginScript(customSettings.interceptOnlyAsyncAjaxRequests); if (customSettings.useShouldInterceptAjaxRequest) { userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript); - userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT); + userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, + customSettings.pluginScriptsForMainFrameOnly)); } if (customSettings.useShouldInterceptFetchRequest) { - userContentController.addPluginScript(InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT); + userContentController.addPluginScript(InterceptFetchRequestJS.INTERCEPT_FETCH_REQUEST_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, + customSettings.pluginScriptsForMainFrameOnly)); } if (customSettings.useOnLoadResource) { - userContentController.addPluginScript(OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT); + userContentController.addPluginScript(OnLoadResourceJS.ON_LOAD_RESOURCE_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, + customSettings.pluginScriptsForMainFrameOnly)); } if (!customSettings.useHybridComposition) { - userContentController.addPluginScript(PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT); + userContentController.addPluginScript(PluginScriptsUtil.CHECK_GLOBAL_KEY_DOWN_EVENT_TO_HIDE_CONTEXT_MENU_JS_PLUGIN_SCRIPT(customSettings.pluginScriptsOriginAllowList, + customSettings.pluginScriptsForMainFrameOnly)); } this.userContentController.addUserOnlyScripts(this.initialUserOnlyScripts); } @@ -783,15 +797,16 @@ public void setSettings(InAppWebViewSettings newCustomSettings, HashMap= Build.VERSION_CODES.M) customSettings = newCustomSettings; } - public Map getCustomSettings() { + public Map getCustomSettingsMap() { return (customSettings != null) ? customSettings.getRealSettings(this) : null; } @@ -1170,8 +1187,8 @@ public void injectDeferredObject(String source, @Nullable final ContentWorld con } if (resultUuid != null && resultCallback != null) { evaluateJavaScriptContentWorldCallbacks.put(resultUuid, resultCallback); - scriptToInject = Util.replaceAll(PluginScriptsUtil.EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE, - PluginScriptsUtil.VAR_RANDOM_NAME, "_" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "_" + Math.round(Math.random() * 1000000)) + scriptToInject = Util.replaceAll(PluginScriptsUtil.EVALUATE_JAVASCRIPT_WITH_CONTENT_WORLD_WRAPPER_JS_SOURCE(), + PluginScriptsUtil.VAR_RANDOM_NAME, "_" + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "_" + Math.round(Math.random() * 1000000)) .replace(PluginScriptsUtil.VAR_PLACEHOLDER_VALUE, UserContentController.escapeCode(source)) .replace(PluginScriptsUtil.VAR_RESULT_UUID, resultUuid); } @@ -1216,13 +1233,13 @@ public void injectJavascriptFileFromUrl(String urlFile, @Nullable Map argumen String functionArgumentValues = TextUtils.join(", ", functionArgumentValuesList); String functionArgumentsObj = Util.JSONStringify(arguments); - String sourceToInject = PluginScriptsUtil.CALL_ASYNC_JAVA_SCRIPT_WRAPPER_JS_SOURCE + String sourceToInject = PluginScriptsUtil.CALL_ASYNC_JAVA_SCRIPT_WRAPPER_JS_SOURCE() .replace(PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_NAMES, functionArgumentNames) .replace(PluginScriptsUtil.VAR_FUNCTION_ARGUMENT_VALUES, functionArgumentValues) .replace(PluginScriptsUtil.VAR_FUNCTION_ARGUMENTS_OBJ, functionArgumentsObj) @@ -2036,6 +2053,11 @@ public void setChannelDelegate(@Nullable WebViewChannelDelegate channelDelegate) this.channelDelegate = channelDelegate; } + @Override + public InAppWebViewSettings getCustomSettings() { + return customSettings; + } + @Override public void dispose() { if (channelDelegate != null) { @@ -2045,7 +2067,7 @@ public void dispose() { super.dispose(); WebSettings settings = getSettings(); settings.setJavaScriptEnabled(false); - removeJavascriptInterface(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME); + removeJavascriptInterface(JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE)) { WebViewCompat.setWebViewRenderProcessClient(this, null); } diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java index c964c0327..f410b2eae 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClient.java @@ -189,12 +189,13 @@ public void loadCustomJavaScriptOnPageStarted(WebView view) { public void loadCustomJavaScriptOnPageFinished(WebView view) { InAppWebView webView = (InAppWebView) view; - String source = webView.userContentController.generateWrappedCodeForDocumentEnd(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - webView.evaluateJavascript(source, (ValueCallback) null); - } else { - webView.loadUrl("javascript:" + source.replaceAll("[\r\n]+", "")); + if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { + String source = webView.userContentController.generateWrappedCodeForDocumentEnd(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + webView.evaluateJavascript(source, (ValueCallback) null); + } else { + webView.loadUrl("javascript:" + source.replaceAll("[\r\n]+", "")); + } } } @@ -237,7 +238,7 @@ public void onPageFinished(WebView view, String url) { CookieSyncManager.getInstance().sync(); } - String js = JavaScriptBridgeJS.PLATFORM_READY_JS_SOURCE; + String js = JavaScriptBridgeJS.PLATFORM_READY_JS_SOURCE(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { webView.evaluateJavascript(js, (ValueCallback) null); diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java index f00af4149..36b34195f 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewClientCompat.java @@ -189,12 +189,13 @@ public void loadCustomJavaScriptOnPageStarted(WebView view) { public void loadCustomJavaScriptOnPageFinished(WebView view) { InAppWebView webView = (InAppWebView) view; - String source = webView.userContentController.generateWrappedCodeForDocumentEnd(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - webView.evaluateJavascript(source, (ValueCallback) null); - } else { - webView.loadUrl("javascript:" + source.replaceAll("[\r\n]+", "")); + if (!WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { + String source = webView.userContentController.generateWrappedCodeForDocumentEnd(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + webView.evaluateJavascript(source, (ValueCallback) null); + } else { + webView.loadUrl("javascript:" + source.replaceAll("[\r\n]+", "")); + } } } @@ -237,7 +238,7 @@ public void onPageFinished(WebView view, String url) { CookieSyncManager.getInstance().sync(); } - String js = JavaScriptBridgeJS.PLATFORM_READY_JS_SOURCE; + String js = JavaScriptBridgeJS.PLATFORM_READY_JS_SOURCE(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { webView.evaluateJavascript(js, (ValueCallback) null); diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java index 91c13ea36..ed1fa5123 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; public class InAppWebViewSettings implements ISettings { @@ -133,6 +134,11 @@ public class InAppWebViewSettings implements ISettings { public byte[] defaultVideoPoster; @Nullable public Set requestedWithHeaderOriginAllowList; + @Nullable + public Set javaScriptHandlerOriginAllowList; + @Nullable + public Set pluginScriptsOriginAllowList; + public Boolean pluginScriptsForMainFrameOnly = false; @NonNull @Override @@ -412,6 +418,18 @@ public InAppWebViewSettings parse(@NonNull Map settings) { case "requestedWithHeaderOriginAllowList": requestedWithHeaderOriginAllowList = new HashSet<>((List) value); break; + case "javaScriptHandlerOriginAllowList": + javaScriptHandlerOriginAllowList = new HashSet<>(); + for (String pattern : (List) value) { + javaScriptHandlerOriginAllowList.add(Pattern.compile(pattern)); + } + break; + case "pluginScriptsOriginAllowList": + pluginScriptsOriginAllowList = new HashSet<>((List) value); + break; + case "pluginScriptsForMainFrameOnly": + pluginScriptsForMainFrameOnly = (Boolean) value; + break; } } @@ -511,6 +529,15 @@ public Map toMap() { settings.put("defaultVideoPoster", defaultVideoPoster); settings.put("requestedWithHeaderOriginAllowList", requestedWithHeaderOriginAllowList != null ? new ArrayList<>(requestedWithHeaderOriginAllowList) : null); + settings.put("javaScriptHandlerOriginAllowList", + javaScriptHandlerOriginAllowList != null ? new ArrayList() {{ + for (Pattern pattern : javaScriptHandlerOriginAllowList) { + add(pattern.pattern()); + } + }} : null); + settings.put("pluginScriptsOriginAllowList", + pluginScriptsOriginAllowList != null ? new ArrayList<>(pluginScriptsOriginAllowList) : null); + settings.put("pluginScriptsForMainFrameOnly", pluginScriptsForMainFrameOnly); return settings; } @@ -557,7 +584,8 @@ public Map getRealSettings(@NonNull InAppWebViewInterface inAppW realSettings.put("defaultTextEncodingName", settings.getDefaultTextEncodingName()); if (WebViewFeature.isFeatureSupported(WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS)) { realSettings.put("disabledActionModeMenuItems", WebSettingsCompat.getDisabledActionModeMenuItems(settings)); - } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { realSettings.put("disabledActionModeMenuItems", settings.getDisabledActionModeMenuItems()); } realSettings.put("fantasyFontFamily", settings.getFantasyFontFamily()); diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannel.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannel.java index b7d059c27..54230d09c 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannel.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageChannel.java @@ -56,7 +56,7 @@ public void initJsInstance(InAppWebViewInterface webView, final ValueCallback() { @Override public void onReceiveValue(String value) { diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListener.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListener.java index fe7326f70..42e0ee9f4 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListener.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/web_message/WebMessageListener.java @@ -91,7 +91,7 @@ public void initJsInstance() { " var scheme = !isPageBlank ? window.location.protocol.replace(':', '') : null;" + " var host = !isPageBlank ? window.location.hostname : null;" + " var port = !isPageBlank ? window.location.port : null;" + - " if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME + "._isOriginAllowed(allowedOriginRules, scheme, host, port)) {" + + " if (window." + JavaScriptBridgeJS.JAVASCRIPT_BRIDGE_NAME() + "._isOriginAllowed(allowedOriginRules, scheme, host, port)) {" + " window['" + jsObjectNameEscaped + "'] = new FlutterInAppWebViewWebMessageListener('" + jsObjectNameEscaped + "');" + " }" + "})();"; @@ -101,7 +101,8 @@ public void initJsInstance() { UserScriptInjectionTime.AT_DOCUMENT_START, null, false, - null + webView.getCustomSettings().pluginScriptsOriginAllowList, + webView.getCustomSettings().pluginScriptsForMainFrameOnly )); } } diff --git a/flutter_inappwebview_android/example/pubspec.lock b/flutter_inappwebview_android/example/pubspec.lock index 8603227e7..dfb7281eb 100644 --- a/flutter_inappwebview_android/example/pubspec.lock +++ b/flutter_inappwebview_android/example/pubspec.lock @@ -81,7 +81,7 @@ packages: path: ".." relative: true source: path - version: "1.1.3" + version: "1.2.0" flutter_inappwebview_internal_annotations: dependency: transitive description: @@ -93,11 +93,10 @@ packages: flutter_inappwebview_platform_interface: dependency: transitive description: - name: flutter_inappwebview_platform_interface - sha256: "6862f4e08aa8f6136762e022c9c1edafb18c1dc3beb03052f2f3f2a48605a182" - url: "https://pub.dev" - source: hosted - version: "1.3.0" + path: "../../flutter_inappwebview_platform_interface" + relative: true + source: path + version: "1.4.0" flutter_lints: dependency: "direct dev" description: diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart index 0d269dc2e..5dee24ef6 100644 --- a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart @@ -1,24 +1,19 @@ -import 'dart:io'; import 'dart:collection'; import 'dart:convert'; import 'dart:core'; import 'dart:developer' as developer; -import 'dart:typed_data'; -import 'dart:ui'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import '../web_message/main.dart'; - import '../in_app_browser/in_app_browser.dart'; +import '../print_job/main.dart'; +import '../web_message/main.dart'; import '../web_storage/web_storage.dart'; - -import 'headless_in_app_webview.dart'; import '_static_channel.dart'; - -import '../print_job/main.dart'; +import 'headless_in_app_webview.dart'; ///List of forbidden names for JavaScript handlers. // ignore: non_constant_identifier_names @@ -66,8 +61,7 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController static final MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL; // List of properties to be saved and restored for keep alive feature - Map _javaScriptHandlersMap = - HashMap(); + Map _javaScriptHandlersMap = HashMap(); Map> _userScripts = { UserScriptInjectionTime.AT_DOCUMENT_START: [], UserScriptInjectionTime.AT_DOCUMENT_END: [] @@ -1408,17 +1402,19 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController break; case "onCallJsHandler": String handlerName = call.arguments["handlerName"]; + Map handlerDataMap = call.arguments["data"].cast(); // decode args to json - List args = jsonDecode(call.arguments["args"]); + handlerDataMap["args"] = jsonDecode(handlerDataMap["args"]); + final handlerData = JavaScriptHandlerFunctionData.fromMap(handlerDataMap)!; - _debugLog(handlerName, args); + _debugLog(handlerName, handlerData); switch (handlerName) { case "onLoadResource": if ((webviewParams != null && webviewParams!.onLoadResource != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = handlerData.args[0].cast(); arguments["startTime"] = arguments["startTime"] is int ? arguments["startTime"].toDouble() : arguments["startTime"]; @@ -1440,7 +1436,7 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController if ((webviewParams != null && webviewParams!.shouldInterceptAjaxRequest != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = handlerData.args[0].cast(); AjaxRequest request = AjaxRequest.fromMap(arguments)!; if (webviewParams != null && @@ -1457,7 +1453,7 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController if ((webviewParams != null && webviewParams!.onAjaxReadyStateChange != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = handlerData.args[0].cast(); AjaxRequest request = AjaxRequest.fromMap(arguments)!; if (webviewParams != null && @@ -1475,7 +1471,7 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController if ((webviewParams != null && webviewParams!.onAjaxProgress != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = handlerData.args[0].cast(); AjaxRequest request = AjaxRequest.fromMap(arguments)!; if (webviewParams != null && @@ -1493,7 +1489,7 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController if ((webviewParams != null && webviewParams!.shouldInterceptFetchRequest != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = handlerData.args[0].cast(); FetchRequest request = FetchRequest.fromMap(arguments)!; if (webviewParams != null && @@ -1519,7 +1515,7 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController _inAppBrowserEventHandler!.onWindowBlur(); return null; case "onInjectedScriptLoaded": - String id = args[0]; + String id = handlerData.args[0]; var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; if ((webviewParams != null || _inAppBrowserEventHandler != null) && onLoadCallback != null) { @@ -1527,7 +1523,7 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController } return null; case "onInjectedScriptError": - String id = args[0]; + String id = handlerData.args[0]; var onErrorCallback = _injectedScriptsFromURL[id]?.onError; if ((webviewParams != null || _inAppBrowserEventHandler != null) && onErrorCallback != null) { @@ -1539,7 +1535,19 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController if (_javaScriptHandlersMap.containsKey(handlerName)) { // convert result to json try { - return jsonEncode(await _javaScriptHandlersMap[handlerName]!(args)); + var jsHandlerResult = null; + if (_javaScriptHandlersMap[handlerName] + is JavaScriptHandlerCallback) { + jsHandlerResult = await (_javaScriptHandlersMap[handlerName] + as JavaScriptHandlerCallback)(handlerData.args); + } else if (_javaScriptHandlersMap[handlerName] + is JavaScriptHandlerFunction) { + jsHandlerResult = await (_javaScriptHandlersMap[handlerName] + as JavaScriptHandlerFunction)(handlerData); + } else { + jsHandlerResult = await _javaScriptHandlersMap[handlerName]!(); + } + return jsonEncode(jsHandlerResult); } catch (error, stacktrace) { developer.log(error.toString() + '\n' + stacktrace.toString(), name: 'JavaScript Handler "$handlerName"'); @@ -1986,16 +1994,14 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController @override void addJavaScriptHandler( - {required String handlerName, - required JavaScriptHandlerCallback callback}) { + {required String handlerName, required Function callback}) { assert(!_JAVASCRIPT_HANDLER_FORBIDDEN_NAMES.contains(handlerName), '"$handlerName" is a forbidden name!'); this._javaScriptHandlersMap[handlerName] = (callback); } @override - JavaScriptHandlerCallback? removeJavaScriptHandler( - {required String handlerName}) { + Function? removeJavaScriptHandler({required String handlerName}) { return this._javaScriptHandlersMap.remove(handlerName); } @@ -2744,6 +2750,21 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController await _staticChannel.invokeMethod('enableSlowWholeDocumentDraw', args); } + @override + Future setJavaScriptBridgeName(String bridgeName) async { + Map args = {}; + args.putIfAbsent('bridgeName', () => bridgeName); + await _staticChannel.invokeMethod('setJavaScriptBridgeName', args); + } + + @override + Future getJavaScriptBridgeName() async { + Map args = {}; + return await _staticChannel.invokeMethod( + 'getJavaScriptBridgeName', args) ?? + ''; + } + @override Future get tRexRunnerHtml async => await rootBundle.loadString( 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html'); diff --git a/flutter_inappwebview_android/pubspec.yaml b/flutter_inappwebview_android/pubspec.yaml index f9fd161a3..83dba2a37 100644 --- a/flutter_inappwebview_android/pubspec.yaml +++ b/flutter_inappwebview_android/pubspec.yaml @@ -20,7 +20,8 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_platform_interface: ^1.4.0 + flutter_inappwebview_platform_interface: # ^1.4.0 + path: ../flutter_inappwebview_platform_interface dev_dependencies: flutter_test: diff --git a/flutter_inappwebview_platform_interface/CHANGELOG.md b/flutter_inappwebview_platform_interface/CHANGELOG.md index 18e127b0c..efc16294c 100644 --- a/flutter_inappwebview_platform_interface/CHANGELOG.md +++ b/flutter_inappwebview_platform_interface/CHANGELOG.md @@ -2,6 +2,9 @@ - Updated static `fromMap` implementation for some classes - Added `PlatformInAppLocalhostServer.onData` parameter to set a custom on data server callback +- Added `javaScriptHandlerOriginAllowList`, `pluginScriptsOriginAllowList`, `pluginScriptsForMainFrameOnly` InAppWebViewSettings parameters +- Added `JavaScriptHandlerFunctionData` type +- Deprecated `JavaScriptHandlerCallback` type in favor of `JavaScriptHandlerFunction` type ## 1.3.0+1 diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_keep_alive.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_keep_alive.dart index 0cf7800e8..cd7cff328 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_keep_alive.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_keep_alive.dart @@ -22,7 +22,7 @@ extension InternalInAppWebViewKeepAlive on InAppWebViewKeepAlive { ///Used internally to save and restore [PlatformInAppWebViewController] properties ///for the keep alive feature. class InAppWebViewControllerKeepAliveProps { - Map javaScriptHandlersMap; + Map javaScriptHandlersMap; Map> userScripts; Set webMessageListenerObjNames; Map injectedScriptsFromURL; diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart index 34f9e9e0b..a7555b4e3 100755 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart @@ -21,6 +21,7 @@ import '../types/scrollview_deceleration_rate.dart'; import '../types/selection_granularity.dart'; import '../types/user_preferred_content_mode.dart'; import '../types/vertical_scrollbar_position.dart'; +import '../types/user_script.dart'; import '../web_uri.dart'; import 'android/in_app_webview_options.dart'; import 'apple/in_app_webview_options.dart'; @@ -1594,6 +1595,39 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri ]) bool? shouldPrintBackgrounds; + ///A list of patterns that will be used to match the allowed origins + ///that are able to execute the JavaScript Handlers defined for the current WebView. + ///This will affect also the internal JavaScript Handlers used by the plugin itself. + ///The default value is `null` and will allow every origin. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + Set? javaScriptHandlerOriginAllowList; + + ///A list of patterns that will be used to match the allowed origins + ///that are able to load all the internal plugin [UserScript]s used by the plugin itself. + ///The default value is `null` and will allow every origin. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + Set? pluginScriptsOriginAllowList; + + ///Set to `true` to allow internal plugin [UserScript]s only on the main frame. + ///The default value is `false`. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + bool? pluginScriptsForMainFrameOnly; + ///Specifies a feature policy for the `. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + String? name; + + ///The unique identifier of the frame associated with the current [FrameInfo]. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + int? frameId; + + ///The kind of the frame. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + FrameKind_? kind; + FrameInfo_( - {required this.isMainFrame, required this.request, this.securityOrigin}); + {required this.isMainFrame, required this.request, this.securityOrigin, + this.name, this.frameId, this.kind}); } ///An object that contains information about a frame on a webpage. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/frame_info.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/frame_info.g.dart index 71f0402a5..f568ad466 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/frame_info.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/frame_info.g.dart @@ -8,15 +8,54 @@ part of 'frame_info.dart'; ///An object that contains information about a frame on a webpage. class FrameInfo { + ///The unique identifier of the frame associated with the current [FrameInfo]. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + int? frameId; + ///A Boolean value indicating whether the frame is the web site's main frame or a subframe. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS + ///- MacOS + ///- Windows bool isMainFrame; + ///The kind of the frame. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + FrameKind? kind; + + ///Gets the name attribute of the frame, as in . + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + String? name; + ///The frame’s current request. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS + ///- MacOS + ///- Windows URLRequest? request; ///The frame’s security origin. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS + ///- MacOS + ///- Windows SecurityOrigin? securityOrigin; - FrameInfo({required this.isMainFrame, this.request, this.securityOrigin}); + FrameInfo( + {this.frameId, + required this.isMainFrame, + this.kind, + this.name, + this.request, + this.securityOrigin}); ///Gets a possible [FrameInfo] instance from a [Map] value. static FrameInfo? fromMap(Map? map) { @@ -24,7 +63,10 @@ class FrameInfo { return null; } final instance = FrameInfo( + frameId: map['frameId'], isMainFrame: map['isMainFrame'], + kind: FrameKind.fromNativeValue(map['kind']), + name: map['name'], request: URLRequest.fromMap(map['request']?.cast()), securityOrigin: SecurityOrigin.fromMap( map['securityOrigin']?.cast()), @@ -35,7 +77,10 @@ class FrameInfo { ///Converts instance to a map. Map toMap() { return { + "frameId": frameId, "isMainFrame": isMainFrame, + "kind": kind?.toNativeValue(), + "name": name, "request": request?.toMap(), "securityOrigin": securityOrigin?.toMap(), }; @@ -48,7 +93,7 @@ class FrameInfo { @override String toString() { - return 'FrameInfo{isMainFrame: $isMainFrame, request: $request, securityOrigin: $securityOrigin}'; + return 'FrameInfo{frameId: $frameId, isMainFrame: $isMainFrame, kind: $kind, name: $name, request: $request, securityOrigin: $securityOrigin}'; } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart new file mode 100644 index 000000000..8b3a19cda --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart @@ -0,0 +1,64 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'frame_kind.g.dart'; + +///Class used to indicate the the frame kind. +@ExchangeableEnum() +class FrameKind_ { + // ignore: unused_field + final String _value; + // ignore: unused_field + final dynamic _nativeValue = null; + const FrameKind_._internal(this._value); + + ///Indicates that the frame is an unknown type frame. We may extend this enum type to identify more frame kinds in the future. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_UNKNOWN', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 0 + ), + ]) + static const UNKNOWN = const FrameKind_._internal('UNKNOWN'); + + ///Indicates that the frame is a primary main frame(webview). + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_MAIN_FRAME', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 1 + ), + ]) + static const MAIN_FRAME = const FrameKind_._internal('MAIN_FRAME'); + + ///Indicates that the frame is an iframe. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_IFRAME', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 2 + ), + ]) + static const IFRAME = const FrameKind_._internal('IFRAME'); + + ///Indicates that the frame is an embed element. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_EMBED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 3 + ), + ]) + static const EMBED = const FrameKind_._internal('EMBED'); + + ///Indicates that the frame is an object element. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_OBJECT', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 4 + ), + ]) + static const OBJECT = const FrameKind_._internal('OBJECT'); +} \ No newline at end of file diff --git a/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.g.dart new file mode 100644 index 000000000..727b15aab --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.g.dart @@ -0,0 +1,140 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'frame_kind.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Class used to indicate the the frame kind. +class FrameKind { + final String _value; + final dynamic _nativeValue; + const FrameKind._internal(this._value, this._nativeValue); +// ignore: unused_element + factory FrameKind._internalMultiPlatform( + String value, Function nativeValue) => + FrameKind._internal(value, nativeValue()); + + ///Indicates that the frame is an embed element. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_FRAME_KIND_EMBED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final EMBED = FrameKind._internalMultiPlatform('EMBED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 3; + default: + break; + } + return null; + }); + + ///Indicates that the frame is an iframe. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_FRAME_KIND_IFRAME](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final IFRAME = FrameKind._internalMultiPlatform('IFRAME', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 2; + default: + break; + } + return null; + }); + + ///Indicates that the frame is a primary main frame(webview). + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_FRAME_KIND_MAIN_FRAME](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final MAIN_FRAME = FrameKind._internalMultiPlatform('MAIN_FRAME', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 1; + default: + break; + } + return null; + }); + + ///Indicates that the frame is an object element. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_FRAME_KIND_OBJECT](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final OBJECT = FrameKind._internalMultiPlatform('OBJECT', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 4; + default: + break; + } + return null; + }); + + ///Indicates that the frame is an unknown type frame. We may extend this enum type to identify more frame kinds in the future. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_FRAME_KIND_UNKNOWN](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final UNKNOWN = FrameKind._internalMultiPlatform('UNKNOWN', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 0; + default: + break; + } + return null; + }); + + ///Set of all values of [FrameKind]. + static final Set values = [ + FrameKind.EMBED, + FrameKind.IFRAME, + FrameKind.MAIN_FRAME, + FrameKind.OBJECT, + FrameKind.UNKNOWN, + ].toSet(); + + ///Gets a possible [FrameKind] instance from [String] value. + static FrameKind? fromValue(String? value) { + if (value != null) { + try { + return FrameKind.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [FrameKind] instance from a native value. + static FrameKind? fromNativeValue(dynamic value) { + if (value != null) { + try { + return FrameKind.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets [String] value. + String toValue() => _value; + + ///Gets [dynamic] native value. + dynamic toNativeValue() => _nativeValue; + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + @override + String toString() { + return _value; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/main.dart b/flutter_inappwebview_platform_interface/lib/src/types/main.dart index ba2c2efb2..738df7950 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/main.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/main.dart @@ -231,3 +231,7 @@ export 'custom_tabs_post_message_result_type.dart' show CustomTabsPostMessageResultType; export 'custom_scheme_registration.dart' show CustomSchemeRegistration; export 'disposable.dart'; +export 'frame_kind.dart' show FrameKind; +export 'process_failed_kind.dart' show ProcessFailedKind; +export 'process_failed_reason.dart' show ProcessFailedReason; +export 'process_failed_detail.dart' show ProcessFailedDetail; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart new file mode 100644 index 000000000..7f865fd28 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart @@ -0,0 +1,76 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import 'frame_info.dart'; +import 'process_failed_kind.dart'; +import 'process_failed_reason.dart'; + +part 'process_failed_detail.g.dart'; + +///An object that contains information about a frame on a webpage. +@ExchangeableObject() +class ProcessFailedDetail_ { + ///The kind of process failure that has occurred. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + ProcessFailedKind_ kind; + + ///The exit code of the failing process, for telemetry purposes. + /// + ///The exit code is always STILL_ACTIVE (259) when [ProcessFailedKind.RENDER_PROCESS_UNRESPONSIVE]. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + int? exitCode; + + ///Description of the process assigned by the WebView2 Runtime. + /// + ///This is a technical English term appropriate for logging or development purposes, and not localized for the end user. + ///It applies to utility processes (for example, "Audio Service", "Video Capture") and plugin processes (for example, "Flash"). + ///The returned [processDescription] is empty if the WebView2 Runtime did not assign a description to the process. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + String? processDescription; + + ///The reason for the process failure. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + ProcessFailedReason_? reason; + + ///This property is the full path of the module that caused the crash in cases of Windows Code Integrity failures. + /// + ///Windows Code Integrity is a feature that verifies the integrity and authenticity of dynamic-link libraries (DLLs) on Windows systems. + ///It ensures that only trusted code can run on the system and prevents unauthorized or malicious modifications. + ///When ProcessFailed occurred due to a failed Code Integrity check, this property returns the full path of the file that was prevented from loading on the system. + ///The webview2 process which tried to load the DLL will fail with exit code STATUS_INVALID_IMAGE_HASH(-1073740760). + ///A file can fail integrity check for various reasons, such as: + ///- It has an invalid or missing signature that does not match the publisher or signer of the file. + ///- It has been tampered with or corrupted by malware or other software. + ///- It has been blocked by an administrator or a security policy. This property always will be the empty string if failure is not caused by STATUS_INVALID_IMAGE_HASH. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + String? failureSourceModulePath; + + ///The collection of [FrameInfo]s for frames in the WebView that were being rendered by the failed process. + /// + ///The content in these frames is replaced with an error page. + ///This is only available when [ProcessFailedKind] is [ProcessFailedKind.FRAME_RENDER_PROCESS_EXITED]; + ///frames is null for all other process failure kinds, including the case in which the failed process was the renderer + ///for the main frame and subframes within it, for which the failure kind is [ProcessFailedKind.RENDER_PROCESS_EXITED]. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + List? frameInfos; + + ProcessFailedDetail_( + {required this.kind, + this.exitCode, + this.processDescription, + this.reason, + this.failureSourceModulePath, + this.frameInfos, + }); +} \ No newline at end of file diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.g.dart new file mode 100644 index 000000000..9c5841db0 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.g.dart @@ -0,0 +1,114 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'process_failed_detail.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///An object that contains information about a frame on a webpage. +class ProcessFailedDetail { + ///The exit code of the failing process, for telemetry purposes. + /// + ///The exit code is always STILL_ACTIVE (259) when [ProcessFailedKind.RENDER_PROCESS_UNRESPONSIVE]. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + int? exitCode; + + ///This property is the full path of the module that caused the crash in cases of Windows Code Integrity failures. + /// + ///Windows Code Integrity is a feature that verifies the integrity and authenticity of dynamic-link libraries (DLLs) on Windows systems. + ///It ensures that only trusted code can run on the system and prevents unauthorized or malicious modifications. + ///When ProcessFailed occurred due to a failed Code Integrity check, this property returns the full path of the file that was prevented from loading on the system. + ///The webview2 process which tried to load the DLL will fail with exit code STATUS_INVALID_IMAGE_HASH(-1073740760). + ///A file can fail integrity check for various reasons, such as: + ///- It has an invalid or missing signature that does not match the publisher or signer of the file. + ///- It has been tampered with or corrupted by malware or other software. + ///- It has been blocked by an administrator or a security policy. This property always will be the empty string if failure is not caused by STATUS_INVALID_IMAGE_HASH. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + String? failureSourceModulePath; + + ///The collection of [FrameInfo]s for frames in the WebView that were being rendered by the failed process. + /// + ///The content in these frames is replaced with an error page. + ///This is only available when [ProcessFailedKind] is [ProcessFailedKind.FRAME_RENDER_PROCESS_EXITED]; + ///frames is null for all other process failure kinds, including the case in which the failed process was the renderer + ///for the main frame and subframes within it, for which the failure kind is [ProcessFailedKind.RENDER_PROCESS_EXITED]. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + List? frameInfos; + + ///The kind of process failure that has occurred. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + ProcessFailedKind kind; + + ///Description of the process assigned by the WebView2 Runtime. + /// + ///This is a technical English term appropriate for logging or development purposes, and not localized for the end user. + ///It applies to utility processes (for example, "Audio Service", "Video Capture") and plugin processes (for example, "Flash"). + ///The returned [processDescription] is empty if the WebView2 Runtime did not assign a description to the process. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + String? processDescription; + + ///The reason for the process failure. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows + ProcessFailedReason? reason; + ProcessFailedDetail( + {this.exitCode, + this.failureSourceModulePath, + this.frameInfos, + required this.kind, + this.processDescription, + this.reason}); + + ///Gets a possible [ProcessFailedDetail] instance from a [Map] value. + static ProcessFailedDetail? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = ProcessFailedDetail( + exitCode: map['exitCode'], + failureSourceModulePath: map['failureSourceModulePath'], + frameInfos: map['frameInfos'] != null + ? List.from(map['frameInfos'] + .map((e) => FrameInfo.fromMap(e?.cast())!)) + : null, + kind: ProcessFailedKind.fromNativeValue(map['kind'])!, + processDescription: map['processDescription'], + reason: ProcessFailedReason.fromNativeValue(map['reason']), + ); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "exitCode": exitCode, + "failureSourceModulePath": failureSourceModulePath, + "frameInfos": frameInfos?.map((e) => e.toMap()).toList(), + "kind": kind.toNativeValue(), + "processDescription": processDescription, + "reason": reason?.toNativeValue(), + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ProcessFailedDetail{exitCode: $exitCode, failureSourceModulePath: $failureSourceModulePath, frameInfos: $frameInfos, kind: $kind, processDescription: $processDescription, reason: $reason}'; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart new file mode 100644 index 000000000..2e3d1db73 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart @@ -0,0 +1,141 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'process_failed_kind.g.dart'; + +///Class used to indicate the kind of process failure that has occurred. +@ExchangeableEnum() +class ProcessFailedKind_ { + // ignore: unused_field + final String _value; + // ignore: unused_field + final dynamic _nativeValue = null; + const ProcessFailedKind_._internal(this._value); + + ///Indicates that the browser process ended unexpectedly. The WebView automatically moves to the Closed state. + ///The app has to recreate a new WebView to recover from this failure. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 0 + ), + ]) + static const BROWSER_PROCESS_EXITED = const ProcessFailedKind_._internal('BROWSER_PROCESS_EXITED'); + + ///Indicates that the main frame's render process ended unexpectedly. Any subframes in the WebView will be gone too. + ///A new render process is created automatically and navigated to an error page. + ///You can use the reload method to try to recover from this failure. Alternatively, you can close and recreate the WebView. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 1 + ), + ]) + static const RENDER_PROCESS_EXITED = const ProcessFailedKind_._internal('RENDER_PROCESS_EXITED'); + + ///Indicates that the main frame's render process is unresponsive. + ///Renderer process unresponsiveness can happen for the following reasons: + /// + ///* There is a **long-running script** being executed. For example, the + ///web content in your WebView might be performing a synchronous XHR, or have + ///entered an infinite loop. + ///* The **system is busy**. + /// + ///The process failed event will continue to be raised every few seconds + ///until the renderer process has become responsive again. The application + ///can consider taking action if the event keeps being raised. For example, + ///the application might show UI for the user to decide to keep waiting or + ///reload the page, or navigate away. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 2 + ), + ]) + static const RENDER_PROCESS_UNRESPONSIVE = const ProcessFailedKind_._internal('RENDER_PROCESS_UNRESPONSIVE'); + + ///Indicates that a frame-only render process ended unexpectedly. + ///The process exit does not affect the top-level document, only a subset of the subframes within it. + ///The content in these frames is replaced with an error page in the frame. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 3 + ), + ]) + static const FRAME_RENDER_PROCESS_EXITED = const ProcessFailedKind_._internal('FRAME_RENDER_PROCESS_EXITED'); + + ///Indicates that a utility process ended unexpectedly. + ///The failed process is recreated automatically. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 4 + ), + ]) + static const UTILITY_PROCESS_EXITED = const ProcessFailedKind_._internal('UTILITY_PROCESS_EXITED'); + + ///Indicates that a sandbox helper process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 5 + ), + ]) + static const SANDBOX_HELPER_PROCESS_EXITED = const ProcessFailedKind_._internal('SANDBOX_HELPER_PROCESS_EXITED'); + + ///Indicates that the GPU process ended unexpectedly. + ///The failed process is recreated automatically. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 6 + ), + ]) + static const GPU_PROCESS_EXITED = const ProcessFailedKind_._internal('GPU_PROCESS_EXITED'); + + ///Indicates that a PPAPI plugin process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 7 + ), + ]) + static const PPAPI_PLUGIN_PROCESS_EXITED = const ProcessFailedKind_._internal('PPAPI_PLUGIN_PROCESS_EXITED'); + + ///Indicates that a PPAPI plugin broker process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 8 + ), + ]) + static const PPAPI_BROKER_PROCESS_EXITED = const ProcessFailedKind_._internal('PPAPI_BROKER_PROCESS_EXITED'); + + ///Indicates that a process of unspecified kind ended unexpectedly. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 9 + ), + ]) + static const UNKNOWN_PROCESS_EXITED = const ProcessFailedKind_._internal('UNKNOWN_PROCESS_EXITED'); +} \ No newline at end of file diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.g.dart new file mode 100644 index 000000000..4c1203d06 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.g.dart @@ -0,0 +1,257 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'process_failed_kind.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Class used to indicate the kind of process failure that has occurred. +class ProcessFailedKind { + final String _value; + final dynamic _nativeValue; + const ProcessFailedKind._internal(this._value, this._nativeValue); +// ignore: unused_element + factory ProcessFailedKind._internalMultiPlatform( + String value, Function nativeValue) => + ProcessFailedKind._internal(value, nativeValue()); + + ///Indicates that the browser process ended unexpectedly. The WebView automatically moves to the Closed state. + ///The app has to recreate a new WebView to recover from this failure. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final BROWSER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('BROWSER_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 0; + default: + break; + } + return null; + }); + + ///Indicates that a frame-only render process ended unexpectedly. + ///The process exit does not affect the top-level document, only a subset of the subframes within it. + ///The content in these frames is replaced with an error page in the frame. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final FRAME_RENDER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('FRAME_RENDER_PROCESS_EXITED', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 3; + default: + break; + } + return null; + }); + + ///Indicates that the GPU process ended unexpectedly. + ///The failed process is recreated automatically. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final GPU_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('GPU_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 6; + default: + break; + } + return null; + }); + + ///Indicates that a PPAPI plugin broker process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final PPAPI_BROKER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('PPAPI_BROKER_PROCESS_EXITED', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 8; + default: + break; + } + return null; + }); + + ///Indicates that a PPAPI plugin process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final PPAPI_PLUGIN_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('PPAPI_PLUGIN_PROCESS_EXITED', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 7; + default: + break; + } + return null; + }); + + ///Indicates that the main frame's render process ended unexpectedly. Any subframes in the WebView will be gone too. + ///A new render process is created automatically and navigated to an error page. + ///You can use the reload method to try to recover from this failure. Alternatively, you can close and recreate the WebView. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final RENDER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('RENDER_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 1; + default: + break; + } + return null; + }); + + ///Indicates that the main frame's render process is unresponsive. + ///Renderer process unresponsiveness can happen for the following reasons: + /// + ///* There is a **long-running script** being executed. For example, the + ///web content in your WebView might be performing a synchronous XHR, or have + ///entered an infinite loop. + ///* The **system is busy**. + /// + ///The process failed event will continue to be raised every few seconds + ///until the renderer process has become responsive again. The application + ///can consider taking action if the event keeps being raised. For example, + ///the application might show UI for the user to decide to keep waiting or + ///reload the page, or navigate away. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final RENDER_PROCESS_UNRESPONSIVE = + ProcessFailedKind._internalMultiPlatform('RENDER_PROCESS_UNRESPONSIVE', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 2; + default: + break; + } + return null; + }); + + ///Indicates that a sandbox helper process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final SANDBOX_HELPER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('SANDBOX_HELPER_PROCESS_EXITED', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 5; + default: + break; + } + return null; + }); + + ///Indicates that a process of unspecified kind ended unexpectedly. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final UNKNOWN_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('UNKNOWN_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 9; + default: + break; + } + return null; + }); + + ///Indicates that a utility process ended unexpectedly. + ///The failed process is recreated automatically. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final UTILITY_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('UTILITY_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 4; + default: + break; + } + return null; + }); + + ///Set of all values of [ProcessFailedKind]. + static final Set values = [ + ProcessFailedKind.BROWSER_PROCESS_EXITED, + ProcessFailedKind.FRAME_RENDER_PROCESS_EXITED, + ProcessFailedKind.GPU_PROCESS_EXITED, + ProcessFailedKind.PPAPI_BROKER_PROCESS_EXITED, + ProcessFailedKind.PPAPI_PLUGIN_PROCESS_EXITED, + ProcessFailedKind.RENDER_PROCESS_EXITED, + ProcessFailedKind.RENDER_PROCESS_UNRESPONSIVE, + ProcessFailedKind.SANDBOX_HELPER_PROCESS_EXITED, + ProcessFailedKind.UNKNOWN_PROCESS_EXITED, + ProcessFailedKind.UTILITY_PROCESS_EXITED, + ].toSet(); + + ///Gets a possible [ProcessFailedKind] instance from [String] value. + static ProcessFailedKind? fromValue(String? value) { + if (value != null) { + try { + return ProcessFailedKind.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [ProcessFailedKind] instance from a native value. + static ProcessFailedKind? fromNativeValue(dynamic value) { + if (value != null) { + try { + return ProcessFailedKind.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets [String] value. + String toValue() => _value; + + ///Gets [dynamic] native value. + dynamic toNativeValue() => _nativeValue; + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + @override + String toString() { + return _value; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart new file mode 100644 index 000000000..b21afbc4b --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart @@ -0,0 +1,74 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'process_failed_reason.g.dart'; + +///Class used to indicate the kind of process failure that has occurred. +@ExchangeableEnum() +class ProcessFailedReason_ { + // ignore: unused_field + final String _value; + // ignore: unused_field + final dynamic _nativeValue = null; + const ProcessFailedReason_._internal(this._value); + + ///An unexpected process failure occurred. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 0 + ), + ]) + static const UNEXPECTED = const ProcessFailedReason_._internal('UNEXPECTED'); + + ///The process became unresponsive. This only applies to the main frame's render process. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_UNRESPONSIVE', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 1 + ), + ]) + static const UNRESPONSIVE = const ProcessFailedReason_._internal('UNRESPONSIVE'); + + ///The process was terminated. For example, from Task Manager. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_TERMINATED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 2 + ), + ]) + static const TERMINATED = const ProcessFailedReason_._internal('TERMINATED'); + + ///The process crashed. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 3 + ), + ]) + static const CRASHED = const ProcessFailedReason_._internal('CRASHED'); + + ///The process failed to launch. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 4 + ), + ]) + static const LAUNCH_FAILED = const ProcessFailedReason_._internal('LAUNCH_FAILED'); + + ///The process terminated due to running out of memory. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_OUT_OF_MEMORY', + apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 5 + ), + ]) + static const OUT_OF_MEMORY = const ProcessFailedReason_._internal('OUT_OF_MEMORY'); +} \ No newline at end of file diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.g.dart new file mode 100644 index 000000000..58e9425ef --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.g.dart @@ -0,0 +1,161 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'process_failed_reason.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Class used to indicate the kind of process failure that has occurred. +class ProcessFailedReason { + final String _value; + final dynamic _nativeValue; + const ProcessFailedReason._internal(this._value, this._nativeValue); +// ignore: unused_element + factory ProcessFailedReason._internalMultiPlatform( + String value, Function nativeValue) => + ProcessFailedReason._internal(value, nativeValue()); + + ///The process crashed. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final CRASHED = + ProcessFailedReason._internalMultiPlatform('CRASHED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 3; + default: + break; + } + return null; + }); + + ///The process failed to launch. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final LAUNCH_FAILED = + ProcessFailedReason._internalMultiPlatform('LAUNCH_FAILED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 4; + default: + break; + } + return null; + }); + + ///The process terminated due to running out of memory. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_OUT_OF_MEMORY](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final OUT_OF_MEMORY = + ProcessFailedReason._internalMultiPlatform('OUT_OF_MEMORY', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 5; + default: + break; + } + return null; + }); + + ///The process was terminated. For example, from Task Manager. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_TERMINATED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final TERMINATED = + ProcessFailedReason._internalMultiPlatform('TERMINATED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 2; + default: + break; + } + return null; + }); + + ///An unexpected process failure occurred. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final UNEXPECTED = + ProcessFailedReason._internalMultiPlatform('UNEXPECTED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 0; + default: + break; + } + return null; + }); + + ///The process became unresponsive. This only applies to the main frame's render process. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_UNRESPONSIVE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final UNRESPONSIVE = + ProcessFailedReason._internalMultiPlatform('UNRESPONSIVE', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 1; + default: + break; + } + return null; + }); + + ///Set of all values of [ProcessFailedReason]. + static final Set values = [ + ProcessFailedReason.CRASHED, + ProcessFailedReason.LAUNCH_FAILED, + ProcessFailedReason.OUT_OF_MEMORY, + ProcessFailedReason.TERMINATED, + ProcessFailedReason.UNEXPECTED, + ProcessFailedReason.UNRESPONSIVE, + ].toSet(); + + ///Gets a possible [ProcessFailedReason] instance from [String] value. + static ProcessFailedReason? fromValue(String? value) { + if (value != null) { + try { + return ProcessFailedReason.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [ProcessFailedReason] instance from a native value. + static ProcessFailedReason? fromNativeValue(dynamic value) { + if (value != null) { + try { + return ProcessFailedReason.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets [String] value. + String toValue() => _value; + + ///Gets [dynamic] native value. + dynamic toNativeValue() => _nativeValue; + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + @override + String toString() { + return _value; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.dart b/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.dart index 1fca268bf..f88d02916 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.dart @@ -11,5 +11,8 @@ class WebViewRenderProcessAction_ { const WebViewRenderProcessAction_._internal(this._value); ///Cause this renderer to terminate. + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform(), + ]) static const TERMINATE = const WebViewRenderProcessAction_._internal(0); } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.g.dart index 15542077b..ce81d5818 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.g.dart @@ -18,6 +18,9 @@ class WebViewRenderProcessAction { WebViewRenderProcessAction._internal(value, nativeValue()); ///Cause this renderer to terminate. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android native WebView static const TERMINATE = WebViewRenderProcessAction._internal(0, 0); ///Set of all values of [WebViewRenderProcessAction]. diff --git a/flutter_inappwebview_windows/CHANGELOG.md b/flutter_inappwebview_windows/CHANGELOG.md index 76a0528e5..67fe54c6f 100644 --- a/flutter_inappwebview_windows/CHANGELOG.md +++ b/flutter_inappwebview_windows/CHANGELOG.md @@ -3,7 +3,7 @@ - Updated flutter_inappwebview_platform_interface version to ^1.4.0 - Updated `scrollMultiplier` default value from 6 to 1 - Added support for `UserScript.allowedOriginRules` and `UserScript.forMainFrameOnly` parameters -- Implemented `onReceivedHttpAuthRequest`, `onReceivedClientCertRequest`, `onReceivedServerTrustAuthRequest` WebView events +- Implemented `onReceivedHttpAuthRequest`, `onReceivedClientCertRequest`, `onReceivedServerTrustAuthRequest`, `onRenderProcessGone`, `onRenderProcessUnresponsive`, `onWebContentProcessDidTerminate`, `onProcessFailed` WebView events - Implemented `clearSslPreferences` WebView method - Fixed `get_optional_fl_map_value` implementation in `utils/flutter.h` - Fixed "Error in transparentBackground handling in Windows" [#2391](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2391) diff --git a/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart index e342c4670..084d6e3b7 100644 --- a/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart @@ -1427,6 +1427,21 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController this._devToolsProtocolEventListenerMap[eventName]!.call(data); } break; + case "onProcessFailed": + if ((webviewParams != null && + webviewParams!.onProcessFailed != null) || + _inAppBrowserEventHandler != null) { + Map arguments = call.arguments.cast(); + final detail = ProcessFailedDetail.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onProcessFailed != null) + webviewParams!.onProcessFailed!(_controllerFromPlatform, detail); + else + _inAppBrowserEventHandler! + .onProcessFailed(detail); + } + break; case "onCallJsHandler": String handlerName = call.arguments["handlerName"]; Map handlerDataMap = diff --git a/flutter_inappwebview_windows/windows/CMakeLists.txt b/flutter_inappwebview_windows/windows/CMakeLists.txt index 5e7034401..30a321527 100644 --- a/flutter_inappwebview_windows/windows/CMakeLists.txt +++ b/flutter_inappwebview_windows/windows/CMakeLists.txt @@ -119,6 +119,14 @@ list(APPEND PLUGIN_SOURCES "types/server_trust_challenge.h" "types/server_trust_auth_response.cpp" "types/server_trust_auth_response.h" + "types/security_origin.cpp" + "types/security_origin.h" + "types/frame_info.cpp" + "types/frame_info.h" + "types/process_failed_detail.cpp" + "types/process_failed_detail.h" + "types/render_process_gone_detail.cpp" + "types/render_process_gone_detail.h" "custom_platform_view/custom_platform_view.cc" "custom_platform_view/custom_platform_view.h" "custom_platform_view/texture_bridge.cc" 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 190533f0f..e58951fec 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 @@ -896,6 +896,74 @@ namespace flutter_inappwebview_plugin ).Get(), nullptr); failedLog(add_WebResourceRequested_HResult); + auto add_ProcessFailed_HResult = webView->add_ProcessFailed( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ProcessFailedEventArgs* argsRaw) + { + if (!channelDelegate) { + return S_OK; + } + + wil::com_ptr args = argsRaw; + auto args2 = args.try_query(); + auto args3 = args.try_query(); + + COREWEBVIEW2_PROCESS_FAILED_REASON reason = COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED; + if (args2) { + args2->get_Reason(&reason); + } + + COREWEBVIEW2_PROCESS_FAILED_KIND kind; + if (succeededOrLog(args->get_ProcessFailedKind(&kind))) { + if (kind == COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED) { + auto didCrash = reason == COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED; + auto detail = std::make_unique( + didCrash + ); + channelDelegate->onRenderProcessGone(std::move(detail)); + } + else if (kind == COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE) { + channelDelegate->onRenderProcessUnresponsive(getUrl()); + } + else if (kind == COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED) { + channelDelegate->onWebContentProcessDidTerminate(); + } + + auto frameInfos = std::optional>>{}; + wil::com_ptr frameInfoCollection; + wil::com_ptr frameIterator; + if (args2 && succeededOrLog(args2->get_FrameInfosForFailedProcess(&frameInfoCollection)) && frameInfoCollection && succeededOrLog(frameInfoCollection->GetIterator(&frameIterator))) { + frameInfos = std::vector>{}; + BOOL hasCurrent = FALSE; + while (SUCCEEDED(frameIterator->MoveNext(&hasCurrent)) && hasCurrent) { + wil::com_ptr frameInfo; + if (SUCCEEDED(frameIterator->GetCurrent(&frameInfo))) { + frameInfos.value().push_back(std::move(FrameInfo::fromICoreWebView2FrameInfo(frameInfo))); + } + BOOL hasNext = FALSE; + failedLog(frameIterator->MoveNext(&hasNext)); + } + } + + wil::unique_cotaskmem_string processDescription; + int exitCode; + wil::unique_cotaskmem_string failedModule; + + auto detail = std::make_unique( + (int64_t)kind, + args2 && succeededOrLog(args2->get_ExitCode(&exitCode)) ? exitCode : std::optional{}, + args2 && succeededOrLog(args2->get_ProcessDescription(&processDescription)) ? wide_to_utf8(processDescription.get()) : std::optional{}, + args2 ? (int64_t)reason : std::optional{}, + args3 && succeededOrLog(args3->get_FailureSourceModulePath(&failedModule)) ? wide_to_utf8(failedModule.get()) : std::optional{}, + frameInfos + ); + channelDelegate->onProcessFailed(std::move(detail)); + } + return S_OK; + } + ).Get(), nullptr); + failedLog(add_ProcessFailed_HResult); + wil::com_ptr webView2; if (SUCCEEDED(webView->QueryInterface(IID_PPV_ARGS(&webView2)))) { auto add_DOMContentLoaded_HResult = webView2->add_DOMContentLoaded( 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 b548aacfd..5ef3e11f9 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 @@ -552,6 +552,47 @@ namespace flutter_inappwebview_plugin channel->InvokeMethod("onReceivedServerTrustAuthRequest", std::move(arguments), std::move(callback)); } + void WebViewChannelDelegate::onRenderProcessGone(const std::shared_ptr detail) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(detail->toEncodableMap()); + channel->InvokeMethod("onDevToolsProtocolEventReceived", std::move(arguments)); + } + + void WebViewChannelDelegate::onRenderProcessUnresponsive(const std::optional& url) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(flutter::EncodableMap{ + {"url", make_fl_value(url)}, + }); + channel->InvokeMethod("onRenderProcessUnresponsive", std::move(arguments)); + } + void WebViewChannelDelegate::onWebContentProcessDidTerminate() const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(); + channel->InvokeMethod("onWebContentProcessDidTerminate", std::move(arguments)); + } + + void WebViewChannelDelegate::onProcessFailed(const std::shared_ptr detail) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(detail->toEncodableMap()); + channel->InvokeMethod("onProcessFailed", 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 dfe68c238..dfd4a3395 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 @@ -15,6 +15,8 @@ #include "../types/javascript_handler_function_data.h" #include "../types/navigation_action.h" #include "../types/permission_response.h" +#include "../types/process_failed_detail.h" +#include "../types/render_process_gone_detail.h" #include "../types/server_trust_auth_response.h" #include "../types/server_trust_challenge.h" #include "../types/web_resource_error.h" @@ -113,6 +115,10 @@ namespace flutter_inappwebview_plugin void onReceivedHttpAuthRequest(std::shared_ptr challenge, std::unique_ptr callback) const; void onReceivedClientCertRequest(std::shared_ptr challenge, std::unique_ptr callback) const; void onReceivedServerTrustAuthRequest(std::shared_ptr challenge, std::unique_ptr callback) const; + void onRenderProcessGone(const std::shared_ptr detail) const; + void onRenderProcessUnresponsive(const std::optional& url) const; + void onWebContentProcessDidTerminate() const; + void onProcessFailed(const std::shared_ptr detail) const; }; } diff --git a/flutter_inappwebview_windows/windows/types/frame_info.cpp b/flutter_inappwebview_windows/windows/types/frame_info.cpp new file mode 100644 index 000000000..f04d48c20 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/frame_info.cpp @@ -0,0 +1,76 @@ +#include "../utils/flutter.h" +#include "../utils/log.h" +#include "../utils/strconv.h" +#include "frame_info.h" + +#include + +namespace flutter_inappwebview_plugin +{ + FrameInfo::FrameInfo(const bool& isMainFrame, + const std::optional> request, + const std::optional> securityOrigin, + const std::optional& name, + const std::optional& frameId, + const std::optional& kind) + : isMainFrame(isMainFrame), request(request), securityOrigin(securityOrigin), name(name), frameId(frameId), kind(kind) + {} + + flutter::EncodableMap FrameInfo::toEncodableMap() const + { + return flutter::EncodableMap{ + {"isMainFrame", make_fl_value(isMainFrame)}, + {"request", request.has_value() ? request.value()->toEncodableMap() : make_fl_value()}, + {"securityOrigin", securityOrigin.has_value() ? securityOrigin.value()->toEncodableMap() : make_fl_value()}, + {"name", make_fl_value(name)}, + {"frameId", make_fl_value(frameId)}, + {"kind", make_fl_value(kind)} + }; + } + + std::unique_ptr FrameInfo::fromICoreWebView2FrameInfo(const wil::com_ptr webViewFrameInfo) + { + wil::unique_cotaskmem_string url; + auto request = std::optional>{}; + auto securityOrigin = std::optional>{}; + if (succeededOrLog(webViewFrameInfo->get_Source(&url))) { + request = std::make_shared( + wide_to_utf8(url.get()), + std::optional{}, + std::optional>{}, + std::optional>{} + ); + + try { + winrt::Windows::Foundation::Uri const uri{ url.get() }; + + securityOrigin = std::make_shared( + wide_to_utf8(uri.Host().c_str()), + uri.Port(), + wide_to_utf8(uri.SchemeName().c_str()) + ); + } + catch (winrt::hresult_error const& ex) { + debugLog(wide_to_utf8(ex.message().c_str())); + } + } + + auto webViewFrameInfo2 = webViewFrameInfo.try_query(); + + uint32_t frameId; + wil::unique_cotaskmem_string name; + COREWEBVIEW2_FRAME_KIND kind = COREWEBVIEW2_FRAME_KIND_UNKNOWN; + if (webViewFrameInfo2) { + failedLog(webViewFrameInfo2->get_FrameKind(&kind)); + } + + return std::make_unique( + webViewFrameInfo2 ? kind == COREWEBVIEW2_FRAME_KIND_MAIN_FRAME : false, + request, + securityOrigin, + succeededOrLog(webViewFrameInfo->get_Name(&name)) ? wide_to_utf8(name.get()) : std::optional{}, + webViewFrameInfo2 && succeededOrLog(webViewFrameInfo2->get_FrameId(&frameId)) ? frameId : std::optional{}, + webViewFrameInfo2 ? (int64_t)kind : std::optional{} + ); + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/frame_info.h b/flutter_inappwebview_windows/windows/types/frame_info.h new file mode 100644 index 000000000..103c30e1a --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/frame_info.h @@ -0,0 +1,39 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_FRAME_INFO_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_FRAME_INFO_H_ + +#include +#include +#include +#include +#include + +#include "security_origin.h" +#include "url_request.h" + +namespace flutter_inappwebview_plugin +{ + + class FrameInfo + { + public: + const bool isMainFrame; + const std::optional> request; + const std::optional> securityOrigin; + const std::optional name; + const std::optional frameId; + const std::optional kind; + + FrameInfo(const bool& isMainFrame, + const std::optional> request, + const std::optional> securityOrigin, + const std::optional& name, + const std::optional& frameId, + const std::optional& kind); + ~FrameInfo() = default; + + flutter::EncodableMap toEncodableMap() const; + static std::unique_ptr fromICoreWebView2FrameInfo(const wil::com_ptr webViewFrameInfo); + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_FRAME_INFO_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/process_failed_detail.cpp b/flutter_inappwebview_windows/windows/types/process_failed_detail.cpp new file mode 100644 index 000000000..be305a661 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/process_failed_detail.cpp @@ -0,0 +1,26 @@ +#include "../utils/flutter.h" +#include "process_failed_detail.h" + +namespace flutter_inappwebview_plugin +{ + ProcessFailedDetail::ProcessFailedDetail(const int64_t& kind, + const std::optional& exitCode, + const std::optional& processDescription, + const std::optional& reason, + const std::optional& failureSourceModulePath, + const std::optional>>& frameInfos) + : kind(kind), exitCode(exitCode), processDescription(processDescription), reason(reason), failureSourceModulePath(failureSourceModulePath), frameInfos(frameInfos) + {} + + flutter::EncodableMap ProcessFailedDetail::toEncodableMap() const + { + return flutter::EncodableMap{ + {"kind", make_fl_value(kind)}, + {"exitCode", make_fl_value(exitCode)}, + {"processDescription", make_fl_value(processDescription)}, + {"reason", make_fl_value(reason)}, + {"failureSourceModulePath", make_fl_value(failureSourceModulePath)}, + {"frameInfos", frameInfos.has_value() ? make_fl_value(functional_map(frameInfos.value(), [](const std::shared_ptr& item) { return item->toEncodableMap(); })) : make_fl_value()} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/process_failed_detail.h b/flutter_inappwebview_windows/windows/types/process_failed_detail.h new file mode 100644 index 000000000..555ae4f69 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/process_failed_detail.h @@ -0,0 +1,36 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PROCESS_FAILED_DETAIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_PROCESS_FAILED_DETAIL_H_ + +#include +#include +#include +#include + +#include "frame_info.h" + +namespace flutter_inappwebview_plugin +{ + + class ProcessFailedDetail + { + public: + const int64_t kind; + const std::optional exitCode; + const std::optional processDescription; + const std::optional reason; + const std::optional failureSourceModulePath; + const std::optional>> frameInfos; + + ProcessFailedDetail(const int64_t& kind, + const std::optional& exitCode, + const std::optional& processDescription, + const std::optional& reason, + const std::optional& failureSourceModulePath, + const std::optional>>& frameInfos); + ~ProcessFailedDetail() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_PROCESS_FAILED_DETAIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/render_process_gone_detail.cpp b/flutter_inappwebview_windows/windows/types/render_process_gone_detail.cpp new file mode 100644 index 000000000..8fbb1238a --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/render_process_gone_detail.cpp @@ -0,0 +1,16 @@ +#include "../utils/flutter.h" +#include "render_process_gone_detail.h" + +namespace flutter_inappwebview_plugin +{ + RenderProcessGoneDetail::RenderProcessGoneDetail(const bool& didCrash) + : didCrash(didCrash) + {} + + flutter::EncodableMap RenderProcessGoneDetail::toEncodableMap() const + { + return flutter::EncodableMap{ + {"didCrash", make_fl_value(didCrash)} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/render_process_gone_detail.h b/flutter_inappwebview_windows/windows/types/render_process_gone_detail.h new file mode 100644 index 000000000..3e324c1ae --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/render_process_gone_detail.h @@ -0,0 +1,21 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_RENDER_PROCESS_GONE_DETAIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_RENDER_PROCESS_GONE_DETAIL_H_ + +#include + +namespace flutter_inappwebview_plugin +{ + + class RenderProcessGoneDetail + { + public: + const bool didCrash; + + RenderProcessGoneDetail(const bool& didCrash); + ~RenderProcessGoneDetail() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_RENDER_PROCESS_GONE_DETAIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/security_origin.cpp b/flutter_inappwebview_windows/windows/types/security_origin.cpp new file mode 100644 index 000000000..bfd43a329 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/security_origin.cpp @@ -0,0 +1,18 @@ +#include "../utils/flutter.h" +#include "security_origin.h" + +namespace flutter_inappwebview_plugin +{ + SecurityOrigin::SecurityOrigin(const std::string& host, const int64_t& port, const std::string& protocol) + : host(host), port(port), protocol(protocol) + {} + + flutter::EncodableMap SecurityOrigin::toEncodableMap() const + { + return flutter::EncodableMap{ + {"host", make_fl_value(host)}, + {"port", make_fl_value(port)}, + {"protocol", make_fl_value(protocol)} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/security_origin.h b/flutter_inappwebview_windows/windows/types/security_origin.h new file mode 100644 index 000000000..84c3fee28 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/security_origin.h @@ -0,0 +1,24 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_SECURITY_ORIGIN_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_SECURITY_ORIGIN_H_ + +#include +#include + +namespace flutter_inappwebview_plugin +{ + + class SecurityOrigin + { + public: + const std::string host; + const int64_t port; + const std::string protocol; + + SecurityOrigin(const std::string& host, const int64_t& port, const std::string& protocol); + ~SecurityOrigin() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_SECURITY_ORIGIN_H_ \ No newline at end of file From df18df4419a5871a648c3c2800c2743919daa0bb Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Mon, 4 Nov 2024 02:14:52 +0100 Subject: [PATCH 046/137] Deprecated InAppWebViewSettings.forceDark and InAppWebViewSettings.forceDarkStrategy Android-only properties in favor of InAppWebViewSettings.algorithmicDarkeningAllowed --- .../src/exchangeable_object_generator.dart | 55 ++++++++++++++----- dev_packages/generators/pubspec.yaml | 1 + flutter_inappwebview/CHANGELOG.md | 1 + .../webview/in_app_webview/InAppWebView.java | 16 +++++- .../in_app_webview/InAppWebViewSettings.java | 9 ++- .../CHANGELOG.md | 1 + .../lib/src/context_menu/context_menu.dart | 4 +- .../lib/src/context_menu/context_menu.g.dart | 7 ++- .../context_menu/context_menu_settings.dart | 20 +------ .../context_menu/context_menu_settings.g.dart | 43 +++++++++++++++ .../platform_in_app_browser.dart | 4 ++ .../in_app_webview_settings.dart | 25 +++++++-- .../in_app_webview_settings.g.dart | 38 +++++++++---- .../src/in_app_webview/platform_webview.dart | 4 ++ 14 files changed, 170 insertions(+), 58 deletions(-) diff --git a/dev_packages/generators/lib/src/exchangeable_object_generator.dart b/dev_packages/generators/lib/src/exchangeable_object_generator.dart index ed5cb23e9..71ccd3198 100644 --- a/dev_packages/generators/lib/src/exchangeable_object_generator.dart +++ b/dev_packages/generators/lib/src/exchangeable_object_generator.dart @@ -1,9 +1,10 @@ -import 'package:build/src/builder/build_step.dart'; -import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/analysis/results.dart'; +import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; -import 'package:source_gen/source_gen.dart'; +import 'package:build/src/builder/build_step.dart'; +import 'package:collection/collection.dart'; import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'package:source_gen/source_gen.dart'; import 'model_visitor.dart'; import 'util.dart'; @@ -229,24 +230,26 @@ class ExchangeableObjectGenerator .firstAnnotationOfExact(deprecatedField)! .getField("message")! .toStringValue()!; - final fieldName = message + final newFieldName = message .replaceFirst("Use ", "") .replaceFirst(" instead", "") .trim(); - final fieldElement = visitor.fields[fieldName]; - if (fieldElement != null) { - final fieldTypeElement = fieldElement.type.element; + + final newFieldElement = visitor.fields[newFieldName]; + final shouldUseNewFieldName = newFieldElement != null; + if (shouldUseNewFieldName) { + final fieldTypeElement = newFieldElement.type.element; final deprecatedFieldTypeElement = deprecatedField.type.element; - final isNullable = Util.typeIsNullable(fieldElement.type); - var hasDefaultValue = (fieldElement is ParameterElement) - ? (fieldElement as ParameterElement).hasDefaultValue + final isNullable = Util.typeIsNullable(newFieldElement.type); + var hasDefaultValue = (newFieldElement is ParameterElement) + ? (newFieldElement as ParameterElement).hasDefaultValue : false; if (!isNullable && hasDefaultValue) { continue; } - classBuffer.write('$fieldName = $fieldName ?? '); + classBuffer.write('$newFieldName = $newFieldName ?? '); if (fieldTypeElement != null && deprecatedFieldTypeElement != null) { final deprecatedIsNullable = Util.typeIsNullable(deprecatedField.type); @@ -274,7 +277,7 @@ class ExchangeableObjectGenerator } else if (deprecatedField.type .getDisplayString(withNullability: false) == "Uri" && - fieldElement.type.getDisplayString(withNullability: false) == + newFieldElement.type.getDisplayString(withNullability: false) == "WebUri") { if (deprecatedIsNullable) { classBuffer.write( @@ -333,7 +336,26 @@ class ExchangeableObjectGenerator .replaceFirst("Use ", "") .replaceFirst(" instead", "") .trim(); - value = "map['$newFieldName']"; + final newFieldElement = fieldElements + .firstWhereOrNull((element) => element.name == newFieldName); + final shouldUseNewFieldName = newFieldElement != null && + (newFieldElement.type == fieldElement.type || + (fieldElement.name.startsWith(RegExp(r'android|ios')) && + fieldElement.name.toLowerCase().replaceFirst( + RegExp(r'android|ioswk|ios'), "") == + newFieldName.toLowerCase()) || + (newFieldElement.type.element != null && + fieldElement.type.element != null && + ((hasFromNativeValueMethod( + newFieldElement.type.element!) && + hasFromNativeValueMethod( + fieldElement.type.element!) || + (hasFromMapMethod(newFieldElement.type.element!) && + hasFromMapMethod( + fieldElement.type.element!)))))); + if (shouldUseNewFieldName) { + value = "map['$newFieldName']"; + } } final mapValue = value; @@ -356,10 +378,13 @@ class ExchangeableObjectGenerator final constructorParameter = visitor.constructorParameters[fieldName]; final isRequiredParameter = constructorParameter != null && (constructorParameter.isRequiredNamed || - constructorParameter.isFinal || fieldElement.isFinal || + constructorParameter.isFinal || + fieldElement.isFinal || !Util.typeIsNullable(constructorParameter.type)) && !constructorParameter.hasDefaultValue; - if (isRequiredParameter || fieldElement.isFinal || annotation.read("fromMapForceAllInline").boolValue) { + if (isRequiredParameter || + fieldElement.isFinal || + annotation.read("fromMapForceAllInline").boolValue) { requiredFields.add('$fieldName: $value,'); } else { final isFieldNullable = Util.typeIsNullable(fieldElement.type); diff --git a/dev_packages/generators/pubspec.yaml b/dev_packages/generators/pubspec.yaml index ffa31b464..5a2622d9a 100755 --- a/dev_packages/generators/pubspec.yaml +++ b/dev_packages/generators/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: sdk: flutter build: ^2.4.1 source_gen: ^1.5.0 + collection: any flutter_inappwebview_internal_annotations: ^1.1.1 dev_dependencies: diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index 1c6265bee..3f310b32a 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -19,6 +19,7 @@ Implemented security features to better manage access to the native javascript b - Added `onProcessFailed` WebView event - Added `JavaScriptHandlerFunctionData` type - Deprecated `JavaScriptHandlerCallback` type in favor of `JavaScriptHandlerFunction` type +- Deprecated `InAppWebViewSettings.forceDark` and `InAppWebViewSettings.forceDarkStrategy` Android-only properties in favor of `InAppWebViewSettings.algorithmicDarkeningAllowed` - Fixed X509Certificate PEM base64 decoding - Fixed specific URLAuthenticationChallenge type for `onReceivedHttpAuthRequest`, `onReceivedServerTrustAuthRequest`, `onReceivedClientCertRequest` events diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java index 2fe614887..d77686ec3 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebView.java @@ -373,7 +373,13 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) settings.setForceDark(customSettings.forceDark); } if (customSettings.forceDarkStrategy != null && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { - WebSettingsCompat.setForceDarkStrategy(settings, customSettings.forceDarkStrategy); + try { + // for some reason the setForceDarkStrategy method could throw a ClassCastException + // from the Android WebView Chromium library. + WebSettingsCompat.setForceDarkStrategy(settings, customSettings.forceDarkStrategy); + } catch (Exception e) { + e.printStackTrace(); + } } settings.setGeolocationEnabled(customSettings.geolocationEnabled); if (customSettings.layoutAlgorithm != null) { @@ -995,7 +1001,13 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) if (newSettingsMap.get("forceDarkStrategy") != null && !customSettings.forceDarkStrategy.equals(newCustomSettings.forceDarkStrategy) && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { - WebSettingsCompat.setForceDarkStrategy(settings, newCustomSettings.forceDarkStrategy); + try { + // for some reason the setForceDarkStrategy method could throw a ClassCastException + // from the Android WebView Chromium library. + WebSettingsCompat.setForceDarkStrategy(settings, newCustomSettings.forceDarkStrategy); + } catch (Exception e) { + e.printStackTrace(); + } } if (newSettingsMap.get("geolocationEnabled") != null && customSettings.geolocationEnabled != newCustomSettings.geolocationEnabled) diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java index 0a1a4b745..6f7744a62 100755 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/in_app_webview/InAppWebViewSettings.java @@ -87,8 +87,10 @@ public class InAppWebViewSettings implements ISettings { public Integer disabledActionModeMenuItems; public String fantasyFontFamily = "fantasy"; public String fixedFontFamily = "monospace"; - public Integer forceDark = 0; // WebSettingsCompat.FORCE_DARK_OFF - public Integer forceDarkStrategy = WebSettingsCompat.DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING; + @Nullable @Deprecated + public Integer forceDark = null; + @Nullable @Deprecated + public Integer forceDarkStrategy = null; public Boolean geolocationEnabled = true; public WebSettings.LayoutAlgorithm layoutAlgorithm; public Boolean loadWithOverviewMode = true; @@ -106,11 +108,14 @@ public class InAppWebViewSettings implements ISettings { public Boolean supportMultipleWindows = false; public String regexToCancelSubFramesLoading; public Integer overScrollMode = View.OVER_SCROLL_IF_CONTENT_SCROLLS; + @Nullable public Boolean networkAvailable = null; public Integer scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY; public Integer verticalScrollbarPosition = View.SCROLLBAR_POSITION_DEFAULT; + @Nullable public Integer scrollBarDefaultDelayBeforeFade = null; public Boolean scrollbarFadingEnabled = true; + @Nullable public Integer scrollBarFadeDuration = null; @Nullable public Map rendererPriorityPolicy = null; diff --git a/flutter_inappwebview_platform_interface/CHANGELOG.md b/flutter_inappwebview_platform_interface/CHANGELOG.md index 8bf316fed..ed56cf1ee 100644 --- a/flutter_inappwebview_platform_interface/CHANGELOG.md +++ b/flutter_inappwebview_platform_interface/CHANGELOG.md @@ -8,6 +8,7 @@ - Added `onProcessFailed` WebView event - Added `JavaScriptHandlerFunctionData` type - Deprecated `JavaScriptHandlerCallback` type in favor of `JavaScriptHandlerFunction` type +- Deprecated `InAppWebViewSettings.forceDark` and `InAppWebViewSettings.forceDarkStrategy` Android-only properties in favor of `InAppWebViewSettings.algorithmicDarkeningAllowed` - Fixed X509Certificate PEM base64 decoding - Fixed specific URLAuthenticationChallenge type for `onReceivedHttpAuthRequest`, `onReceivedServerTrustAuthRequest`, `onReceivedClientCertRequest` events diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart index 6e790c4d7..f791abaac 100644 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart +++ b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart @@ -33,7 +33,7 @@ class ContextMenu_ { ///Use [settings] instead @Deprecated("Use settings instead") - final ContextMenuOptions? options; + final ContextMenuOptions_? options; ///Context menu settings. final ContextMenuSettings_? settings; @@ -55,7 +55,7 @@ class ContextMenu_ { Map _toMapMergeWith() { return { "settings": - (settings as ContextMenuSettings?)?.toMap() ?? options?.toMap() + (settings as ContextMenuSettings?)?.toMap() ?? (options as ContextMenuOptions?)?.toMap() }; } } diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.g.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.g.dart index 84e63405f..246632d29 100644 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.g.dart @@ -59,7 +59,8 @@ class ContextMenu { final instance = ContextMenu( menuItems: List.from(map['menuItems'] .map((e) => ContextMenuItem.fromMap(e?.cast())!)), - options: map['settings'], + options: + ContextMenuOptions.fromMap(map['settings']?.cast()), settings: ContextMenuSettings.fromMap(map['settings']?.cast()), ); @@ -69,8 +70,8 @@ class ContextMenu { @ExchangeableObjectMethod(toMapMergeWith: true) Map _toMapMergeWith() { return { - "settings": - (settings as ContextMenuSettings?)?.toMap() ?? options?.toMap() + "settings": (settings as ContextMenuSettings?)?.toMap() ?? + (options as ContextMenuOptions?)?.toMap() }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.dart index dd6c001a4..8f4565787 100644 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.dart @@ -15,24 +15,10 @@ class ContextMenuSettings_ { ///Use [ContextMenuSettings] instead. @Deprecated("Use ContextMenuSettings instead") -class ContextMenuOptions { +@ExchangeableObject(copyMethod: true) +class ContextMenuOptions_ { ///Whether all the default system context menu items should be hidden or not. The default value is `false`. bool hideDefaultSystemContextMenuItems; - ContextMenuOptions({this.hideDefaultSystemContextMenuItems = false}); - - Map toMap() { - return { - "hideDefaultSystemContextMenuItems": hideDefaultSystemContextMenuItems - }; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } + ContextMenuOptions_({this.hideDefaultSystemContextMenuItems = false}); } diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart index 1c91e9eca..9f02f2bf2 100644 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu_settings.g.dart @@ -47,3 +47,46 @@ class ContextMenuSettings { return 'ContextMenuSettings{hideDefaultSystemContextMenuItems: $hideDefaultSystemContextMenuItems}'; } } + +///Use [ContextMenuSettings] instead. +@Deprecated('Use ContextMenuSettings instead') +class ContextMenuOptions { + ///Whether all the default system context menu items should be hidden or not. The default value is `false`. + bool hideDefaultSystemContextMenuItems; + ContextMenuOptions({this.hideDefaultSystemContextMenuItems = false}); + + ///Gets a possible [ContextMenuOptions] instance from a [Map] value. + static ContextMenuOptions? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = ContextMenuOptions(); + if (map['hideDefaultSystemContextMenuItems'] != null) { + instance.hideDefaultSystemContextMenuItems = + map['hideDefaultSystemContextMenuItems']; + } + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "hideDefaultSystemContextMenuItems": hideDefaultSystemContextMenuItems, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + ///Returns a copy of ContextMenuOptions. + ContextMenuOptions copy() { + return ContextMenuOptions.fromMap(toMap()) ?? ContextMenuOptions(); + } + + @override + String toString() { + return 'ContextMenuOptions{hideDefaultSystemContextMenuItems: $hideDefaultSystemContextMenuItems}'; + } +} 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 4a059886a..542ba56e2 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 @@ -827,6 +827,10 @@ abstract class PlatformInAppBrowserEvents { /// ///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [ServerTrustChallenge]. /// + ///**NOTE for iOS and macOS**: to override the certificate verification logic, you have to provide ATS (App Transport Security) exceptions in your iOS/macOS `Info.plist`. + ///See `NSAppTransportSecurity` in the [Information Property List Key Reference](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW1) + ///for details. + /// ///**Officially Supported Platforms/Implementations**: ///- Android native WebView ([Official API - WebViewClient.onReceivedSslError](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%20android.webkit.SslErrorHandler,%20android.net.http.SslError))) ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview)) diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart index f85030c44..4e68f34c9 100755 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart @@ -624,7 +624,16 @@ because there isn't any way to make the website data store non-persistent for th ]) String? fixedFontFamily; + ///Use [algorithmicDarkeningAllowed] instead. + /// ///Set the force dark mode for this WebView. The default value is [ForceDark.OFF]. + /// + ///Deprecated - The "force dark" model previously implemented by WebView was complex and didn't + ///interoperate well with current Web standards for `prefers-color-scheme` and `color-scheme`. + ///In apps with `targetSdkVersion` ≥ `android.os.Build.VERSION_CODES.TIRAMISU` this API is a no-op and + ///WebView will always use the dark style defined by web content authors if the app's theme is dark. + ///To customize the behavior, refer to [algorithmicDarkeningAllowed]. + @Deprecated("Use algorithmicDarkeningAllowed instead") @SupportedPlatforms(platforms: [ AndroidPlatform( available: "29", @@ -634,10 +643,17 @@ because there isn't any way to make the website data store non-persistent for th ]) ForceDark_? forceDark; - ///Sets whether Geolocation API is enabled. The default value is `true`. - + ///Use [algorithmicDarkeningAllowed] instead. + /// ///Set how WebView content should be darkened. ///The default value is [ForceDarkStrategy.PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING]. + /// + ///Deprecated - The "force dark" model previously implemented by WebView was complex and didn't + ///interoperate well with current Web standards for `prefers-color-scheme` and `color-scheme`. + ///In apps with `targetSdkVersion` ≥ `android.os.Build.VERSION_CODES.TIRAMISU` this API is a no-op and + ///WebView will always use the dark style defined by web content authors if the app's theme is dark. + ///To customize the behavior, refer to [algorithmicDarkeningAllowed]. + @Deprecated("Use algorithmicDarkeningAllowed instead") @SupportedPlatforms(platforms: [ AndroidPlatform( apiName: "WebSettingsCompat.setForceDarkStrategy", @@ -1862,9 +1878,8 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri this.disabledActionModeMenuItems, this.fantasyFontFamily = "fantasy", this.fixedFontFamily = "monospace", - this.forceDark = ForceDark_.OFF, - this.forceDarkStrategy = - ForceDarkStrategy_.PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING, + this.forceDark, + this.forceDarkStrategy, this.geolocationEnabled = true, this.layoutAlgorithm, this.loadWithOverviewMode = true, diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart index 11f6a9f21..7982ceb05 100644 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.g.dart @@ -470,20 +470,37 @@ class InAppWebViewSettings { ///- Android native WebView ([Official API - WebSettings.setFixedFontFamily](https://developer.android.com/reference/android/webkit/WebSettings#setFixedFontFamily(java.lang.String))) String? fixedFontFamily; + ///Use [algorithmicDarkeningAllowed] instead. + /// ///Set the force dark mode for this WebView. The default value is [ForceDark.OFF]. /// + ///Deprecated - The "force dark" model previously implemented by WebView was complex and didn't + ///interoperate well with current Web standards for `prefers-color-scheme` and `color-scheme`. + ///In apps with `targetSdkVersion` ≥ `android.os.Build.VERSION_CODES.TIRAMISU` this API is a no-op and + ///WebView will always use the dark style defined by web content authors if the app's theme is dark. + ///To customize the behavior, refer to [algorithmicDarkeningAllowed]. + /// ///**Officially Supported Platforms/Implementations**: ///- Android native WebView 29+ ([Official API - WebSettings.setForceDark](https://developer.android.com/reference/android/webkit/WebSettings#setForceDark(int))) + @Deprecated('Use algorithmicDarkeningAllowed instead') ForceDark? forceDark; - ///Sets whether Geolocation API is enabled. The default value is `true`. + ///Use [algorithmicDarkeningAllowed] instead. + /// ///Set how WebView content should be darkened. ///The default value is [ForceDarkStrategy.PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING]. /// + ///Deprecated - The "force dark" model previously implemented by WebView was complex and didn't + ///interoperate well with current Web standards for `prefers-color-scheme` and `color-scheme`. + ///In apps with `targetSdkVersion` ≥ `android.os.Build.VERSION_CODES.TIRAMISU` this API is a no-op and + ///WebView will always use the dark style defined by web content authors if the app's theme is dark. + ///To customize the behavior, refer to [algorithmicDarkeningAllowed]. + /// ///**NOTE for Android native WebView**: it will take effect only if [WebViewFeature.isFeatureSupported] returns `true` for [WebViewFeature.FORCE_DARK_STRATEGY]. /// ///**Officially Supported Platforms/Implementations**: ///- Android native WebView ([Official API - WebSettingsCompat.setForceDarkStrategy](https://developer.android.com/reference/androidx/webkit/WebSettingsCompat#setForceDarkStrategy(android.webkit.WebSettings,int))) + @Deprecated('Use algorithmicDarkeningAllowed instead') ForceDarkStrategy? forceDarkStrategy; ///Sets whether Geolocation is enabled. The default is `true`. @@ -1394,9 +1411,8 @@ class InAppWebViewSettings { this.disabledActionModeMenuItems, this.fantasyFontFamily = "fantasy", this.fixedFontFamily = "monospace", - this.forceDark = ForceDark.OFF, - this.forceDarkStrategy = - ForceDarkStrategy.PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING, + this.forceDark, + this.forceDarkStrategy, this.geolocationEnabled = true, this.layoutAlgorithm, this.loadWithOverviewMode = true, @@ -1531,6 +1547,9 @@ class InAppWebViewSettings { : null, disabledActionModeMenuItems: ActionModeMenuItem.fromNativeValue( map['disabledActionModeMenuItems']), + forceDark: ForceDark.fromNativeValue(map['forceDark']), + forceDarkStrategy: + ForceDarkStrategy.fromNativeValue(map['forceDarkStrategy']), horizontalScrollbarThumbColor: map['horizontalScrollbarThumbColor'] != null ? UtilColor.fromStringRepresentation( @@ -1640,8 +1659,8 @@ class InAppWebViewSettings { instance.builtInZoomControls = map['builtInZoomControls']; instance.cacheEnabled = map['cacheEnabled']; instance.cacheMode = CacheMode.fromNativeValue(map['cacheMode']); - instance.clearCache = map['InAppWebViewController.clearAllCache']; - instance.clearSessionCache = map['CookieManager.removeSessionCookies']; + instance.clearCache = map['clearCache']; + instance.clearSessionCache = map['clearSessionCache']; instance.contentBlockers = _deserializeContentBlockers(map['contentBlockers']); instance.contentInsetAdjustmentBehavior = @@ -1673,9 +1692,6 @@ class InAppWebViewSettings { map['enterpriseAuthenticationAppLinkPolicyEnabled']; instance.fantasyFontFamily = map['fantasyFontFamily']; instance.fixedFontFamily = map['fixedFontFamily']; - instance.forceDark = ForceDark.fromNativeValue(map['forceDark']); - instance.forceDarkStrategy = - ForceDarkStrategy.fromNativeValue(map['forceDarkStrategy']); instance.geolocationEnabled = map['geolocationEnabled']; instance.hardwareAcceleration = map['hardwareAcceleration']; instance.horizontalScrollBarEnabled = map['horizontalScrollBarEnabled']; @@ -1809,8 +1825,6 @@ class InAppWebViewSettings { enterpriseAuthenticationAppLinkPolicyEnabled, "fantasyFontFamily": fantasyFontFamily, "fixedFontFamily": fixedFontFamily, - "forceDark": forceDark?.toNativeValue(), - "forceDarkStrategy": forceDarkStrategy?.toNativeValue(), "geolocationEnabled": geolocationEnabled, "hardwareAcceleration": hardwareAcceleration, "horizontalScrollBarEnabled": horizontalScrollBarEnabled, @@ -1925,6 +1939,6 @@ class InAppWebViewSettings { @override String toString() { - return 'InAppWebViewSettings{accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowingReadAccessTo: $allowingReadAccessTo, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsLinkPreview: $allowsLinkPreview, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, alwaysBounceHorizontal: $alwaysBounceHorizontal, alwaysBounceVertical: $alwaysBounceVertical, appCachePath: $appCachePath, applePayAPIEnabled: $applePayAPIEnabled, applicationNameForUserAgent: $applicationNameForUserAgent, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, builtInZoomControls: $builtInZoomControls, cacheEnabled: $cacheEnabled, cacheMode: $cacheMode, contentBlockers: $contentBlockers, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, cursiveFontFamily: $cursiveFontFamily, dataDetectorTypes: $dataDetectorTypes, databaseEnabled: $databaseEnabled, decelerationRate: $decelerationRate, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, defaultVideoPoster: $defaultVideoPoster, disableContextMenu: $disableContextMenu, disableDefaultErrorPage: $disableDefaultErrorPage, disableHorizontalScroll: $disableHorizontalScroll, disableInputAccessoryView: $disableInputAccessoryView, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableVerticalScroll: $disableVerticalScroll, disabledActionModeMenuItems: $disabledActionModeMenuItems, disallowOverScroll: $disallowOverScroll, displayZoomControls: $displayZoomControls, domStorageEnabled: $domStorageEnabled, enableViewportScale: $enableViewportScale, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, forceDark: $forceDark, forceDarkStrategy: $forceDarkStrategy, geolocationEnabled: $geolocationEnabled, hardwareAcceleration: $hardwareAcceleration, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeAriaHidden: $iframeAriaHidden, iframeCsp: $iframeCsp, iframeName: $iframeName, iframeReferrerPolicy: $iframeReferrerPolicy, iframeRole: $iframeRole, iframeSandbox: $iframeSandbox, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, incognito: $incognito, initialScale: $initialScale, interceptOnlyAsyncAjaxRequests: $interceptOnlyAsyncAjaxRequests, isDirectionalLockEnabled: $isDirectionalLockEnabled, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, isInspectable: $isInspectable, isPagingEnabled: $isPagingEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, isTextInteractionEnabled: $isTextInteractionEnabled, javaScriptBridgeEnabled: $javaScriptBridgeEnabled, javaScriptBridgeForMainFrameOnly: $javaScriptBridgeForMainFrameOnly, javaScriptBridgeOriginAllowList: $javaScriptBridgeOriginAllowList, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, javaScriptEnabled: $javaScriptEnabled, javaScriptHandlersForMainFrameOnly: $javaScriptHandlersForMainFrameOnly, javaScriptHandlersOriginAllowList: $javaScriptHandlersOriginAllowList, layoutAlgorithm: $layoutAlgorithm, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, maximumViewportInset: $maximumViewportInset, maximumZoomScale: $maximumZoomScale, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, mediaType: $mediaType, minimumFontSize: $minimumFontSize, minimumLogicalFontSize: $minimumLogicalFontSize, minimumViewportInset: $minimumViewportInset, minimumZoomScale: $minimumZoomScale, mixedContentMode: $mixedContentMode, needInitialFocus: $needInitialFocus, networkAvailable: $networkAvailable, offscreenPreRaster: $offscreenPreRaster, overScrollMode: $overScrollMode, pageZoom: $pageZoom, pluginScriptsForMainFrameOnly: $pluginScriptsForMainFrameOnly, pluginScriptsOriginAllowList: $pluginScriptsOriginAllowList, preferredContentMode: $preferredContentMode, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading, rendererPriorityPolicy: $rendererPriorityPolicy, requestedWithHeaderOriginAllowList: $requestedWithHeaderOriginAllowList, resourceCustomSchemes: $resourceCustomSchemes, safeBrowsingEnabled: $safeBrowsingEnabled, sansSerifFontFamily: $sansSerifFontFamily, saveFormData: $saveFormData, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollBarFadeDuration: $scrollBarFadeDuration, scrollBarStyle: $scrollBarStyle, scrollMultiplier: $scrollMultiplier, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollsToTop: $scrollsToTop, selectionGranularity: $selectionGranularity, serifFontFamily: $serifFontFamily, sharedCookiesEnabled: $sharedCookiesEnabled, shouldPrintBackgrounds: $shouldPrintBackgrounds, standardFontFamily: $standardFontFamily, supportMultipleWindows: $supportMultipleWindows, supportZoom: $supportZoom, suppressesIncrementalRendering: $suppressesIncrementalRendering, textZoom: $textZoom, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, transparentBackground: $transparentBackground, underPageBackgroundColor: $underPageBackgroundColor, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, useHybridComposition: $useHybridComposition, useOnDownloadStart: $useOnDownloadStart, useOnLoadResource: $useOnLoadResource, useOnNavigationResponse: $useOnNavigationResponse, useOnRenderProcessGone: $useOnRenderProcessGone, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, useShouldInterceptRequest: $useShouldInterceptRequest, useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useWideViewPort: $useWideViewPort, userAgent: $userAgent, verticalScrollBarEnabled: $verticalScrollBarEnabled, verticalScrollbarPosition: $verticalScrollbarPosition, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, webViewAssetLoader: $webViewAssetLoader}'; + return 'InAppWebViewSettings{accessibilityIgnoresInvertColors: $accessibilityIgnoresInvertColors, algorithmicDarkeningAllowed: $algorithmicDarkeningAllowed, allowBackgroundAudioPlaying: $allowBackgroundAudioPlaying, allowContentAccess: $allowContentAccess, allowFileAccess: $allowFileAccess, allowFileAccessFromFileURLs: $allowFileAccessFromFileURLs, allowUniversalAccessFromFileURLs: $allowUniversalAccessFromFileURLs, allowingReadAccessTo: $allowingReadAccessTo, allowsAirPlayForMediaPlayback: $allowsAirPlayForMediaPlayback, allowsBackForwardNavigationGestures: $allowsBackForwardNavigationGestures, allowsInlineMediaPlayback: $allowsInlineMediaPlayback, allowsLinkPreview: $allowsLinkPreview, allowsPictureInPictureMediaPlayback: $allowsPictureInPictureMediaPlayback, alwaysBounceHorizontal: $alwaysBounceHorizontal, alwaysBounceVertical: $alwaysBounceVertical, appCachePath: $appCachePath, applePayAPIEnabled: $applePayAPIEnabled, applicationNameForUserAgent: $applicationNameForUserAgent, automaticallyAdjustsScrollIndicatorInsets: $automaticallyAdjustsScrollIndicatorInsets, blockNetworkImage: $blockNetworkImage, blockNetworkLoads: $blockNetworkLoads, builtInZoomControls: $builtInZoomControls, cacheEnabled: $cacheEnabled, cacheMode: $cacheMode, contentBlockers: $contentBlockers, contentInsetAdjustmentBehavior: $contentInsetAdjustmentBehavior, cursiveFontFamily: $cursiveFontFamily, dataDetectorTypes: $dataDetectorTypes, databaseEnabled: $databaseEnabled, decelerationRate: $decelerationRate, defaultFixedFontSize: $defaultFixedFontSize, defaultFontSize: $defaultFontSize, defaultTextEncodingName: $defaultTextEncodingName, defaultVideoPoster: $defaultVideoPoster, disableContextMenu: $disableContextMenu, disableDefaultErrorPage: $disableDefaultErrorPage, disableHorizontalScroll: $disableHorizontalScroll, disableInputAccessoryView: $disableInputAccessoryView, disableLongPressContextMenuOnLinks: $disableLongPressContextMenuOnLinks, disableVerticalScroll: $disableVerticalScroll, disabledActionModeMenuItems: $disabledActionModeMenuItems, disallowOverScroll: $disallowOverScroll, displayZoomControls: $displayZoomControls, domStorageEnabled: $domStorageEnabled, enableViewportScale: $enableViewportScale, enterpriseAuthenticationAppLinkPolicyEnabled: $enterpriseAuthenticationAppLinkPolicyEnabled, fantasyFontFamily: $fantasyFontFamily, fixedFontFamily: $fixedFontFamily, geolocationEnabled: $geolocationEnabled, hardwareAcceleration: $hardwareAcceleration, horizontalScrollBarEnabled: $horizontalScrollBarEnabled, horizontalScrollbarThumbColor: $horizontalScrollbarThumbColor, horizontalScrollbarTrackColor: $horizontalScrollbarTrackColor, iframeAllow: $iframeAllow, iframeAllowFullscreen: $iframeAllowFullscreen, iframeAriaHidden: $iframeAriaHidden, iframeCsp: $iframeCsp, iframeName: $iframeName, iframeReferrerPolicy: $iframeReferrerPolicy, iframeRole: $iframeRole, iframeSandbox: $iframeSandbox, ignoresViewportScaleLimits: $ignoresViewportScaleLimits, incognito: $incognito, initialScale: $initialScale, interceptOnlyAsyncAjaxRequests: $interceptOnlyAsyncAjaxRequests, isDirectionalLockEnabled: $isDirectionalLockEnabled, isElementFullscreenEnabled: $isElementFullscreenEnabled, isFindInteractionEnabled: $isFindInteractionEnabled, isFraudulentWebsiteWarningEnabled: $isFraudulentWebsiteWarningEnabled, isInspectable: $isInspectable, isPagingEnabled: $isPagingEnabled, isSiteSpecificQuirksModeEnabled: $isSiteSpecificQuirksModeEnabled, isTextInteractionEnabled: $isTextInteractionEnabled, javaScriptBridgeEnabled: $javaScriptBridgeEnabled, javaScriptBridgeForMainFrameOnly: $javaScriptBridgeForMainFrameOnly, javaScriptBridgeOriginAllowList: $javaScriptBridgeOriginAllowList, javaScriptCanOpenWindowsAutomatically: $javaScriptCanOpenWindowsAutomatically, javaScriptEnabled: $javaScriptEnabled, javaScriptHandlersForMainFrameOnly: $javaScriptHandlersForMainFrameOnly, javaScriptHandlersOriginAllowList: $javaScriptHandlersOriginAllowList, layoutAlgorithm: $layoutAlgorithm, limitsNavigationsToAppBoundDomains: $limitsNavigationsToAppBoundDomains, loadWithOverviewMode: $loadWithOverviewMode, loadsImagesAutomatically: $loadsImagesAutomatically, maximumViewportInset: $maximumViewportInset, maximumZoomScale: $maximumZoomScale, mediaPlaybackRequiresUserGesture: $mediaPlaybackRequiresUserGesture, mediaType: $mediaType, minimumFontSize: $minimumFontSize, minimumLogicalFontSize: $minimumLogicalFontSize, minimumViewportInset: $minimumViewportInset, minimumZoomScale: $minimumZoomScale, mixedContentMode: $mixedContentMode, needInitialFocus: $needInitialFocus, networkAvailable: $networkAvailable, offscreenPreRaster: $offscreenPreRaster, overScrollMode: $overScrollMode, pageZoom: $pageZoom, pluginScriptsForMainFrameOnly: $pluginScriptsForMainFrameOnly, pluginScriptsOriginAllowList: $pluginScriptsOriginAllowList, preferredContentMode: $preferredContentMode, regexToCancelSubFramesLoading: $regexToCancelSubFramesLoading, rendererPriorityPolicy: $rendererPriorityPolicy, requestedWithHeaderOriginAllowList: $requestedWithHeaderOriginAllowList, resourceCustomSchemes: $resourceCustomSchemes, safeBrowsingEnabled: $safeBrowsingEnabled, sansSerifFontFamily: $sansSerifFontFamily, saveFormData: $saveFormData, scrollBarDefaultDelayBeforeFade: $scrollBarDefaultDelayBeforeFade, scrollBarFadeDuration: $scrollBarFadeDuration, scrollBarStyle: $scrollBarStyle, scrollMultiplier: $scrollMultiplier, scrollbarFadingEnabled: $scrollbarFadingEnabled, scrollsToTop: $scrollsToTop, selectionGranularity: $selectionGranularity, serifFontFamily: $serifFontFamily, sharedCookiesEnabled: $sharedCookiesEnabled, shouldPrintBackgrounds: $shouldPrintBackgrounds, standardFontFamily: $standardFontFamily, supportMultipleWindows: $supportMultipleWindows, supportZoom: $supportZoom, suppressesIncrementalRendering: $suppressesIncrementalRendering, textZoom: $textZoom, thirdPartyCookiesEnabled: $thirdPartyCookiesEnabled, transparentBackground: $transparentBackground, underPageBackgroundColor: $underPageBackgroundColor, upgradeKnownHostsToHTTPS: $upgradeKnownHostsToHTTPS, useHybridComposition: $useHybridComposition, useOnDownloadStart: $useOnDownloadStart, useOnLoadResource: $useOnLoadResource, useOnNavigationResponse: $useOnNavigationResponse, useOnRenderProcessGone: $useOnRenderProcessGone, useShouldInterceptAjaxRequest: $useShouldInterceptAjaxRequest, useShouldInterceptFetchRequest: $useShouldInterceptFetchRequest, useShouldInterceptRequest: $useShouldInterceptRequest, useShouldOverrideUrlLoading: $useShouldOverrideUrlLoading, useWideViewPort: $useWideViewPort, userAgent: $userAgent, verticalScrollBarEnabled: $verticalScrollBarEnabled, verticalScrollbarPosition: $verticalScrollbarPosition, verticalScrollbarThumbColor: $verticalScrollbarThumbColor, verticalScrollbarTrackColor: $verticalScrollbarTrackColor, webViewAssetLoader: $webViewAssetLoader}'; } } 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 9b19ff767..7de987d63 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 @@ -380,6 +380,10 @@ class PlatformWebViewCreationParams { /// ///[challenge] contains data about host, port, protocol, realm, etc. as specified in the [ServerTrustChallenge]. /// + ///**NOTE for iOS and macOS**: to override the certificate verification logic, you have to provide ATS (App Transport Security) exceptions in your iOS/macOS `Info.plist`. + ///See `NSAppTransportSecurity` in the [Information Property List Key Reference](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW1) + ///for details. + /// ///**Officially Supported Platforms/Implementations**: ///- Android native WebView ([Official API - WebViewClient.onReceivedSslError](https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%20android.webkit.SslErrorHandler,%20android.net.http.SslError))) ///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455638-webview)) From 99474490e73ba7e3c8fc95ff0046ed602411afbb Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Mon, 4 Nov 2024 02:23:40 +0100 Subject: [PATCH 047/137] updated plugin version to 6.2.0-beta.1 --- flutter_inappwebview/CHANGELOG.md | 14 +++++++------- flutter_inappwebview/pubspec.yaml | 14 +++++++------- flutter_inappwebview_android/CHANGELOG.md | 2 +- flutter_inappwebview_android/pubspec.yaml | 2 +- flutter_inappwebview_ios/CHANGELOG.md | 2 +- flutter_inappwebview_ios/pubspec.yaml | 2 +- flutter_inappwebview_macos/CHANGELOG.md | 2 +- flutter_inappwebview_macos/pubspec.yaml | 2 +- .../CHANGELOG.md | 2 +- .../pubspec.yaml | 2 +- flutter_inappwebview_web/CHANGELOG.md | 2 +- flutter_inappwebview_web/pubspec.yaml | 2 +- flutter_inappwebview_windows/CHANGELOG.md | 2 +- flutter_inappwebview_windows/pubspec.yaml | 2 +- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index 3f310b32a..b7970c3f0 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -1,12 +1,12 @@ -## 6.2.0 +## 6.2.0-beta.1 - Updated dependencies to the latest versions for all platform implementations: - - `flutter_inappwebview_platform_interface`: `^1.3.0` -> `^1.4.0` - - `flutter_inappwebview_android`: `^1.1.3` -> `^1.2.0` - - `flutter_inappwebview_ios`: `^1.1.2` -> `^1.2.0` - - `flutter_inappwebview_macos`: `^1.1.2` -> `^1.2.0` - - `flutter_inappwebview_web`: `^1.1.2` -> `^1.2.0` - - `flutter_inappwebview_windows`: `^0.6.0` -> `^0.7.0` + - `flutter_inappwebview_platform_interface`: `^1.3.0` -> `^1.4.0-beta.1` + - `flutter_inappwebview_android`: `^1.1.3` -> `^1.2.0-beta.1` + - `flutter_inappwebview_ios`: `^1.1.2` -> `^1.2.0-beta.1` + - `flutter_inappwebview_macos`: `^1.1.2` -> `^1.2.0-beta.1` + - `flutter_inappwebview_web`: `^1.1.2` -> `^1.2.0-beta.1` + - `flutter_inappwebview_windows`: `^0.6.0` -> `^0.7.0-beta.1` Implemented security features to better manage access to the native javascript bridge. diff --git a/flutter_inappwebview/pubspec.yaml b/flutter_inappwebview/pubspec.yaml index c58b7d424..779449baf 100755 --- a/flutter_inappwebview/pubspec.yaml +++ b/flutter_inappwebview/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview description: A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. -version: 6.2.0 +version: 6.2.0-beta.1 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -20,17 +20,17 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_platform_interface: #^1.4.0 + flutter_inappwebview_platform_interface: #^1.4.0-beta.1 path: ../flutter_inappwebview_platform_interface - flutter_inappwebview_android: #^1.2.0 + flutter_inappwebview_android: #^1.2.0-beta.1 path: ../flutter_inappwebview_android - flutter_inappwebview_ios: #^1.2.0 + flutter_inappwebview_ios: #^1.2.0-beta.1 path: ../flutter_inappwebview_ios - flutter_inappwebview_macos: #^1.2.0 + flutter_inappwebview_macos: #^1.2.0-beta.1 path: ../flutter_inappwebview_macos - flutter_inappwebview_web: #^1.2.0 + flutter_inappwebview_web: #^1.2.0-beta.1 path: ../flutter_inappwebview_web - flutter_inappwebview_windows: #^0.7.0 + flutter_inappwebview_windows: #^0.7.0-beta.1 path: ../flutter_inappwebview_windows dev_dependencies: diff --git a/flutter_inappwebview_android/CHANGELOG.md b/flutter_inappwebview_android/CHANGELOG.md index 7de8e4034..d037d7d96 100644 --- a/flutter_inappwebview_android/CHANGELOG.md +++ b/flutter_inappwebview_android/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.2.0 +## 1.2.0-beta.1 - Updated flutter_inappwebview_platform_interface version to ^1.4.0 - Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method diff --git a/flutter_inappwebview_android/pubspec.yaml b/flutter_inappwebview_android/pubspec.yaml index 83dba2a37..dce9f49c6 100644 --- a/flutter_inappwebview_android/pubspec.yaml +++ b/flutter_inappwebview_android/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_android description: Android implementation of the flutter_inappwebview plugin. -version: 1.2.0 +version: 1.2.0-beta.1 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_android issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues diff --git a/flutter_inappwebview_ios/CHANGELOG.md b/flutter_inappwebview_ios/CHANGELOG.md index 19f2ef2eb..1041fe279 100644 --- a/flutter_inappwebview_ios/CHANGELOG.md +++ b/flutter_inappwebview_ios/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.2.0 +## 1.2.0-beta.1 - Updated flutter_inappwebview_platform_interface version to ^1.4.0 - Updated ConsoleLogJS internal PluginScript to main-frame only as using it on non-main frames could cause issues such as [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) diff --git a/flutter_inappwebview_ios/pubspec.yaml b/flutter_inappwebview_ios/pubspec.yaml index cc3fafee9..a377bea3b 100644 --- a/flutter_inappwebview_ios/pubspec.yaml +++ b/flutter_inappwebview_ios/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_ios description: iOS implementation of the flutter_inappwebview plugin. -version: 1.2.0 +version: 1.2.0-beta.1 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_ios issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues diff --git a/flutter_inappwebview_macos/CHANGELOG.md b/flutter_inappwebview_macos/CHANGELOG.md index 40f1114ac..a07283b49 100644 --- a/flutter_inappwebview_macos/CHANGELOG.md +++ b/flutter_inappwebview_macos/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.2.0 +## 1.2.0-beta.1 - Updated flutter_inappwebview_platform_interface version to ^1.4.0 - Updated ConsoleLogJS internal PluginScript to main-frame only as using it on non-main frames could cause issues such as [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) diff --git a/flutter_inappwebview_macos/pubspec.yaml b/flutter_inappwebview_macos/pubspec.yaml index 402274ead..b10ee0962 100644 --- a/flutter_inappwebview_macos/pubspec.yaml +++ b/flutter_inappwebview_macos/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_macos description: macOS implementation of the flutter_inappwebview plugin. -version: 1.2.0 +version: 1.2.0-beta.1 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_macos issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues diff --git a/flutter_inappwebview_platform_interface/CHANGELOG.md b/flutter_inappwebview_platform_interface/CHANGELOG.md index ed56cf1ee..4e13231ae 100644 --- a/flutter_inappwebview_platform_interface/CHANGELOG.md +++ b/flutter_inappwebview_platform_interface/CHANGELOG.md @@ -1,4 +1,4 @@ -#### 1.4.0 +#### 1.4.0-beta.1 - Updated static `fromMap` implementation for some classes - Updated `kJavaScriptHandlerForbiddenNames` list diff --git a/flutter_inappwebview_platform_interface/pubspec.yaml b/flutter_inappwebview_platform_interface/pubspec.yaml index 78131c8e7..b75eef581 100644 --- a/flutter_inappwebview_platform_interface/pubspec.yaml +++ b/flutter_inappwebview_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_platform_interface description: A common platform interface for the flutter_inappwebview plugin. -version: 1.4.0 +version: 1.4.0-beta.1 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_platform_interface issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues diff --git a/flutter_inappwebview_web/CHANGELOG.md b/flutter_inappwebview_web/CHANGELOG.md index 01f42810f..7c32ecf94 100644 --- a/flutter_inappwebview_web/CHANGELOG.md +++ b/flutter_inappwebview_web/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.2.0 +## 1.2.0-beta.1 - Updated flutter_inappwebview_platform_interface version to ^1.4.0 - Merged "[web] support iframe role and aria-hidden attributes" [2293](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2293) (thanks to [p-mazhnik](https://github.com/p-mazhnik)) diff --git a/flutter_inappwebview_web/pubspec.yaml b/flutter_inappwebview_web/pubspec.yaml index 193a6c152..70ab4dcf4 100644 --- a/flutter_inappwebview_web/pubspec.yaml +++ b/flutter_inappwebview_web/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_web description: Web implementation of the flutter_inappwebview plugin. -version: 1.2.0 +version: 1.2.0-beta.1 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_web issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues diff --git a/flutter_inappwebview_windows/CHANGELOG.md b/flutter_inappwebview_windows/CHANGELOG.md index 67fe54c6f..d4e1e2d18 100644 --- a/flutter_inappwebview_windows/CHANGELOG.md +++ b/flutter_inappwebview_windows/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.7.0 +## 0.7.0-beta.1 - Updated flutter_inappwebview_platform_interface version to ^1.4.0 - Updated `scrollMultiplier` default value from 6 to 1 diff --git a/flutter_inappwebview_windows/pubspec.yaml b/flutter_inappwebview_windows/pubspec.yaml index 5210d5bc4..51bed48fb 100644 --- a/flutter_inappwebview_windows/pubspec.yaml +++ b/flutter_inappwebview_windows/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_windows description: Windows implementation of the flutter_inappwebview plugin. -version: 0.7.0 +version: 0.7.0-beta.1 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_windows issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues From f8b94d8b5b964a71ab5c20e332e13c1758d9fc54 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:04:17 +0000 Subject: [PATCH 048/137] update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ddfc4b01..77e836e7c 100755 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-88-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-89-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -196,6 +196,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Murmurl912
Murmurl912

đź’» Benjamin Schulz
Benjamin Schulz

🤔 seal-app
seal-app

đź’» + Takuya Tominaga
Takuya Tominaga

đź’» From 593ebc6e2a1bb2145bd61cfeb41ac5822fc79b1b Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:04:18 +0000 Subject: [PATCH 049/137] update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index b62b3eaa3..b461deb99 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -802,6 +802,15 @@ "contributions": [ "code" ] + }, + { + "login": "takuyaaaaaaahaaaaaa", + "name": "Takuya Tominaga", + "avatar_url": "https://avatars.githubusercontent.com/u/31458194?v=4", + "profile": "https://github.com/takuyaaaaaaahaaaaaa", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, From f0fcd6e821e74e95a74b6ab7b2c5d91e342ffb50 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Mon, 4 Nov 2024 10:14:13 +0100 Subject: [PATCH 050/137] ios, macos: updated _getCookieExpirationDate method format in case of falling back to use js --- flutter_inappwebview/CHANGELOG.md | 1 + flutter_inappwebview/README.md | 3 ++- flutter_inappwebview_android/CHANGELOG.md | 1 + flutter_inappwebview_ios/ios/Classes/PlatformUtil.swift | 1 + flutter_inappwebview_ios/lib/src/cookie_manager.dart | 8 +++----- flutter_inappwebview_macos/lib/src/cookie_manager.dart | 8 +++----- .../macos/Classes/PlatformUtil.swift | 1 + 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index b7970c3f0..0adc91e0a 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -32,6 +32,7 @@ Implemented security features to better manage access to the native javascript b - Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) - Fixed crash when trying to open InAppBrowser with R.menu.menu_main on release mode - Merged "Prevent blank InAppBrowser Activity from being restored" [#1984](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1984) (thanks to [ShuheiSuzuki-07](https://github.com/ShuheiSuzuki-07)) +- Merged "Update Android Cookie Expiration date format to 24-hour format (HH)" [#2389](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2389) (thanks to [takuyaaaaaaahaaaaaa](https://github.com/takuyaaaaaaahaaaaaa)) #### macOS and iOS Platforms - Updated ConsoleLogJS internal PluginScript to main-frame only as using it on non-main frames could cause issues such as [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) diff --git a/flutter_inappwebview/README.md b/flutter_inappwebview/README.md index 413b1099f..5ddfc4b01 100755 --- a/flutter_inappwebview/README.md +++ b/flutter_inappwebview/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-87-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-88-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -195,6 +195,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d nlog (solrin)
nlog (solrin)

đź’» Murmurl912
Murmurl912

đź’» Benjamin Schulz
Benjamin Schulz

🤔 + seal-app
seal-app

đź’» diff --git a/flutter_inappwebview_android/CHANGELOG.md b/flutter_inappwebview_android/CHANGELOG.md index d037d7d96..f5d4e25aa 100644 --- a/flutter_inappwebview_android/CHANGELOG.md +++ b/flutter_inappwebview_android/CHANGELOG.md @@ -9,6 +9,7 @@ - Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) - Fixed crash when trying to open InAppBrowser with R.menu.menu_main on release mode - Merged "Prevent blank InAppBrowser Activity from being restored" [#1984](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1984) (thanks to [ShuheiSuzuki-07](https://github.com/ShuheiSuzuki-07)) +- Merged "Update Android Cookie Expiration date format to 24-hour format (HH)" [#2389](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2389) (thanks to [takuyaaaaaaahaaaaaa](https://github.com/takuyaaaaaaahaaaaaa)) ## 1.1.3 diff --git a/flutter_inappwebview_ios/ios/Classes/PlatformUtil.swift b/flutter_inappwebview_ios/ios/Classes/PlatformUtil.swift index a49d5316d..a44fabc0e 100644 --- a/flutter_inappwebview_ios/ios/Classes/PlatformUtil.swift +++ b/flutter_inappwebview_ios/ios/Classes/PlatformUtil.swift @@ -50,6 +50,7 @@ public class PlatformUtil: ChannelDelegate { static public func formatDate(date: Int64, format: String, locale: Locale, timezone: TimeZone) -> String { let formatter = DateFormatter() + formatter.locale = locale formatter.dateFormat = format formatter.timeZone = timezone return formatter.string(from: PlatformUtil.getDateFromMilliseconds(date: date)) diff --git a/flutter_inappwebview_ios/lib/src/cookie_manager.dart b/flutter_inappwebview_ios/lib/src/cookie_manager.dart index e640c9f02..b2272f38c 100755 --- a/flutter_inappwebview_ios/lib/src/cookie_manager.dart +++ b/flutter_inappwebview_ios/lib/src/cookie_manager.dart @@ -407,13 +407,11 @@ class IOSCookieManager extends PlatformCookieManager with ChannelController { Future _getCookieExpirationDate(int expiresDate) async { var platformUtil = PlatformUtil.instance(); var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc(); - return !kIsWeb - ? await platformUtil.formatDate( + return await platformUtil.formatDate( date: dateTime, - format: 'EEE, dd MMM yyyy hh:mm:ss z', + format: 'EEE, dd MMM yyyy HH:mm:ss z', locale: 'en_US', - timezone: 'GMT') - : await platformUtil.getWebCookieExpirationDate(date: dateTime); + timezone: 'GMT'); } Future _shouldUseJavascript() async { diff --git a/flutter_inappwebview_macos/lib/src/cookie_manager.dart b/flutter_inappwebview_macos/lib/src/cookie_manager.dart index bf9d5a9bc..dba8e6088 100755 --- a/flutter_inappwebview_macos/lib/src/cookie_manager.dart +++ b/flutter_inappwebview_macos/lib/src/cookie_manager.dart @@ -407,13 +407,11 @@ class MacOSCookieManager extends PlatformCookieManager with ChannelController { Future _getCookieExpirationDate(int expiresDate) async { var platformUtil = PlatformUtil.instance(); var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc(); - return !kIsWeb - ? await platformUtil.formatDate( + return await platformUtil.formatDate( date: dateTime, - format: 'EEE, dd MMM yyyy hh:mm:ss z', + format: 'EEE, dd MMM yyyy HH:mm:ss z', locale: 'en_US', - timezone: 'GMT') - : await platformUtil.getWebCookieExpirationDate(date: dateTime); + timezone: 'GMT'); } Future _shouldUseJavascript() async { diff --git a/flutter_inappwebview_macos/macos/Classes/PlatformUtil.swift b/flutter_inappwebview_macos/macos/Classes/PlatformUtil.swift index c9859d7d8..a349a908f 100644 --- a/flutter_inappwebview_macos/macos/Classes/PlatformUtil.swift +++ b/flutter_inappwebview_macos/macos/Classes/PlatformUtil.swift @@ -51,6 +51,7 @@ public class PlatformUtil: ChannelDelegate { static public func formatDate(date: Int64, format: String, locale: Locale, timezone: TimeZone) -> String { let formatter = DateFormatter() + formatter.locale = locale formatter.dateFormat = format formatter.timeZone = timezone return formatter.string(from: PlatformUtil.getDateFromMilliseconds(date: date)) From 91da20808b523a51c66ac3f1c04088875748547c Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Mon, 4 Nov 2024 10:16:30 +0100 Subject: [PATCH 051/137] updated readme --- flutter_inappwebview/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flutter_inappwebview/README.md b/flutter_inappwebview/README.md index 5ddfc4b01..77e836e7c 100755 --- a/flutter_inappwebview/README.md +++ b/flutter_inappwebview/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-88-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-89-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -196,6 +196,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Murmurl912
Murmurl912

đź’» Benjamin Schulz
Benjamin Schulz

🤔 seal-app
seal-app

đź’» + Takuya Tominaga
Takuya Tominaga

đź’» From c4b4c23745aaa324bee3098339909837bc26e96b Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:22:56 +0000 Subject: [PATCH 052/137] update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 77e836e7c..2c2325d28 100755 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-89-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-90-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -197,6 +197,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Benjamin Schulz
Benjamin Schulz

🤔 seal-app
seal-app

đź’» Takuya Tominaga
Takuya Tominaga

đź’» + Sergey
Sergey

đź’» From d43e33977606086b3ec7582b14e2d45d4022cb12 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:22:57 +0000 Subject: [PATCH 053/137] update .all-contributorsrc --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index b461deb99..00748cac3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -811,6 +811,15 @@ "contributions": [ "code" ] + }, + { + "login": "yamaha252", + "name": "Sergey", + "avatar_url": "https://avatars.githubusercontent.com/u/4444068?v=4", + "profile": "https://github.com/yamaha252", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, From bd5960d515c2aad1b1401a1e646f7d1ff1bc8fe0 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Mon, 4 Nov 2024 10:23:47 +0100 Subject: [PATCH 054/137] updated readme --- flutter_inappwebview/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flutter_inappwebview/README.md b/flutter_inappwebview/README.md index 77e836e7c..2c2325d28 100755 --- a/flutter_inappwebview/README.md +++ b/flutter_inappwebview/README.md @@ -5,7 +5,7 @@ ![InAppWebView-logo](https://user-images.githubusercontent.com/5956938/195422744-bdcfed16-73f0-4bc9-94ab-ecf10771a1c4.png) -[![All Contributors](https://img.shields.io/badge/all_contributors-89-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-90-orange.svg?style=flat-square)](#contributors-) [![flutter_inappwebview version](https://img.shields.io/pub/v/flutter_inappwebview?include_prereleases)](https://pub.dartlang.org/packages/flutter_inappwebview) @@ -197,6 +197,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Benjamin Schulz
Benjamin Schulz

🤔 seal-app
seal-app

đź’» Takuya Tominaga
Takuya Tominaga

đź’» + Sergey
Sergey

💻 From a2736353449fa67dba17c89223ae65810a681eee Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Mon, 4 Nov 2024 17:32:01 +0100 Subject: [PATCH 055/137] updated requestFocus implementation, macos: implemented requestFocus and clearFocus WebView methods, implemented workaround for macos #2380 --- flutter_inappwebview/CHANGELOG.md | 5 + .../lib/in_app_webiew_example.screen.dart | 3 +- .../in_app_webview_controller.dart | 12 +- flutter_inappwebview_android/CHANGELOG.md | 1 + .../types/InAppWebViewRect.java | 107 +++++++++++++++ .../webview/WebViewChannelDelegate.java | 17 ++- .../in_app_webview_controller.dart | 8 +- flutter_inappwebview_ios/CHANGELOG.md | 1 + .../Classes/InAppWebView/InAppWebView.swift | 8 +- .../InAppWebView/WebViewChannelDelegate.swift | 6 +- .../in_app_webview_controller.dart | 8 +- flutter_inappwebview_macos/CHANGELOG.md | 2 + .../src/in_app_webview/in_app_webview.dart | 2 +- .../in_app_webview_controller.dart | 24 ++++ .../Classes/InAppWebView/InAppWebView.swift | 44 ++++++ .../InAppWebView/WebViewChannelDelegate.swift | 16 +++ .../WebViewChannelDelegateMethods.swift | 2 + .../platform_inappwebview_controller.dart | 20 ++- .../lib/src/types/focus_direction.dart | 54 ++++++++ .../lib/src/types/focus_direction.g.dart | 125 ++++++++++++++++++ .../lib/src/types/main.dart | 1 + 21 files changed, 443 insertions(+), 23 deletions(-) create mode 100644 flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppWebViewRect.java create mode 100644 flutter_inappwebview_platform_interface/lib/src/types/focus_direction.dart create mode 100644 flutter_inappwebview_platform_interface/lib/src/types/focus_direction.g.dart diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index 0adc91e0a..8eb2eff6c 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -16,6 +16,7 @@ Implemented security features to better manage access to the native javascript b - Added `PlatformInAppLocalhostServer.onData` parameter to set a custom on data server callback - Added `javaScriptBridgeEnabled`, `javaScriptBridgeOriginAllowList`, `javaScriptBridgeForMainFrameOnly`, `pluginScriptsOriginAllowList`, `pluginScriptsForMainFrameOnly`, `javaScriptHandlersOriginAllowList`, `javaScriptHandlersForMainFrameOnly`, `scrollMultiplier` InAppWebViewSettings parameters - Added `setJavaScriptBridgeName`, `getJavaScriptBridgeName` static WebView controller methods +- Added `requestFocus` WebView method - Added `onProcessFailed` WebView event - Added `JavaScriptHandlerFunctionData` type - Deprecated `JavaScriptHandlerCallback` type in favor of `JavaScriptHandlerFunction` type @@ -27,6 +28,7 @@ Implemented security features to better manage access to the native javascript b - Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method - Added `CookieManager.flush` method - Added support for `UserScript.forMainFrameOnly` parameter +- Implemented `requestFocus` WebView method - Updated UserScript at document end implementation - Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called - Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) @@ -35,10 +37,13 @@ Implemented security features to better manage access to the native javascript b - Merged "Update Android Cookie Expiration date format to 24-hour format (HH)" [#2389](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2389) (thanks to [takuyaaaaaaahaaaaaa](https://github.com/takuyaaaaaaahaaaaaa)) #### macOS and iOS Platforms +- Implemented `requestFocus` WebView method - Updated ConsoleLogJS internal PluginScript to main-frame only as using it on non-main frames could cause issues such as [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error - Added support for `UserScript.allowedOriginRules` parameter - Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) +- macOS: Implemented also `clearFocus` WebView method +- macOS: Implemented workaround for "[macOS] Copy Shortcut does not work if TextField outside of WebView has focus" [#2380](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2380) #### Windows Platform - Updated `scrollMultiplier` default value from 6 to 1 diff --git a/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart b/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart index 0a53f086c..82d17b658 100755 --- a/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart +++ b/flutter_inappwebview/example/lib/in_app_webiew_example.screen.dart @@ -1,4 +1,5 @@ import 'dart:collection'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; @@ -116,7 +117,7 @@ class _InAppWebViewExampleScreenState extends State { key: webViewKey, webViewEnvironment: webViewEnvironment, initialUrlRequest: - URLRequest(url: WebUri('https://flutter.dev')), + URLRequest(url: WebUri('https://flutter.dev')), // initialUrlRequest: // URLRequest(url: WebUri(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')), // initialFile: "assets/index.html", diff --git a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart index 0920b9685..72e9dab13 100644 --- a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview_controller.dart @@ -1,18 +1,14 @@ import 'dart:core'; -import 'dart:typed_data'; -import 'dart:ui'; -import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; +import '../print_job/main.dart'; import '../web_message/main.dart'; import '../web_storage/web_storage.dart'; import 'android/in_app_webview_controller.dart'; import 'apple/in_app_webview_controller.dart'; -import '../print_job/main.dart'; - ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController} class InAppWebViewController { ///Use [InAppWebViewController] instead. @@ -289,7 +285,11 @@ class InAppWebViewController { platform.getHitTestResult(); ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestFocus} - Future requestFocus() => platform.requestFocus(); + Future requestFocus( + {FocusDirection? direction, + InAppWebViewRect? previouslyFocusedRect}) => + platform.requestFocus( + direction: direction, previouslyFocusedRect: previouslyFocusedRect); ///{@macro flutter_inappwebview_platform_interface.PlatformInAppWebViewController.clearFocus} Future clearFocus() => platform.clearFocus(); diff --git a/flutter_inappwebview_android/CHANGELOG.md b/flutter_inappwebview_android/CHANGELOG.md index f5d4e25aa..23e8baffd 100644 --- a/flutter_inappwebview_android/CHANGELOG.md +++ b/flutter_inappwebview_android/CHANGELOG.md @@ -4,6 +4,7 @@ - Added `InAppWebViewController.enableSlowWholeDocumentDraw` static method - Added `CookieManager.flush` method - Added support for `UserScript.forMainFrameOnly` parameter +- Implemented `requestFocus` WebView method - Updated UserScript at document end implementation - Updated `InAppWebViewController.takeScreenshot` implementation to support screenshot out of visible viewport when `InAppWebViewController.enableSlowWholeDocumentDraw` is called - Fixed "After dispose a InAppWebViewKeepAlive using InAppWebViewController.disposeKeepAlive. NullPointerException is thrown when main activity enter destroyed state." [#2025](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2025) diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppWebViewRect.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppWebViewRect.java new file mode 100644 index 000000000..b297899ff --- /dev/null +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/InAppWebViewRect.java @@ -0,0 +1,107 @@ +package com.pichillilorenzo.flutter_inappwebview_android.types; + +import android.graphics.Rect; + +import androidx.annotation.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class InAppWebViewRect { + private double height; + private double width; + private double x; + private double y; + + public InAppWebViewRect(double height, double width, double x, double y) { + this.height = height; + this.width = width; + this.x = x; + this.y = y; + } + + @Nullable + public static InAppWebViewRect fromMap(@Nullable Map map) { + if (map == null) { + return null; + } + double height = (double) map.get("height"); + double width = (double) map.get("width"); + double x = (double) map.get("x"); + double y = (double) map.get("y"); + return new InAppWebViewRect(height, width, x, y); + } + + public Map toMap() { + Map map = new HashMap<>(); + map.put("height", height); + map.put("width", width); + map.put("x", x); + map.put("y", y); + return map; + } + + public Rect toRect() { + return new Rect((int) x, (int) y, (int) (x + width), (int) (y + height)); + } + + public double getHeight() { + return height; + } + + public void setHeight(double height) { + this.height = height; + } + + public double getWidth() { + return width; + } + + public void setWidth(double width) { + this.width = width; + } + + public double getX() { + return x; + } + + public void setX(double x) { + this.x = x; + } + + public double getY() { + return y; + } + + public void setY(double y) { + this.y = y; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + InAppWebViewRect that = (InAppWebViewRect) o; + return Double.compare(height, that.height) == 0 && Double.compare(width, that.width) == 0 && Double.compare(x, that.x) == 0 && Double.compare(y, that.y) == 0; + } + + @Override + public int hashCode() { + int result = Double.hashCode(height); + result = 31 * result + Double.hashCode(width); + result = 31 * result + Double.hashCode(x); + result = 31 * result + Double.hashCode(y); + return result; + } + + @Override + public String toString() { + return "InAppWebViewRect{" + + "height=" + height + + ", width=" + width + + ", x=" + x + + ", y=" + y + + '}'; + } +} diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java index e4b12a976..e8e64a166 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/webview/WebViewChannelDelegate.java @@ -1,5 +1,6 @@ package com.pichillilorenzo.flutter_inappwebview_android.webview; +import android.graphics.Rect; import android.net.Uri; import android.os.Build; import android.webkit.ValueCallback; @@ -29,6 +30,7 @@ import com.pichillilorenzo.flutter_inappwebview_android.types.HitTestResult; import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthResponse; import com.pichillilorenzo.flutter_inappwebview_android.types.HttpAuthenticationChallenge; +import com.pichillilorenzo.flutter_inappwebview_android.types.InAppWebViewRect; import com.pichillilorenzo.flutter_inappwebview_android.types.JavaScriptHandlerFunctionData; import com.pichillilorenzo.flutter_inappwebview_android.types.JsAlertResponse; import com.pichillilorenzo.flutter_inappwebview_android.types.JsBeforeUnloadResponse; @@ -477,9 +479,20 @@ public void onReceiveValue(String value) { break; case requestFocus: if (webView != null) { - webView.requestFocus(); + boolean resultValue = false; + Integer direction = (Integer) call.argument("direction"); + InAppWebViewRect previouslyFocusedRect = InAppWebViewRect.fromMap((Map) call.argument("previouslyFocusedRect")); + if (direction != null && previouslyFocusedRect != null) { + resultValue = webView.requestFocus(direction, previouslyFocusedRect.toRect()); + } else if (direction != null) { + resultValue = webView.requestFocus(direction); + } else { + resultValue = webView.requestFocus(); + } + result.success(resultValue); + } else { + result.success(false); } - result.success(true); break; case setContextMenu: if (webView != null) { diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart index c9cbc155c..4e3794b53 100644 --- a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart @@ -2240,9 +2240,13 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController } @override - Future requestFocus() async { + Future requestFocus( + {FocusDirection? direction, + InAppWebViewRect? previouslyFocusedRect}) async { Map args = {}; - return await channel?.invokeMethod('requestFocus', args); + args.putIfAbsent("direction", () => direction?.toNativeValue()); + args.putIfAbsent("previouslyFocusedRect", () => previouslyFocusedRect?.toMap()); + return await channel?.invokeMethod('requestFocus', args); } @override diff --git a/flutter_inappwebview_ios/CHANGELOG.md b/flutter_inappwebview_ios/CHANGELOG.md index 1041fe279..2c52d0bf4 100644 --- a/flutter_inappwebview_ios/CHANGELOG.md +++ b/flutter_inappwebview_ios/CHANGELOG.md @@ -1,6 +1,7 @@ ## 1.2.0-beta.1 - Updated flutter_inappwebview_platform_interface version to ^1.4.0 +- Implemented `requestFocus` WebView method - Updated ConsoleLogJS internal PluginScript to main-frame only as using it on non-main frames could cause issues such as [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) - Added support for `UserScript.allowedOriginRules` parameter - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error diff --git a/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift b/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift index 98862b282..3a9d3ca8d 100755 --- a/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppWebView/InAppWebView.swift @@ -3259,12 +3259,12 @@ if(window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)] } } - public func clearFocus() { - self.scrollView.subviews.first?.resignFirstResponder() + public func clearFocus() -> Bool { + return self.scrollView.subviews.first?.resignFirstResponder() ?? false } - public func requestFocus() { - self.scrollView.subviews.first?.becomeFirstResponder() + public func requestFocus() -> Bool { + return self.scrollView.subviews.first?.becomeFirstResponder() ?? false } public func getCertificate() -> SslCertificate? { diff --git a/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift b/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift index 0e8c19670..b0d88ebcc 100644 --- a/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -345,12 +345,10 @@ public class WebViewChannelDelegate: ChannelDelegate { } break case .clearFocus: - webView?.clearFocus() - result(true) + result(webView?.clearFocus()) break case .requestFocus: - webView?.requestFocus() - result(true) + result(webView?.requestFocus()) break case .setContextMenu: if let webView = webView { diff --git a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart index d37e14602..7fe686162 100644 --- a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart @@ -2233,9 +2233,13 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController } @override - Future requestFocus() async { + Future requestFocus( + {FocusDirection? direction, + InAppWebViewRect? previouslyFocusedRect}) async { Map args = {}; - return await channel?.invokeMethod('requestFocus', args); + args.putIfAbsent("direction", () => direction?.toNativeValue()); + args.putIfAbsent("previouslyFocusedRect", () => previouslyFocusedRect?.toMap()); + return await channel?.invokeMethod('requestFocus', args); } @override diff --git a/flutter_inappwebview_macos/CHANGELOG.md b/flutter_inappwebview_macos/CHANGELOG.md index a07283b49..b245ed568 100644 --- a/flutter_inappwebview_macos/CHANGELOG.md +++ b/flutter_inappwebview_macos/CHANGELOG.md @@ -1,10 +1,12 @@ ## 1.2.0-beta.1 - Updated flutter_inappwebview_platform_interface version to ^1.4.0 +- Implemented `requestFocus`, `clearFocus` WebView methods - Updated ConsoleLogJS internal PluginScript to main-frame only as using it on non-main frames could cause issues such as [#1738](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1738) - Added support for `UserScript.allowedOriginRules` parameter - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error - Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) +- Implemented workaround for "[macOS] Copy Shortcut does not work if TextField outside of WebView has focus" [#2380](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2380) ## 1.1.2 diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart index f2800a949..0d0499c69 100755 --- a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart +++ b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'headless_in_app_webview.dart'; import '../find_interaction/find_interaction_controller.dart'; +import 'headless_in_app_webview.dart'; import 'in_app_webview_controller.dart'; /// Object specifying creation parameters for creating a [PlatformInAppWebViewWidget]. diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart index ec7cd242a..add535e8a 100644 --- a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart @@ -6,6 +6,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; import '../in_app_browser/in_app_browser.dart'; @@ -188,6 +189,13 @@ class MacOSInAppWebViewController extends PlatformInAppWebViewController } Future _handleMethod(MethodCall call) async { + if (call.method == "_onMouseDown") { + // Workaround for https://github.com/pichillilorenzo/flutter_inappwebview/issues/2380 + // TODO: remove when Flutter fixes this + FocusManager.instance.primaryFocus?.unfocus(); + return; + } + if (PlatformInAppWebViewController.debugLoggingSettings.enabled && call.method != "onCallJsHandler") { _debugLog(call.method, call.arguments); @@ -2202,6 +2210,22 @@ class MacOSInAppWebViewController extends PlatformInAppWebViewController return await channel?.invokeMethod('getSelectedText', args); } + @override + Future requestFocus( + {FocusDirection? direction, + InAppWebViewRect? previouslyFocusedRect}) async { + Map args = {}; + args.putIfAbsent("direction", () => direction?.toNativeValue()); + args.putIfAbsent("previouslyFocusedRect", () => previouslyFocusedRect?.toMap()); + return await channel?.invokeMethod('requestFocus', args); + } + + @override + Future clearFocus() async { + Map args = {}; + return await channel?.invokeMethod('clearFocus', args); + } + @override Future> getMetaTags() async { List metaTags = []; diff --git a/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift index ce7f505f4..18c493cca 100755 --- a/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift +++ b/flutter_inappwebview_macos/macos/Classes/InAppWebView/InAppWebView.swift @@ -53,6 +53,8 @@ public class InAppWebView: WKWebView, WKUIDelegate, private var exceptedBridgeSecret = NSUUID().uuidString private var javaScriptBridgeEnabled = true + public override var acceptsFirstResponder: Bool { return true } + init(id: Any?, plugin: InAppWebViewFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration, userScripts: [UserScript] = []) { super.init(frame: frame, configuration: configuration) @@ -2604,6 +2606,48 @@ if(window.\(JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME())[\(_callHandlerID)] } } + public func clearFocus() -> Bool { + return (self.superview?.window ?? self.window)?.makeFirstResponder(nil) ?? false + } + + public func requestFocus() -> Bool { + return (self.superview?.window ?? self.window)?.makeFirstResponder(self) ?? false + } + + // Workaround for https://github.com/pichillilorenzo/flutter_inappwebview/issues/2380 + // TODO: remove when Flutter fixes this + private var _isFirstResponder = true + override open func becomeFirstResponder() -> Bool { + _isFirstResponder = true + return super.becomeFirstResponder() + } + private func _fixFocus(callback: @escaping () -> Void) { + if _isFirstResponder, let channelDelegate = channelDelegate { + _isFirstResponder = false + channelDelegate._onMouseDown(callback: { [weak self] in + let _ = self?.requestFocus() + callback() + }) + } else { + callback() + } + } + override public func mouseDown(with event: NSEvent) { + _fixFocus { + super.mouseDown(with: event) + } + } + override public func rightMouseDown(with event: NSEvent) { + _fixFocus { + super.rightMouseDown(with: event) + } + } + override public func otherMouseDown(with event: NSEvent) { + _fixFocus { + super.otherMouseDown(with: event) + } + } + public func getCertificate() -> SslCertificate? { guard let scheme = url?.scheme, scheme == "https", diff --git a/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift index 671083388..cd8a5358a 100644 --- a/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -370,6 +370,12 @@ public class WebViewChannelDelegate: ChannelDelegate { result(nil) } break + case .clearFocus: + result(webView?.clearFocus()) + break + case .requestFocus: + result(webView?.requestFocus()) + break case .getCertificate: result(webView?.getCertificate()?.toMap()) break @@ -1166,6 +1172,16 @@ public class WebViewChannelDelegate: ChannelDelegate { channel?.invokeMethod("onPrintRequest", arguments: arguments, callback: callback) } + internal func _onMouseDown(callback: @escaping () -> Void) { + if channel == nil { + return + } + let arguments: [String:Any] = [:]; + channel?.invokeMethod("_onMouseDown", arguments: arguments) {(result) -> Void in + callback() + } + } + public override func dispose() { super.dispose() webView = nil diff --git a/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegateMethods.swift b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegateMethods.swift index 4810bae3b..8dac64e48 100644 --- a/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegateMethods.swift +++ b/flutter_inappwebview_macos/macos/Classes/InAppWebView/WebViewChannelDelegateMethods.swift @@ -58,6 +58,8 @@ public enum WebViewChannelDelegateMethods: String { case getSelectedText = "getSelectedText" case getScrollX = "getScrollX" case getScrollY = "getScrollY" + case clearFocus = "clearFocus" + case requestFocus = "requestFocus" case getCertificate = "getCertificate" case addUserScript = "addUserScript" case removeUserScript = "removeUserScript" 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 43aa98baf..6a7502052 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 @@ -1071,7 +1071,24 @@ abstract class PlatformInAppWebViewController extends PlatformInterface 'getHitTestResult is not implemented on the current platform'); } - Future requestFocus() { + ///{@template flutter_inappwebview_platform_interface.PlatformInAppWebViewController.requestFocus} + ///Call this method when you want to try the WebView to be the first responder. + /// + ///On Android, call this to try to give focus to the WebView and + ///give it hints about the [direction] and a specific [previouslyFocusedRect] that the focus is coming from. + ///The [previouslyFocusedRect] can help give larger views a finer grained hint about where focus is coming from, + ///and therefore, where to show selection, or forward focus change internally. + /// + ///Returns `true` whether this WebView actually took focus; otherwise, `false`. + /// + ///**NOTE**: [direction] and [previouslyFocusedRect] are available only on Android. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - WebView.requestFocus](https://developer.android.com/reference/android/webkit/WebView#requestFocus(int,%20android.graphics.Rect))) + ///- iOS ([Official API - UIResponder.becomeFirstResponder](https://developer.apple.com/documentation/uikit/uiresponder/1621113-becomefirstresponder)) + ///- MacOS ([Official API - NSWindow.makeFirstResponder](https://developer.apple.com/documentation/appkit/nswindow/1419366-makefirstresponder)) + ///{@endtemplate} + Future requestFocus({FocusDirection? direction, InAppWebViewRect? previouslyFocusedRect}) { throw UnimplementedError( 'requestFocus is not implemented on the current platform'); } @@ -1082,6 +1099,7 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///**Officially Supported Platforms/Implementations**: ///- Android native WebView ([Official API - ViewGroup.clearFocus](https://developer.android.com/reference/android/view/ViewGroup#clearFocus())) ///- iOS ([Official API - UIResponder.resignFirstResponder](https://developer.apple.com/documentation/uikit/uiresponder/1621097-resignfirstresponder)) + ///- MacOS ([Official API - NSWindow.makeFirstResponder](https://developer.apple.com/documentation/appkit/nswindow/1419366-makefirstresponder)) ///{@endtemplate} Future clearFocus() { throw UnimplementedError( diff --git a/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.dart b/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.dart new file mode 100644 index 000000000..c3f593b8b --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.dart @@ -0,0 +1,54 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'focus_direction.g.dart'; + +///Class used to indicate the force dark mode. +@ExchangeableEnum() +class FocusDirection_ { + // ignore: unused_field + final String _value; + // ignore: unused_field + final dynamic _nativeValue = null; + const FocusDirection_._internal(this._value); + + ///Move focus up. + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform( + apiName: 'FOCUS_UP', + apiUrl: 'https://developer.android.com/reference/android/view/View#FOCUS_UP', + value: 33 + ), + ]) + static const UP = const FocusDirection_._internal('UP'); + + ///Move focus down. + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform( + apiName: 'FOCUS_DOWN', + apiUrl: 'https://developer.android.com/reference/android/view/View#FOCUS_DOWN', + value: 130 + ), + ]) + static const DOWN = const FocusDirection_._internal('DOWN'); + + ///Move focus to the left. + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform( + apiName: 'FOCUS_LEFT', + apiUrl: 'https://developer.android.com/reference/android/view/View#FOCUS_LEFT', + value: 130 + ), + ]) + static const LEFT = const FocusDirection_._internal('LEFT'); + + ///Move focus to the right. + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform( + apiName: 'FOCUS_RIGHT', + apiUrl: 'https://developer.android.com/reference/android/view/View#FOCUS_RIGHT', + value: 130 + ), + ]) + static const RIGHT = const FocusDirection_._internal('RIGHT'); +} \ No newline at end of file diff --git a/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.g.dart new file mode 100644 index 000000000..76684e551 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.g.dart @@ -0,0 +1,125 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'focus_direction.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Class used to indicate the force dark mode. +class FocusDirection { + final String _value; + final dynamic _nativeValue; + const FocusDirection._internal(this._value, this._nativeValue); +// ignore: unused_element + factory FocusDirection._internalMultiPlatform( + String value, Function nativeValue) => + FocusDirection._internal(value, nativeValue()); + + ///Move focus down. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - FOCUS_DOWN](https://developer.android.com/reference/android/view/View#FOCUS_DOWN)) + static final DOWN = FocusDirection._internalMultiPlatform('DOWN', () { + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 130; + default: + break; + } + return null; + }); + + ///Move focus to the left. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - FOCUS_LEFT](https://developer.android.com/reference/android/view/View#FOCUS_LEFT)) + static final LEFT = FocusDirection._internalMultiPlatform('LEFT', () { + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 130; + default: + break; + } + return null; + }); + + ///Move focus to the right. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - FOCUS_RIGHT](https://developer.android.com/reference/android/view/View#FOCUS_RIGHT)) + static final RIGHT = FocusDirection._internalMultiPlatform('RIGHT', () { + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 130; + default: + break; + } + return null; + }); + + ///Move focus up. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - FOCUS_UP](https://developer.android.com/reference/android/view/View#FOCUS_UP)) + static final UP = FocusDirection._internalMultiPlatform('UP', () { + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 33; + default: + break; + } + return null; + }); + + ///Set of all values of [FocusDirection]. + static final Set values = [ + FocusDirection.DOWN, + FocusDirection.LEFT, + FocusDirection.RIGHT, + FocusDirection.UP, + ].toSet(); + + ///Gets a possible [FocusDirection] instance from [String] value. + static FocusDirection? fromValue(String? value) { + if (value != null) { + try { + return FocusDirection.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [FocusDirection] instance from a native value. + static FocusDirection? fromNativeValue(dynamic value) { + if (value != null) { + try { + return FocusDirection.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets [String] value. + String toValue() => _value; + + ///Gets [dynamic] native value. + dynamic toNativeValue() => _nativeValue; + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + @override + String toString() { + return _value; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/main.dart b/flutter_inappwebview_platform_interface/lib/src/types/main.dart index 738df7950..d6d4c78cb 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/main.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/main.dart @@ -235,3 +235,4 @@ export 'frame_kind.dart' show FrameKind; export 'process_failed_kind.dart' show ProcessFailedKind; export 'process_failed_reason.dart' show ProcessFailedReason; export 'process_failed_detail.dart' show ProcessFailedDetail; +export 'focus_direction.dart' show FocusDirection; From f16fe0622e6458446b1fe3f4132eb51cfe1e0a16 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Tue, 5 Nov 2024 01:50:26 +0100 Subject: [PATCH 056/137] updated tests, android: fixed js bridge logic, ios: Fixed show, hide methods and hidden setting for InAppBrowser --- flutter_inappwebview/CHANGELOG.md | 1 + .../chrome_safari_browser/open_and_close.dart | 2 +- .../in_app_webview/user_scripts.dart | 2 + .../in_app_webview/web_archive.dart | 4 +- .../plugin_scripts_js/JavaScriptBridgeJS.java | 4 +- .../types/UserContentController.java | 8 +-- flutter_inappwebview_ios/CHANGELOG.md | 1 + .../InAppBrowser/InAppBrowserManager.swift | 31 ++++----- .../InAppBrowserNavigationController.swift | 4 -- .../InAppBrowserWebViewController.swift | 64 ++++++++++--------- .../PluginScriptsJS/JavaScriptBridgeJS.swift | 2 +- .../PluginScriptsJS/JavaScriptBridgeJS.swift | 2 +- .../lib/src/types/user_script.dart | 4 ++ .../lib/src/types/user_script.g.dart | 4 ++ 14 files changed, 73 insertions(+), 60 deletions(-) diff --git a/flutter_inappwebview/CHANGELOG.md b/flutter_inappwebview/CHANGELOG.md index 8eb2eff6c..4cbf82219 100755 --- a/flutter_inappwebview/CHANGELOG.md +++ b/flutter_inappwebview/CHANGELOG.md @@ -42,6 +42,7 @@ Implemented security features to better manage access to the native javascript b - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error - Added support for `UserScript.allowedOriginRules` parameter - Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) +- ios: Fixed `show`, `hide` methods and `hidden` setting for `InAppBrowser` - macOS: Implemented also `clearFocus` WebView method - macOS: Implemented workaround for "[macOS] Copy Shortcut does not work if TextField outside of WebView has focus" [#2380](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2380) diff --git a/flutter_inappwebview/example/integration_test/chrome_safari_browser/open_and_close.dart b/flutter_inappwebview/example/integration_test/chrome_safari_browser/open_and_close.dart index 4615f4573..78eb9c4dc 100644 --- a/flutter_inappwebview/example/integration_test/chrome_safari_browser/open_and_close.dart +++ b/flutter_inappwebview/example/integration_test/chrome_safari_browser/open_and_close.dart @@ -40,7 +40,7 @@ void openAndClose() { activityButton: ActivityButton( templateImage: UIImage(systemName: "sun.max"), extensionIdentifier: - "com.pichillilorenzo.flutterinappwebview-ios-example.test"))); + "com.pichillilorenzo.flutterinappwebview-ios-example3.test"))); await chromeSafariBrowser.opened.future; expect(chromeSafariBrowser.isOpened(), true); expect(() async { diff --git a/flutter_inappwebview/example/integration_test/in_app_webview/user_scripts.dart b/flutter_inappwebview/example/integration_test/in_app_webview/user_scripts.dart index 078218caf..339fd53dd 100644 --- a/flutter_inappwebview/example/integration_test/in_app_webview/user_scripts.dart +++ b/flutter_inappwebview/example/integration_test/in_app_webview/user_scripts.dart @@ -32,10 +32,12 @@ void userScripts() { UserScript( source: "var bar = 2;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END, + forMainFrameOnly: defaultTargetPlatform != TargetPlatform.android, contentWorld: ContentWorld.DEFAULT_CLIENT), UserScript( source: "var bar2 = 12;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END, + forMainFrameOnly: defaultTargetPlatform != TargetPlatform.android, contentWorld: ContentWorld.world(name: "test")), ]), onWebViewCreated: (controller) { diff --git a/flutter_inappwebview/example/integration_test/in_app_webview/web_archive.dart b/flutter_inappwebview/example/integration_test/in_app_webview/web_archive.dart index 914011ec4..36a25f410 100644 --- a/flutter_inappwebview/example/integration_test/in_app_webview/web_archive.dart +++ b/flutter_inappwebview/example/integration_test/in_app_webview/web_archive.dart @@ -60,7 +60,9 @@ void webArchive() { controllerCompleter.complete(controller); }, onLoadStop: (controller, url) { - pageLoaded.complete(); + if (!pageLoaded.isCompleted) { + pageLoaded.complete(); + } }, ), ), diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java index 66fc8bf21..a48d08a1e 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/plugin_scripts_js/JavaScriptBridgeJS.java @@ -322,7 +322,7 @@ public static String JAVASCRIPT_BRIDGE_JS_SOURCE() { " _Array_slice.call = window.Function.prototype.call;" + " _setTimeout = window.setTimeout;" + " _Promise = window.Promise;" + - " _javaInjectedObject = window." + get_JAVASCRIPT_BRIDGE_NAME() + ";" + + " _javaInjectedObject = window.top." + get_JAVASCRIPT_BRIDGE_NAME() + ";" + " } catch (_) { return; }" + " window." + get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler = function() {" + " var _callHandlerID = _setTimeout(function(){});" + @@ -337,7 +337,7 @@ public static String JAVASCRIPT_BRIDGE_JS_SOURCE() { " 'args': _JSON_stringify(_Array_slice.call(arguments, 1))" + " }));" + " return new _Promise(function(resolve, reject) {" + - " window.top." + get_JAVASCRIPT_BRIDGE_NAME() + "[_callHandlerID] = {resolve: resolve, reject: reject};" + + " _javaInjectedObject[_callHandlerID] = {resolve: resolve, reject: reject};" + " });" + " } catch (error) {" + " return new _Promise(function(resolve, reject) { resolve(); });" + diff --git a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java index 21b596d27..0e59a581d 100644 --- a/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java +++ b/flutter_inappwebview_android/android/src/main/java/com/pichillilorenzo/flutter_inappwebview_android/types/UserContentController.java @@ -460,15 +460,15 @@ static private String wrapSourceCodeAddChecks(String source, UserScript userScri } private static String USER_SCRIPTS_AT_DOCUMENT_START_WRAPPER_JS_SOURCE() { - return "if (window._userScriptsAtDocumentStartLoaded == null || !window._userScriptsAtDocumentStartLoaded) {" + - " window._userScriptsAtDocumentStartLoaded = true;" + + return "if (window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentStartLoaded == null || !window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentStartLoaded) {" + + " window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentStartLoaded = true;" + " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + "}"; } private static String USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE() { - return "if (window._userScriptsAtDocumentEndLoaded == null || !window._userScriptsAtDocumentEndLoaded) {" + - " window._userScriptsAtDocumentEndLoaded = true;" + + return "if (window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentEndLoaded == null || !window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentEndLoaded) {" + + " window._" + JavaScriptBridgeJS.get_JAVASCRIPT_BRIDGE_NAME() + "_userScriptsAtDocumentEndLoaded = true;" + " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + "}"; } diff --git a/flutter_inappwebview_ios/CHANGELOG.md b/flutter_inappwebview_ios/CHANGELOG.md index 2c52d0bf4..51c5596b8 100644 --- a/flutter_inappwebview_ios/CHANGELOG.md +++ b/flutter_inappwebview_ios/CHANGELOG.md @@ -6,6 +6,7 @@ - Added support for `UserScript.allowedOriginRules` parameter - Moved `WKUserContentController` initialization on `preWKWebViewConfiguration` to fix possible `undefined is not an object (evaluating 'window.webkit.messageHandlers')` javascript error - Merged "change priority of DispatchQueue" [#2322](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2322) (thanks to [nnnlog](https://github.com/nnnlog)) +- Fixed `show`, `hide` methods and `hidden` setting for `InAppBrowser` ## 1.1.2 diff --git a/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserManager.swift b/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserManager.swift index 06219762e..c7c3b8e77 100755 --- a/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserManager.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserManager.swift @@ -17,8 +17,8 @@ public class InAppBrowserManager: ChannelDelegate { static let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController" static let NAV_STORYBOARD_CONTROLLER_ID = "navController" var plugin: SwiftFlutterPlugin? - - private var previousStatusBarStyle = -1 + + var navControllers: [String: InAppBrowserNavigationController?] = [:] init(plugin: SwiftFlutterPlugin) { super.init(channel: FlutterMethodChannel(name: InAppBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) @@ -44,10 +44,6 @@ public class InAppBrowserManager: ChannelDelegate { } public func prepareInAppBrowserWebViewController(settings: [String: Any?]) -> InAppBrowserWebViewController { - if previousStatusBarStyle == -1 { - previousStatusBarStyle = UIApplication.shared.statusBarStyle.rawValue - } - let browserSettings = InAppBrowserSettings() let _ = browserSettings.parse(settings: settings) @@ -59,7 +55,6 @@ public class InAppBrowserManager: ChannelDelegate { webViewController.browserSettings = browserSettings webViewController.isHidden = browserSettings.hidden webViewController.webViewSettings = webViewSettings - webViewController.previousStatusBarStyle = previousStatusBarStyle return webViewController } @@ -105,17 +100,12 @@ public class InAppBrowserManager: ChannelDelegate { navController.pushViewController(webViewController, animated: false) webViewController.prepareNavigationControllerBeforeViewWillAppear() - var animated = true - if let browserSettings = webViewController.browserSettings, browserSettings.hidden { - animated = false - } - guard let visibleViewController = UIApplication.shared.visibleViewController else { assertionFailure("Failure init the visibleViewController!") return } - - if let popover = navController.popoverPresentationController { + + if let popover = webViewController.popoverPresentationController { let sourceView = visibleViewController.view ?? UIView() popover.sourceRect = CGRect(x: sourceView.bounds.midX, y: sourceView.bounds.midY, width: 0, height: 0) @@ -123,7 +113,13 @@ public class InAppBrowserManager: ChannelDelegate { popover.sourceView = sourceView } - visibleViewController.present(navController, animated: animated) + if let browserSettings = webViewController.browserSettings, browserSettings.hidden { + webViewController.loadViewIfNeeded() + } else { + visibleViewController.present(navController, animated: true) + } + + navControllers[webViewController.id] = navController } public func openWithSystemBrowser(url: String, result: @escaping FlutterResult) { @@ -144,6 +140,11 @@ public class InAppBrowserManager: ChannelDelegate { public override func dispose() { super.dispose() + let navControllersValues = navControllers.values + navControllersValues.forEach { (navController: InAppBrowserNavigationController?) in + navController?.dismiss(animated: false) + } + navControllers.removeAll() plugin = nil } diff --git a/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserNavigationController.swift b/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserNavigationController.swift index 2d7b8c590..1ab8a3642 100644 --- a/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserNavigationController.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserNavigationController.swift @@ -8,12 +8,8 @@ import Foundation public class InAppBrowserNavigationController: UINavigationController { - var tmpWindow: UIWindow? - deinit { debugPrint("InAppBrowserNavigationController - dealloc") - tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0) - tmpWindow = nil UIApplication.shared.delegate?.window??.makeKeyAndVisible() } } diff --git a/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift b/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift index c75434782..befa12ab0 100755 --- a/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift +++ b/flutter_inappwebview_ios/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift @@ -47,7 +47,6 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega var initialMimeType: String? var initialEncoding: String? var initialBaseUrl: String? - var previousStatusBarStyle = -1 var initialUserScripts: [[String: Any]] = [] var pullToRefreshInitialSettings: [String: Any?] = [:] var isHidden = false @@ -214,7 +213,9 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega } public override func viewDidDisappear(_ animated: Bool) { - dispose() + if !isHidden { + dispose() + } super.viewDidDisappear(animated) } @@ -411,31 +412,27 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega } public func show(completion: (() -> Void)? = nil) { - if let navController = navigationController as? InAppBrowserNavigationController, let window = navController.tmpWindow { + if let visibleViewController = UIApplication.shared.visibleViewController, + let navigationController = navigationController { isHidden = false - window.alpha = 0.0 - window.isHidden = false - window.makeKeyAndVisible() - UIView.animate(withDuration: 0.2) { - window.alpha = 1.0 + visibleViewController.present(navigationController, animated: true) { completion?() } + } else { + completion?() } } public func hide(completion: (() -> Void)? = nil) { - if let navController = navigationController as? InAppBrowserNavigationController, let window = navController.tmpWindow { + if let navigationController = navigationController { isHidden = true - window.alpha = 1.0 - UIView.animate(withDuration: 0.2) { - window.alpha = 0.0 - } completion: { (finished) in - if finished { - window.isHidden = true - UIApplication.shared.delegate?.window??.makeKeyAndVisible() - completion?() - } + navigationController.dismiss(animated: true) { + completion?() + UIApplication.shared.delegate?.window??.makeKeyAndVisible() } + } else { + completion?() + UIApplication.shared.delegate?.window??.makeKeyAndVisible() } } @@ -451,24 +448,31 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega public func close(completion: (() -> Void)? = nil) { if (navigationController?.responds(to: #selector(getter: navigationController?.presentingViewController)))! { - navigationController?.presentingViewController?.dismiss(animated: true, completion: {() -> Void in + if let presentingViewController = navigationController?.presentingViewController { + presentingViewController.dismiss(animated: true, completion: {() -> Void in + completion?() + self.dispose() + }) + } else { completion?() - }) + dispose() + } } else { - navigationController?.parent?.dismiss(animated: true, completion: {() -> Void in + if let parent = navigationController?.parent { + parent.dismiss(animated: true, completion: {() -> Void in + completion?() + self.dispose() + }) + } else { completion?() - }) + dispose() + } } } @objc public func close() { - if (navigationController?.responds(to: #selector(getter: navigationController?.presentingViewController)))! { - navigationController?.presentingViewController?.dismiss(animated: true, completion: nil) - } - else { - navigationController?.parent?.dismiss(animated: true, completion: nil) - } + close(completion: nil) } @objc public func goBack() { @@ -633,9 +637,6 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega webView?.removeFromSuperview() webView = nil view = nil - if previousStatusBarStyle != -1, let statusBarStyle = UIStatusBarStyle(rawValue: previousStatusBarStyle) { - UIApplication.shared.statusBarStyle = statusBarStyle - } transitioningDelegate = nil searchBar?.delegate = nil closeButton?.target = nil @@ -644,6 +645,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega reloadButton?.target = nil shareButton?.target = nil menuButton?.target = nil + plugin?.inAppBrowserManager?.navControllers[id] = nil plugin = nil } diff --git a/flutter_inappwebview_ios/ios/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift b/flutter_inappwebview_ios/ios/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift index b4df2ee73..0e42a3734 100644 --- a/flutter_inappwebview_ios/ios/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift +++ b/flutter_inappwebview_ios/ios/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift @@ -66,7 +66,7 @@ public class JavaScriptBridgeJS { }); return new _Promise(function(resolve, reject) { try { - (window.top != window ? window.top : window).\(get_JAVASCRIPT_BRIDGE_NAME())[_callHandlerID] = {resolve: resolve, reject: reject}; + (window.top === window ? window : window.top).\(get_JAVASCRIPT_BRIDGE_NAME())[_callHandlerID] = {resolve: resolve, reject: reject}; } catch (e) { resolve(); } diff --git a/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift index b4df2ee73..0e42a3734 100644 --- a/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift +++ b/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/JavaScriptBridgeJS.swift @@ -66,7 +66,7 @@ public class JavaScriptBridgeJS { }); return new _Promise(function(resolve, reject) { try { - (window.top != window ? window.top : window).\(get_JAVASCRIPT_BRIDGE_NAME())[_callHandlerID] = {resolve: resolve, reject: reject}; + (window.top === window ? window : window.top).\(get_JAVASCRIPT_BRIDGE_NAME())[_callHandlerID] = {resolve: resolve, reject: reject}; } catch (e) { resolve(); } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/user_script.dart b/flutter_inappwebview_platform_interface/lib/src/types/user_script.dart index c3614b490..fb655cd55 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/user_script.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/user_script.dart @@ -47,6 +47,10 @@ class UserScript_ { ///A scope of execution in which to evaluate the script to prevent conflicts between different scripts. ///For more information about content worlds, see [ContentWorld]. + /// + ///**NOTE for Android**: because of how a Content World is implemented on Android, if [forMainFrameOnly] is `true`, + ///the [source] inside a specific Content World that is not [ContentWorld.PAGE] will not be executed. + ///See [ContentWorld] for more details. late ContentWorld contentWorld; @ExchangeableObjectConstructor() diff --git a/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart index 53a92ff19..e2f5fc415 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart @@ -23,6 +23,10 @@ class UserScript { ///A scope of execution in which to evaluate the script to prevent conflicts between different scripts. ///For more information about content worlds, see [ContentWorld]. + /// + ///**NOTE for Android**: because of how a Content World is implemented on Android, if [forMainFrameOnly] is `true`, + ///the [source] inside a specific Content World that is not [ContentWorld.PAGE] will not be executed. + ///See [ContentWorld] for more details. late ContentWorld contentWorld; ///A Boolean value that indicates whether to inject the script into the main frame. From 1c90aef65f4cb138a43dbec9d8cde75252961eb1 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Tue, 5 Nov 2024 01:52:16 +0100 Subject: [PATCH 057/137] code format --- .../in_app_webview/user_scripts.dart | 6 +- .../src/in_app_webview/in_app_webview.dart | 18 ++-- .../in_app_webview_controller.dart | 3 +- .../lib/src/cookie_manager.dart | 8 +- .../in_app_webview_controller.dart | 5 +- .../lib/src/cookie_manager.dart | 8 +- .../in_app_webview_controller.dart | 5 +- .../lib/src/context_menu/context_menu.dart | 4 +- .../platform_inappwebview_controller.dart | 3 +- .../src/in_app_webview/platform_webview.dart | 3 +- .../lib/src/types/client_cert_challenge.dart | 32 +++---- .../lib/src/types/client_cert_response.dart | 2 +- .../lib/src/types/focus_direction.dart | 26 ++--- .../lib/src/types/frame_info.dart | 8 +- .../lib/src/types/frame_kind.dart | 34 +++---- .../lib/src/types/process_failed_detail.dart | 18 ++-- .../lib/src/types/process_failed_kind.dart | 95 +++++++++++-------- .../lib/src/types/process_failed_reason.dart | 47 ++++----- .../lib/src/types/ssl_error_type.dart | 19 ++-- .../in_app_webview_controller.dart | 48 ++++++---- 20 files changed, 212 insertions(+), 180 deletions(-) diff --git a/flutter_inappwebview/example/integration_test/in_app_webview/user_scripts.dart b/flutter_inappwebview/example/integration_test/in_app_webview/user_scripts.dart index 339fd53dd..933bfc428 100644 --- a/flutter_inappwebview/example/integration_test/in_app_webview/user_scripts.dart +++ b/flutter_inappwebview/example/integration_test/in_app_webview/user_scripts.dart @@ -32,12 +32,14 @@ void userScripts() { UserScript( source: "var bar = 2;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END, - forMainFrameOnly: defaultTargetPlatform != TargetPlatform.android, + forMainFrameOnly: + defaultTargetPlatform != TargetPlatform.android, contentWorld: ContentWorld.DEFAULT_CLIENT), UserScript( source: "var bar2 = 12;", injectionTime: UserScriptInjectionTime.AT_DOCUMENT_END, - forMainFrameOnly: defaultTargetPlatform != TargetPlatform.android, + forMainFrameOnly: + defaultTargetPlatform != TargetPlatform.android, contentWorld: ContentWorld.world(name: "test")), ]), onWebViewCreated: (controller) { diff --git a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview.dart index 249cbd645..5a42a3959 100755 --- a/flutter_inappwebview/lib/src/in_app_webview/in_app_webview.dart +++ b/flutter_inappwebview/lib/src/in_app_webview/in_app_webview.dart @@ -166,14 +166,14 @@ class InAppWebView extends StatefulWidget { onPrintRequest, void Function(InAppWebViewController controller, int progress)? onProgressChanged, - Future Function(InAppWebViewController controller, - ClientCertChallenge challenge)? + Future Function( + InAppWebViewController controller, ClientCertChallenge challenge)? onReceivedClientCertRequest, Future Function(InAppWebViewController controller, - HttpAuthenticationChallenge challenge)? + HttpAuthenticationChallenge challenge)? onReceivedHttpAuthRequest, - Future Function(InAppWebViewController controller, - ServerTrustChallenge challenge)? + Future Function( + InAppWebViewController controller, ServerTrustChallenge challenge)? onReceivedServerTrustAuthRequest, void Function(InAppWebViewController controller, int x, int y)? onScrollChanged, @@ -294,8 +294,9 @@ class InAppWebView extends StatefulWidget { void Function(InAppWebViewController controller, Size oldContentSize, Size newContentSize)? onContentSizeChanged, - void Function(InAppWebViewController controller, ProcessFailedDetail detail)? - onProcessFailed, + void Function( + InAppWebViewController controller, ProcessFailedDetail detail)? + onProcessFailed, }) : this.fromPlatformCreationParams( key: key, params: PlatformInAppWebViewWidgetCreationParams( @@ -660,8 +661,7 @@ class InAppWebView extends StatefulWidget { : null, onProcessFailed: onProcessFailed != null ? (controller, detail) => - onProcessFailed.call( - controller, detail) + onProcessFailed.call(controller, detail) : null, gestureRecognizers: gestureRecognizers, headlessWebView: headlessWebView?.platform, diff --git a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart index 4e3794b53..5ce328db3 100644 --- a/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_android/lib/src/in_app_webview/in_app_webview_controller.dart @@ -2245,7 +2245,8 @@ class AndroidInAppWebViewController extends PlatformInAppWebViewController InAppWebViewRect? previouslyFocusedRect}) async { Map args = {}; args.putIfAbsent("direction", () => direction?.toNativeValue()); - args.putIfAbsent("previouslyFocusedRect", () => previouslyFocusedRect?.toMap()); + args.putIfAbsent( + "previouslyFocusedRect", () => previouslyFocusedRect?.toMap()); return await channel?.invokeMethod('requestFocus', args); } diff --git a/flutter_inappwebview_ios/lib/src/cookie_manager.dart b/flutter_inappwebview_ios/lib/src/cookie_manager.dart index b2272f38c..2c0eea9cd 100755 --- a/flutter_inappwebview_ios/lib/src/cookie_manager.dart +++ b/flutter_inappwebview_ios/lib/src/cookie_manager.dart @@ -408,10 +408,10 @@ class IOSCookieManager extends PlatformCookieManager with ChannelController { var platformUtil = PlatformUtil.instance(); var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc(); return await platformUtil.formatDate( - date: dateTime, - format: 'EEE, dd MMM yyyy HH:mm:ss z', - locale: 'en_US', - timezone: 'GMT'); + date: dateTime, + format: 'EEE, dd MMM yyyy HH:mm:ss z', + locale: 'en_US', + timezone: 'GMT'); } Future _shouldUseJavascript() async { diff --git a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart index 7fe686162..ee76ad6f4 100644 --- a/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_ios/lib/src/in_app_webview/in_app_webview_controller.dart @@ -2235,10 +2235,11 @@ class IOSInAppWebViewController extends PlatformInAppWebViewController @override Future requestFocus( {FocusDirection? direction, - InAppWebViewRect? previouslyFocusedRect}) async { + InAppWebViewRect? previouslyFocusedRect}) async { Map args = {}; args.putIfAbsent("direction", () => direction?.toNativeValue()); - args.putIfAbsent("previouslyFocusedRect", () => previouslyFocusedRect?.toMap()); + args.putIfAbsent( + "previouslyFocusedRect", () => previouslyFocusedRect?.toMap()); return await channel?.invokeMethod('requestFocus', args); } diff --git a/flutter_inappwebview_macos/lib/src/cookie_manager.dart b/flutter_inappwebview_macos/lib/src/cookie_manager.dart index dba8e6088..6078cb526 100755 --- a/flutter_inappwebview_macos/lib/src/cookie_manager.dart +++ b/flutter_inappwebview_macos/lib/src/cookie_manager.dart @@ -408,10 +408,10 @@ class MacOSCookieManager extends PlatformCookieManager with ChannelController { var platformUtil = PlatformUtil.instance(); var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc(); return await platformUtil.formatDate( - date: dateTime, - format: 'EEE, dd MMM yyyy HH:mm:ss z', - locale: 'en_US', - timezone: 'GMT'); + date: dateTime, + format: 'EEE, dd MMM yyyy HH:mm:ss z', + locale: 'en_US', + timezone: 'GMT'); } Future _shouldUseJavascript() async { diff --git a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart index add535e8a..4a6ebd52a 100644 --- a/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_macos/lib/src/in_app_webview/in_app_webview_controller.dart @@ -2213,10 +2213,11 @@ class MacOSInAppWebViewController extends PlatformInAppWebViewController @override Future requestFocus( {FocusDirection? direction, - InAppWebViewRect? previouslyFocusedRect}) async { + InAppWebViewRect? previouslyFocusedRect}) async { Map args = {}; args.putIfAbsent("direction", () => direction?.toNativeValue()); - args.putIfAbsent("previouslyFocusedRect", () => previouslyFocusedRect?.toMap()); + args.putIfAbsent( + "previouslyFocusedRect", () => previouslyFocusedRect?.toMap()); return await channel?.invokeMethod('requestFocus', args); } diff --git a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart index f791abaac..cf9c81592 100644 --- a/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart +++ b/flutter_inappwebview_platform_interface/lib/src/context_menu/context_menu.dart @@ -54,8 +54,8 @@ class ContextMenu_ { // ignore: unused_element Map _toMapMergeWith() { return { - "settings": - (settings as ContextMenuSettings?)?.toMap() ?? (options as ContextMenuOptions?)?.toMap() + "settings": (settings as ContextMenuSettings?)?.toMap() ?? + (options as ContextMenuOptions?)?.toMap() }; } } 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 6a7502052..968b2c8f8 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 @@ -1088,7 +1088,8 @@ abstract class PlatformInAppWebViewController extends PlatformInterface ///- iOS ([Official API - UIResponder.becomeFirstResponder](https://developer.apple.com/documentation/uikit/uiresponder/1621113-becomefirstresponder)) ///- MacOS ([Official API - NSWindow.makeFirstResponder](https://developer.apple.com/documentation/appkit/nswindow/1419366-makefirstresponder)) ///{@endtemplate} - Future requestFocus({FocusDirection? direction, InAppWebViewRect? previouslyFocusedRect}) { + Future requestFocus( + {FocusDirection? direction, InAppWebViewRect? previouslyFocusedRect}) { throw UnimplementedError( 'requestFocus is not implemented on the current platform'); } 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 7de987d63..b53bba279 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 @@ -1080,7 +1080,8 @@ class PlatformWebViewCreationParams { ///**Officially Supported Platforms/Implementations**: ///- Windows ([Official API - ICoreWebView2.add_ProcessFailed](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2?view=webview2-1.0.2849.39#add_processfailed)) ///{@endtemplate} - final void Function(T controller, ProcessFailedDetail detail)? onProcessFailed; + final void Function(T controller, ProcessFailedDetail detail)? + onProcessFailed; ///{@template flutter_inappwebview_platform_interface.PlatformWebViewCreationParams.initialUrlRequest} ///Initial url request that will be loaded. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/client_cert_challenge.dart b/flutter_inappwebview_platform_interface/lib/src/types/client_cert_challenge.dart index fd8cc5a62..5c094362a 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/client_cert_challenge.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/client_cert_challenge.dart @@ -41,31 +41,25 @@ class ClientCertChallenge_ extends URLAuthenticationChallenge_ { ///The collection contains Base64 encoding of DER encoded distinguished names ///of certificate authorities allowed by the server. - @SupportedPlatforms(platforms: [ - WindowsPlatform() - ]) + @SupportedPlatforms(platforms: [WindowsPlatform()]) List? allowedCertificateAuthorities; ///If the server that issued this request is an http proxy. - @SupportedPlatforms(platforms: [ - WindowsPlatform() - ]) + @SupportedPlatforms(platforms: [WindowsPlatform()]) bool? isProxy; ///The collection contains mutually trusted CA certificates. - @SupportedPlatforms(platforms: [ - WindowsPlatform() - ]) + @SupportedPlatforms(platforms: [WindowsPlatform()]) List? mutuallyTrustedCertificates; - ClientCertChallenge_( - {required URLProtectionSpace_ protectionSpace, - @Deprecated('Use principals instead') this.androidPrincipals, - this.principals, - @Deprecated('Use keyTypes instead') this.androidKeyTypes, - this.keyTypes, - this.allowedCertificateAuthorities, - this.isProxy, - this.mutuallyTrustedCertificates,}) - : super(protectionSpace: protectionSpace); + ClientCertChallenge_({ + required URLProtectionSpace_ protectionSpace, + @Deprecated('Use principals instead') this.androidPrincipals, + this.principals, + @Deprecated('Use keyTypes instead') this.androidKeyTypes, + this.keyTypes, + this.allowedCertificateAuthorities, + this.isProxy, + this.mutuallyTrustedCertificates, + }) : super(protectionSpace: protectionSpace); } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/client_cert_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/client_cert_response.dart index ee9f91d0f..ed3194e93 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/client_cert_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/client_cert_response.dart @@ -51,7 +51,7 @@ class ClientCertResponse_ { @Deprecated('Use keyStoreType instead') this.androidKeyStoreType = "PKCS12", this.keyStoreType = "PKCS12", - this.selectedCertificate = -1, + this.selectedCertificate = -1, this.action = ClientCertResponseAction_.CANCEL}) { if (this.action == ClientCertResponseAction_.PROCEED && !Util.isWindows) assert(certificatePath.isNotEmpty); diff --git a/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.dart b/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.dart index c3f593b8b..aead758e8 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/focus_direction.dart @@ -16,9 +16,9 @@ class FocusDirection_ { @EnumSupportedPlatforms(platforms: [ EnumAndroidPlatform( apiName: 'FOCUS_UP', - apiUrl: 'https://developer.android.com/reference/android/view/View#FOCUS_UP', - value: 33 - ), + apiUrl: + 'https://developer.android.com/reference/android/view/View#FOCUS_UP', + value: 33), ]) static const UP = const FocusDirection_._internal('UP'); @@ -26,9 +26,9 @@ class FocusDirection_ { @EnumSupportedPlatforms(platforms: [ EnumAndroidPlatform( apiName: 'FOCUS_DOWN', - apiUrl: 'https://developer.android.com/reference/android/view/View#FOCUS_DOWN', - value: 130 - ), + apiUrl: + 'https://developer.android.com/reference/android/view/View#FOCUS_DOWN', + value: 130), ]) static const DOWN = const FocusDirection_._internal('DOWN'); @@ -36,9 +36,9 @@ class FocusDirection_ { @EnumSupportedPlatforms(platforms: [ EnumAndroidPlatform( apiName: 'FOCUS_LEFT', - apiUrl: 'https://developer.android.com/reference/android/view/View#FOCUS_LEFT', - value: 130 - ), + apiUrl: + 'https://developer.android.com/reference/android/view/View#FOCUS_LEFT', + value: 130), ]) static const LEFT = const FocusDirection_._internal('LEFT'); @@ -46,9 +46,9 @@ class FocusDirection_ { @EnumSupportedPlatforms(platforms: [ EnumAndroidPlatform( apiName: 'FOCUS_RIGHT', - apiUrl: 'https://developer.android.com/reference/android/view/View#FOCUS_RIGHT', - value: 130 - ), + apiUrl: + 'https://developer.android.com/reference/android/view/View#FOCUS_RIGHT', + value: 130), ]) static const RIGHT = const FocusDirection_._internal('RIGHT'); -} \ No newline at end of file +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/frame_info.dart b/flutter_inappwebview_platform_interface/lib/src/types/frame_info.dart index 6283a3100..ad8906c8c 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/frame_info.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/frame_info.dart @@ -52,8 +52,12 @@ class FrameInfo_ { FrameKind_? kind; FrameInfo_( - {required this.isMainFrame, required this.request, this.securityOrigin, - this.name, this.frameId, this.kind}); + {required this.isMainFrame, + required this.request, + this.securityOrigin, + this.name, + this.frameId, + this.kind}); } ///An object that contains information about a frame on a webpage. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart index 8b3a19cda..c3a6c6965 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart @@ -15,10 +15,10 @@ class FrameKind_ { ///Indicates that the frame is an unknown type frame. We may extend this enum type to identify more frame kinds in the future. @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( - apiName: 'COREWEBVIEW2_FRAME_KIND_UNKNOWN', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', - value: 0 - ), + apiName: 'COREWEBVIEW2_FRAME_KIND_UNKNOWN', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 0), ]) static const UNKNOWN = const FrameKind_._internal('UNKNOWN'); @@ -26,9 +26,9 @@ class FrameKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_FRAME_KIND_MAIN_FRAME', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', - value: 1 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 1), ]) static const MAIN_FRAME = const FrameKind_._internal('MAIN_FRAME'); @@ -36,9 +36,9 @@ class FrameKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_FRAME_KIND_IFRAME', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', - value: 2 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 2), ]) static const IFRAME = const FrameKind_._internal('IFRAME'); @@ -46,9 +46,9 @@ class FrameKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_FRAME_KIND_EMBED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', - value: 3 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 3), ]) static const EMBED = const FrameKind_._internal('EMBED'); @@ -56,9 +56,9 @@ class FrameKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_FRAME_KIND_OBJECT', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', - value: 4 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 4), ]) static const OBJECT = const FrameKind_._internal('OBJECT'); -} \ No newline at end of file +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart index 7f865fd28..c9704c296 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart @@ -65,12 +65,12 @@ class ProcessFailedDetail_ { ]) List? frameInfos; - ProcessFailedDetail_( - {required this.kind, - this.exitCode, - this.processDescription, - this.reason, - this.failureSourceModulePath, - this.frameInfos, - }); -} \ No newline at end of file + ProcessFailedDetail_({ + required this.kind, + this.exitCode, + this.processDescription, + this.reason, + this.failureSourceModulePath, + this.frameInfos, + }); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart index 2e3d1db73..cee266e32 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart @@ -17,11 +17,12 @@ class ProcessFailedKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 0 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 0), ]) - static const BROWSER_PROCESS_EXITED = const ProcessFailedKind_._internal('BROWSER_PROCESS_EXITED'); + static const BROWSER_PROCESS_EXITED = + const ProcessFailedKind_._internal('BROWSER_PROCESS_EXITED'); ///Indicates that the main frame's render process ended unexpectedly. Any subframes in the WebView will be gone too. ///A new render process is created automatically and navigated to an error page. @@ -29,11 +30,12 @@ class ProcessFailedKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 1 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 1), ]) - static const RENDER_PROCESS_EXITED = const ProcessFailedKind_._internal('RENDER_PROCESS_EXITED'); + static const RENDER_PROCESS_EXITED = + const ProcessFailedKind_._internal('RENDER_PROCESS_EXITED'); ///Indicates that the main frame's render process is unresponsive. ///Renderer process unresponsiveness can happen for the following reasons: @@ -51,11 +53,12 @@ class ProcessFailedKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 2 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 2), ]) - static const RENDER_PROCESS_UNRESPONSIVE = const ProcessFailedKind_._internal('RENDER_PROCESS_UNRESPONSIVE'); + static const RENDER_PROCESS_UNRESPONSIVE = + const ProcessFailedKind_._internal('RENDER_PROCESS_UNRESPONSIVE'); ///Indicates that a frame-only render process ended unexpectedly. ///The process exit does not affect the top-level document, only a subset of the subframes within it. @@ -63,11 +66,12 @@ class ProcessFailedKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 3 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 3), ]) - static const FRAME_RENDER_PROCESS_EXITED = const ProcessFailedKind_._internal('FRAME_RENDER_PROCESS_EXITED'); + static const FRAME_RENDER_PROCESS_EXITED = + const ProcessFailedKind_._internal('FRAME_RENDER_PROCESS_EXITED'); ///Indicates that a utility process ended unexpectedly. ///The failed process is recreated automatically. @@ -75,23 +79,26 @@ class ProcessFailedKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 4 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 4), ]) - static const UTILITY_PROCESS_EXITED = const ProcessFailedKind_._internal('UTILITY_PROCESS_EXITED'); + static const UTILITY_PROCESS_EXITED = + const ProcessFailedKind_._internal('UTILITY_PROCESS_EXITED'); ///Indicates that a sandbox helper process ended unexpectedly. ///This failure is not fatal. ///Your application does not need to handle recovery for this event. @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( - apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 5 - ), + apiName: + 'COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 5), ]) - static const SANDBOX_HELPER_PROCESS_EXITED = const ProcessFailedKind_._internal('SANDBOX_HELPER_PROCESS_EXITED'); + static const SANDBOX_HELPER_PROCESS_EXITED = + const ProcessFailedKind_._internal('SANDBOX_HELPER_PROCESS_EXITED'); ///Indicates that the GPU process ended unexpectedly. ///The failed process is recreated automatically. @@ -99,11 +106,12 @@ class ProcessFailedKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 6 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 6), ]) - static const GPU_PROCESS_EXITED = const ProcessFailedKind_._internal('GPU_PROCESS_EXITED'); + static const GPU_PROCESS_EXITED = + const ProcessFailedKind_._internal('GPU_PROCESS_EXITED'); ///Indicates that a PPAPI plugin process ended unexpectedly. ///This failure is not fatal. @@ -111,11 +119,12 @@ class ProcessFailedKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 7 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 7), ]) - static const PPAPI_PLUGIN_PROCESS_EXITED = const ProcessFailedKind_._internal('PPAPI_PLUGIN_PROCESS_EXITED'); + static const PPAPI_PLUGIN_PROCESS_EXITED = + const ProcessFailedKind_._internal('PPAPI_PLUGIN_PROCESS_EXITED'); ///Indicates that a PPAPI plugin broker process ended unexpectedly. ///This failure is not fatal. @@ -123,19 +132,21 @@ class ProcessFailedKind_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 8 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 8), ]) - static const PPAPI_BROKER_PROCESS_EXITED = const ProcessFailedKind_._internal('PPAPI_BROKER_PROCESS_EXITED'); + static const PPAPI_BROKER_PROCESS_EXITED = + const ProcessFailedKind_._internal('PPAPI_BROKER_PROCESS_EXITED'); ///Indicates that a process of unspecified kind ended unexpectedly. @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', - value: 9 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 9), ]) - static const UNKNOWN_PROCESS_EXITED = const ProcessFailedKind_._internal('UNKNOWN_PROCESS_EXITED'); -} \ No newline at end of file + static const UNKNOWN_PROCESS_EXITED = + const ProcessFailedKind_._internal('UNKNOWN_PROCESS_EXITED'); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart index b21afbc4b..647e6e887 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart @@ -16,9 +16,9 @@ class ProcessFailedReason_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', - value: 0 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 0), ]) static const UNEXPECTED = const ProcessFailedReason_._internal('UNEXPECTED'); @@ -26,19 +26,20 @@ class ProcessFailedReason_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_UNRESPONSIVE', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', - value: 1 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 1), ]) - static const UNRESPONSIVE = const ProcessFailedReason_._internal('UNRESPONSIVE'); + static const UNRESPONSIVE = + const ProcessFailedReason_._internal('UNRESPONSIVE'); ///The process was terminated. For example, from Task Manager. @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_TERMINATED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', - value: 2 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 2), ]) static const TERMINATED = const ProcessFailedReason_._internal('TERMINATED'); @@ -46,9 +47,9 @@ class ProcessFailedReason_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', - value: 3 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 3), ]) static const CRASHED = const ProcessFailedReason_._internal('CRASHED'); @@ -56,19 +57,21 @@ class ProcessFailedReason_ { @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', - value: 4 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 4), ]) - static const LAUNCH_FAILED = const ProcessFailedReason_._internal('LAUNCH_FAILED'); + static const LAUNCH_FAILED = + const ProcessFailedReason_._internal('LAUNCH_FAILED'); ///The process terminated due to running out of memory. @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_OUT_OF_MEMORY', - apiUrl: 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', - value: 5 - ), + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 5), ]) - static const OUT_OF_MEMORY = const ProcessFailedReason_._internal('OUT_OF_MEMORY'); -} \ No newline at end of file + static const OUT_OF_MEMORY = + const ProcessFailedReason_._internal('OUT_OF_MEMORY'); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.dart b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.dart index 0b114bce1..a8348cdb3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.dart @@ -36,7 +36,7 @@ class SslErrorType_ { EnumWindowsPlatform( apiName: 'COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_EXPIRED', apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', value: 2) ]) static const EXPIRED = SslErrorType_._internal('EXPIRED'); @@ -91,7 +91,7 @@ class SslErrorType_ { EnumWindowsPlatform( apiName: 'COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID', apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', value: 5) ]) static const INVALID = SslErrorType_._internal('INVALID'); @@ -201,9 +201,10 @@ class SslErrorType_ { 'https://developer.apple.com/documentation/security/sectrustresulttype/othererror', value: 7), EnumWindowsPlatform( - apiName: 'COREWEBVIEW2_WEB_ERROR_STATUS_CLIENT_CERTIFICATE_CONTAINS_ERRORS', + apiName: + 'COREWEBVIEW2_WEB_ERROR_STATUS_CLIENT_CERTIFICATE_CONTAINS_ERRORS', apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', value: 3) ]) static const OTHER_ERROR = SslErrorType_._internal('OTHER_ERROR'); @@ -211,19 +212,21 @@ class SslErrorType_ { ///Indicates that the SSL certificate common name does not match the web address. @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( - apiName: 'COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT', + apiName: + 'COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT', apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', value: 1) ]) - static const COMMON_NAME_IS_INCORRECT = SslErrorType_._internal('COMMON_NAME_IS_INCORRECT'); + static const COMMON_NAME_IS_INCORRECT = + SslErrorType_._internal('COMMON_NAME_IS_INCORRECT'); ///Indicates that the SSL certificate has been revoked. @EnumSupportedPlatforms(platforms: [ EnumWindowsPlatform( apiName: 'COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_REVOKED', apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', value: 4) ]) static const REVOKED = SslErrorType_._internal('REVOKED'); diff --git a/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart index 084d6e3b7..b8cc2e12f 100644 --- a/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart @@ -890,9 +890,13 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController Map arguments = call.arguments.cast(); - if (arguments['protectionSpace'] is Map && arguments['protectionSpace']['sslCertificate'] is Map && - arguments['protectionSpace']['sslCertificate']['x509Certificate'] is String) { - arguments['protectionSpace']['sslCertificate']['x509Certificate'] = utf8.encode(arguments['protectionSpace']['sslCertificate']['x509Certificate']); + if (arguments['protectionSpace'] is Map && + arguments['protectionSpace']['sslCertificate'] is Map && + arguments['protectionSpace']['sslCertificate']['x509Certificate'] + is String) { + arguments['protectionSpace']['sslCertificate']['x509Certificate'] = + utf8.encode(arguments['protectionSpace']['sslCertificate'] + ['x509Certificate']); } HttpAuthenticationChallenge challenge = @@ -916,9 +920,13 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController Map arguments = call.arguments.cast(); - if (arguments['protectionSpace'] is Map && arguments['protectionSpace']['sslCertificate'] is Map && - arguments['protectionSpace']['sslCertificate']['x509Certificate'] is String) { - arguments['protectionSpace']['sslCertificate']['x509Certificate'] = utf8.encode(arguments['protectionSpace']['sslCertificate']['x509Certificate']); + if (arguments['protectionSpace'] is Map && + arguments['protectionSpace']['sslCertificate'] is Map && + arguments['protectionSpace']['sslCertificate']['x509Certificate'] + is String) { + arguments['protectionSpace']['sslCertificate']['x509Certificate'] = + utf8.encode(arguments['protectionSpace']['sslCertificate'] + ['x509Certificate']); } ServerTrustChallenge challenge = @@ -942,18 +950,22 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController Map arguments = call.arguments.cast(); - if (arguments['protectionSpace'] is Map && arguments['protectionSpace']['sslCertificate'] is Map && - arguments['protectionSpace']['sslCertificate']['x509Certificate'] is String) { - arguments['protectionSpace']['sslCertificate']['x509Certificate'] = utf8.encode(arguments['protectionSpace']['sslCertificate']['x509Certificate']); + if (arguments['protectionSpace'] is Map && + arguments['protectionSpace']['sslCertificate'] is Map && + arguments['protectionSpace']['sslCertificate']['x509Certificate'] + is String) { + arguments['protectionSpace']['sslCertificate']['x509Certificate'] = + utf8.encode(arguments['protectionSpace']['sslCertificate'] + ['x509Certificate']); } arguments['mutuallyTrustedCertificates'] = (arguments['mutuallyTrustedCertificates'] as List) .cast>() .map((c) { - c['x509Certificate'] = utf8.encode(c['x509Certificate']); - return c; - }).toList(); + c['x509Certificate'] = utf8.encode(c['x509Certificate']); + return c; + }).toList(); ClientCertChallenge challenge = ClientCertChallenge.fromMap(arguments)!; @@ -1428,18 +1440,16 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController } break; case "onProcessFailed": - if ((webviewParams != null && - webviewParams!.onProcessFailed != null) || + if ((webviewParams != null && webviewParams!.onProcessFailed != null) || _inAppBrowserEventHandler != null) { - Map arguments = call.arguments.cast(); + Map arguments = + call.arguments.cast(); final detail = ProcessFailedDetail.fromMap(arguments)!; - if (webviewParams != null && - webviewParams!.onProcessFailed != null) + if (webviewParams != null && webviewParams!.onProcessFailed != null) webviewParams!.onProcessFailed!(_controllerFromPlatform, detail); else - _inAppBrowserEventHandler! - .onProcessFailed(detail); + _inAppBrowserEventHandler!.onProcessFailed(detail); } break; case "onCallJsHandler": From 9a03fecd8ab32ff62f984b689331898ac0025cc6 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Tue, 5 Nov 2024 10:12:10 +0100 Subject: [PATCH 058/137] Update in_app_webview_settings.dart --- .../in_app_webview_settings.dart | 269 ++++++++++++++++-- 1 file changed, 242 insertions(+), 27 deletions(-) diff --git a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart index 2b0f896f0..1d33b0a1f 100755 --- a/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart @@ -1,23 +1,16 @@ -import 'dart:typed_data'; - import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; +import 'dart:typed_data'; -import '../content_blocker.dart'; -import '../context_menu/context_menu.dart'; -import '../in_app_browser/in_app_browser_settings.dart'; -import '../in_app_browser/platform_in_app_browser.dart'; -import '../in_app_webview/platform_inappwebview_controller.dart'; import '../platform_webview_asset_loader.dart'; -import '../platform_webview_feature.dart'; import '../types/action_mode_menu_item.dart'; import '../types/cache_mode.dart'; import '../types/data_detector_types.dart'; import '../types/force_dark.dart'; import '../types/force_dark_strategy.dart'; import '../types/layout_algorithm.dart'; -import '../types/main.dart'; import '../types/mixed_content_mode.dart'; import '../types/over_scroll_mode.dart'; import '../types/referrer_policy.dart'; @@ -29,10 +22,18 @@ import '../types/scrollview_deceleration_rate.dart'; import '../types/selection_granularity.dart'; import '../types/user_preferred_content_mode.dart'; import '../types/vertical_scrollbar_position.dart'; -import '../util.dart'; +import '../types/user_script.dart'; import '../web_uri.dart'; import 'android/in_app_webview_options.dart'; import 'apple/in_app_webview_options.dart'; +import '../content_blocker.dart'; +import '../types/main.dart'; +import '../util.dart'; +import '../in_app_browser/in_app_browser_settings.dart'; +import '../platform_webview_feature.dart'; +import '../in_app_webview/platform_inappwebview_controller.dart'; +import '../context_menu/context_menu.dart'; +import '../in_app_browser/platform_in_app_browser.dart'; import 'platform_webview.dart'; part 'in_app_webview_settings.g.dart'; @@ -58,8 +59,12 @@ class InAppWebViewSettings_ { ///If the [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event is implemented and this value is `null`, ///it will be automatically inferred as `true`, otherwise, the default value is `false`. ///This logic will not be applied for [PlatformInAppBrowser], where you must set the value manually. - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()]) + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform() + ]) bool? useShouldOverrideUrlLoading; ///Set to `true` to be able to listen at the [PlatformWebViewCreationParams.onLoadResource] event. @@ -99,7 +104,11 @@ class InAppWebViewSettings_ { MacOSPlatform( apiName: "WKWebView.customUserAgent", apiUrl: - "https://developer.apple.com/documentation/webkit/wkwebview/1414950-customuseragent") + "https://developer.apple.com/documentation/webkit/wkwebview/1414950-customuseragent"), + WindowsPlatform( + apiName: 'ICoreWebView2Settings2.put_UserAgent', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings2?view=webview2-1.0.2210.55#put_useragent') ]) String? userAgent; @@ -131,7 +140,11 @@ class InAppWebViewSettings_ { apiName: "WKWebpagePreferences.allowsContentJavaScript", apiUrl: "https://developer.apple.com/documentation/webkit/wkwebpagepreferences/3552422-allowscontentjavascript/"), - WebPlatform(requiresSameOrigin: false) + WebPlatform(requiresSameOrigin: false), + WindowsPlatform( + apiName: "ICoreWebView2Settings.put_IsScriptEnabled", + apiUrl: + "https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_isscriptenabled") ]) bool? javaScriptEnabled; @@ -295,7 +308,11 @@ class InAppWebViewSettings_ { """setting this to `true`, it will clear all the cookies of all WebView instances, because there isn't any way to make the website data store non-persistent for the specific WebView instance such as on iOS."""), IOSPlatform(), - MacOSPlatform() + MacOSPlatform(), + WindowsPlatform( + apiName: "ICoreWebView2ControllerOptions.put_IsInPrivateModeEnabled", + apiUrl: + "https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controlleroptions?view=webview2-1.0.2792.45#put_isinprivatemodeenabled") ]) bool? incognito; @@ -308,7 +325,12 @@ because there isn't any way to make the website data store non-persistent for th @SupportedPlatforms(platforms: [ AndroidPlatform(), IOSPlatform(), - MacOSPlatform(available: "12.0") + MacOSPlatform(available: "12.0"), + WindowsPlatform( + available: '1.0.774.44', + apiName: 'ICoreWebView2Controller2.put_DefaultBackgroundColor', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2controller2?view=webview2-1.0.2210.55#put_defaultbackgroundcolor') ]) bool? transparentBackground; @@ -323,8 +345,15 @@ because there isn't any way to make the website data store non-persistent for th bool? disableHorizontalScroll; ///Set to `true` to disable context menu. The default value is `false`. - @SupportedPlatforms( - platforms: [AndroidPlatform(), IOSPlatform(), WebPlatform()]) + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + WebPlatform(), + WindowsPlatform( + apiName: "ICoreWebView2Settings.put_AreDefaultContextMenusEnabled", + apiUrl: + "https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_aredefaultcontextmenusenabled") + ]) bool? disableContextMenu; ///Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`. @@ -334,7 +363,11 @@ because there isn't any way to make the website data store non-persistent for th apiUrl: "https://developer.android.com/reference/android/webkit/WebSettings?hl=en#setSupportZoom(boolean)"), IOSPlatform(), - MacOSPlatform() + MacOSPlatform(), + WindowsPlatform( + apiName: "ICoreWebView2Settings.put_IsZoomControlEnabled", + apiUrl: + "https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_iszoomcontrolenabled") ]) bool? supportZoom; @@ -591,7 +624,16 @@ because there isn't any way to make the website data store non-persistent for th ]) String? fixedFontFamily; + ///Use [algorithmicDarkeningAllowed] instead. + /// ///Set the force dark mode for this WebView. The default value is [ForceDark.OFF]. + /// + ///Deprecated - The "force dark" model previously implemented by WebView was complex and didn't + ///interoperate well with current Web standards for `prefers-color-scheme` and `color-scheme`. + ///In apps with `targetSdkVersion` ≥ `android.os.Build.VERSION_CODES.TIRAMISU` this API is a no-op and + ///WebView will always use the dark style defined by web content authors if the app's theme is dark. + ///To customize the behavior, refer to [algorithmicDarkeningAllowed]. + @Deprecated("Use algorithmicDarkeningAllowed instead") @SupportedPlatforms(platforms: [ AndroidPlatform( available: "29", @@ -601,10 +643,17 @@ because there isn't any way to make the website data store non-persistent for th ]) ForceDark_? forceDark; - ///Sets whether Geolocation API is enabled. The default value is `true`. - + ///Use [algorithmicDarkeningAllowed] instead. + /// ///Set how WebView content should be darkened. ///The default value is [ForceDarkStrategy.PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING]. + /// + ///Deprecated - The "force dark" model previously implemented by WebView was complex and didn't + ///interoperate well with current Web standards for `prefers-color-scheme` and `color-scheme`. + ///In apps with `targetSdkVersion` ≥ `android.os.Build.VERSION_CODES.TIRAMISU` this API is a no-op and + ///WebView will always use the dark style defined by web content authors if the app's theme is dark. + ///To customize the behavior, refer to [algorithmicDarkeningAllowed]. + @Deprecated("Use algorithmicDarkeningAllowed instead") @SupportedPlatforms(platforms: [ AndroidPlatform( apiName: "WebSettingsCompat.setForceDarkStrategy", @@ -778,8 +827,8 @@ because there isn't any way to make the website data store non-persistent for th @SupportedPlatforms(platforms: [AndroidPlatform()]) String? regexToCancelSubFramesLoading; - ///Regular expression used by [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event to cancel navigation requests - ///If the url request not matches the regular expression, then the shouldOverrideUrlLoading is return false. + ///Regular expression used by [PlatformWebViewCreationParams.shouldOverrideUrlLoading] event to cancel navigation requests. + ///If the url request doesn't match the regular expression, then the request is canceled. @SupportedPlatforms(platforms: [AndroidPlatform()]) String? regexToCancelOverrideUrlLoading; @@ -1543,7 +1592,11 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri available: "13.3", apiName: "WKWebView.isInspectable", apiUrl: - "https://developer.apple.com/documentation/webkit/wkwebview/4111163-isinspectable") + "https://developer.apple.com/documentation/webkit/wkwebview/4111163-isinspectable"), + WindowsPlatform( + apiName: "ICoreWebView2Settings.put_AreDevToolsEnabled", + apiUrl: + "https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.2210.55#put_aredevtoolsenabled") ]) bool? isInspectable; @@ -1564,6 +1617,139 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri ]) bool? shouldPrintBackgrounds; + ///A [Set] of Regular Expression Patterns that will be used on native side to match the allowed origins + ///that are able to execute the JavaScript Handlers defined for the current WebView. + ///This will affect also the internal JavaScript Handlers used by the plugin itself. + /// + ///An empty [Set] will block every origin. + /// + ///The default value is `null` and will allow every origin. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + Set? javaScriptHandlersOriginAllowList; + + ///Set to `true` to allow to execute the JavaScript Handlers only on the main frame. + ///This will affect also the internal JavaScript Handlers used by the plugin itself. + ///The default value is `false`. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + bool? javaScriptHandlersForMainFrameOnly; + + ///Set to `false` to disable the JavaScript Bridge completely. + ///This will affect also all the internal plugin [UserScript]s + ///that are using the JavaScript Bridge to work. + /// + ///**NOTE**: setting or changing this value after the WebView has been created won't have any effect. + ///It should be set when initializing the WebView through [PlatformWebViewCreationParams.initialSettings] parameter. + /// + ///The default value is `true`. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + bool? javaScriptBridgeEnabled; + + ///A [Set] of patterns that will be used to match the allowed origins where + ///the JavaScript Bridge could be used. + ///If [pluginScriptsOriginAllowList] is present, then this value will override + ///it only for the JavaScript Bridge internal plugin. + ///Adding `'*'` as an allowed origin or setting this to `null`, it means it will allow every origin. + ///Instead, an empty [Set] will block every origin and, in this case, + ///it will force the behaviour of the [javaScriptBridgeEnabled] parameter, + ///as it was set to `false`. + /// + ///**NOTE**: setting or changing this value after the WebView has been created won't have any effect. + ///It should be set when initializing the WebView through [PlatformWebViewCreationParams.initialSettings] parameter. + /// + ///**NOTE for Android**: each origin pattern MUST follow the table rule of [PlatformInAppWebViewController.addWebMessageListener]. + /// + ///**NOTE for iOS, macOS, Windows**: each origin pattern will be used as a + ///Regular Expression Pattern that will be used on JavaScript side using [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp). + /// + ///The default value is `null` and will allow every origin. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + Set? javaScriptBridgeOriginAllowList; + + ///Set to `true` to allow the JavaScript Bridge only on the main frame. + ///If [pluginScriptsForMainFrameOnly] is present, then this value will override + ///it only for the JavaScript Bridge internal plugin. + /// + ///**NOTE**: setting or changing this value after the WebView has been created won't have any effect. + ///It should be set when initializing the WebView through [PlatformWebViewCreationParams.initialSettings] parameter. + /// + ///The default value is `false`. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + bool? javaScriptBridgeForMainFrameOnly; + + ///A [Set] of patterns that will be used to match the allowed origins + ///that are able to load all the internal plugin [UserScript]s used by the plugin itself. + ///Adding `'*'` as an allowed origin or setting this to `null`, it means it will allow every origin. + ///Instead, an empty [Set] will block every origin. + /// + ///**NOTE**: If [javaScriptBridgeOriginAllowList] is not present, this value will affect also the JavaScript Bridge internal plugin. + ///Also, setting or changing this value after the WebView has been created won't have any effect. + ///It should be set when initializing the WebView through [PlatformWebViewCreationParams.initialSettings] parameter. + /// + ///**NOTE for Android**: each origin pattern MUST follow the table rule of [PlatformInAppWebViewController.addWebMessageListener]. + /// + ///**NOTE for iOS, macOS, Windows**: each origin pattern will be used as a + ///Regular Expression Pattern that will be used on JavaScript side using [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp). + /// + ///The default value is `null` and will allow every origin. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + Set? pluginScriptsOriginAllowList; + + ///Set to `true` to allow internal plugin [UserScript]s only on the main frame. + /// + ///**NOTE**: If [javaScriptBridgeForMainFrameOnly] is not present, this value will affect also the JavaScript Bridge internal plugin. + ///Also, setting or changing this value after the WebView has been created won't have any effect. + ///It should be set when initializing the WebView through [PlatformWebViewCreationParams.initialSettings] parameter. + /// + ///The default value is `false`. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) + bool? pluginScriptsForMainFrameOnly; + + ///The multiplier applied to the scroll amount for the WebView. + /// + ///This value determines how much the content will scroll in response to user input. + ///A higher value means faster scrolling, while a lower value means slower scrolling. + /// + ///The default value is `1`. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + int? scrollMultiplier; + ///Specifies a feature policy for the `