fix #1905, updated useShouldInterceptAjaxRequest automatic infer logic

This commit is contained in:
Lorenzo Pichilli 2023-12-07 16:59:30 +01:00
parent 2a4313dc50
commit e60fe1740a
32 changed files with 402 additions and 161 deletions

View File

@ -10,11 +10,11 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
build: 2.3.1 build: ^2.4.0
source_gen: ^1.3.1 source_gen: ^1.3.1
flutter_inappwebview_internal_annotations: ^1.1.1 flutter_inappwebview_internal_annotations: ^1.1.1
dev_dependencies: dev_dependencies:
build_runner: 2.3.3 build_runner: ^2.4.0
build_test: ^2.1.7 build_test: ^2.1.7
test: ^1.24.2 test: ^1.24.2

View File

@ -1,3 +1,8 @@
## 6.0.0-beta.32
- Updated minimum platform interface and implementation versions
- Added `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests` [#1905](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1905)
## 6.0.0-beta.31 ## 6.0.0-beta.31
- Updated minimum platform interface and implementation versions - Updated minimum platform interface and implementation versions

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview 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. 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.0.0-beta.31 version: 6.0.0-beta.32
homepage: https://inappwebview.dev/ homepage: https://inappwebview.dev/
repository: https://github.com/pichillilorenzo/flutter_inappwebview repository: https://github.com/pichillilorenzo/flutter_inappwebview
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
@ -22,7 +22,7 @@ dependencies:
flutter_inappwebview_android: ^1.0.5 flutter_inappwebview_android: ^1.0.5
flutter_inappwebview_ios: ^1.0.5 flutter_inappwebview_ios: ^1.0.5
flutter_inappwebview_macos: ^1.0.3 flutter_inappwebview_macos: ^1.0.3
flutter_inappwebview_web: ^1.0.2 flutter_inappwebview_web: ^1.0.3
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -30,7 +30,7 @@ dev_dependencies:
flutter_driver: flutter_driver:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.1 flutter_lints: ^2.0.1
build_runner: 2.3.3 build_runner: ^2.4.0
generators: generators:
path: ../dev_packages/generators path: ../dev_packages/generators

View File

@ -1,3 +1,8 @@
## 1.0.8
- Implemented `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests`
- Updated `useShouldInterceptAjaxRequest` automatic infer logic
## 1.0.7 ## 1.0.7
- Merged "Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property'" [#1904](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1904) (thanks to [EArminjon](https://github.com/EArminjon)) - Merged "Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property'" [#1904](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1904) (thanks to [EArminjon](https://github.com/EArminjon))

View File

@ -7,6 +7,7 @@ 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 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_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( 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_PLUGIN_SCRIPT_GROUP_NAME,
InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_SOURCE, InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_SOURCE,
@ -16,6 +17,17 @@ public class InterceptAjaxRequestJS {
null null
); );
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 +";",
UserScriptInjectionTime.AT_DOCUMENT_START,
null,
true,
null
);
}
public static final String INTERCEPT_AJAX_REQUEST_JS_SOURCE = "(function(ajax) {" + public static final String INTERCEPT_AJAX_REQUEST_JS_SOURCE = "(function(ajax) {" +
" var w = (window.top == null || window.top === window) ? window : window.top;" + " var w = (window.top == null || window.top === window) ? window : window.top;" +
" w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " = true;" + " w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " = true;" +
@ -122,7 +134,8 @@ public class InterceptAjaxRequestJS {
" ajax.prototype.send = function(data) {" + " ajax.prototype.send = function(data) {" +
" var self = this;" + " var self = this;" +
" var w = (window.top == null || window.top === window) ? window : window.top;" + " 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 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) {" + " if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) {" +
" this._flutter_inappwebview_already_onreadystatechange_wrapped = true;" + " this._flutter_inappwebview_already_onreadystatechange_wrapped = true;" +
" var onreadystatechange = this.onreadystatechange;" + " var onreadystatechange = this.onreadystatechange;" +
@ -220,7 +233,7 @@ public class InterceptAjaxRequestJS {
" data = new Uint8Array(result.data);" + " data = new Uint8Array(result.data);" +
" }" + " }" +
" self.withCredentials = result.withCredentials;" + " self.withCredentials = result.withCredentials;" +
" if (result.responseType != null && self.isAsync) {" + " if (result.responseType != null && self._flutter_inappwebview_isAsync) {" +
" self.responseType = result.responseType;" + " self.responseType = result.responseType;" +
" };" + " };" +
" for (var header in result.headers) {" + " for (var header in result.headers) {" +

View File

@ -174,6 +174,9 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@Nullable @Nullable
public WebViewAssetLoaderExt webViewAssetLoaderExt; public WebViewAssetLoaderExt webViewAssetLoaderExt;
@Nullable
private PluginScript interceptOnlyAsyncAjaxRequestsPluginScript;
public InAppWebView(Context context) { public InAppWebView(Context context) {
super(context); super(context);
} }
@ -565,7 +568,9 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT); userContentController.addPluginScript(PrintJS.PRINT_JS_PLUGIN_SCRIPT);
userContentController.addPluginScript(OnWindowBlurEventJS.ON_WINDOW_BLUR_EVENT_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(OnWindowFocusEventJS.ON_WINDOW_FOCUS_EVENT_JS_PLUGIN_SCRIPT);
interceptOnlyAsyncAjaxRequestsPluginScript = InterceptAjaxRequestJS.createInterceptOnlyAsyncAjaxRequestsPluginScript(customSettings.interceptOnlyAsyncAjaxRequests);
if (customSettings.useShouldInterceptAjaxRequest) { if (customSettings.useShouldInterceptAjaxRequest) {
userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript);
userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT); userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT);
} }
if (customSettings.useShouldInterceptFetchRequest) { if (customSettings.useShouldInterceptFetchRequest) {
@ -772,6 +777,14 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
); );
} }
if (newSettingsMap.get("interceptOnlyAsyncAjaxRequests") != null && customSettings.interceptOnlyAsyncAjaxRequests != newCustomSettings.interceptOnlyAsyncAjaxRequests) {
enablePluginScriptAtRuntime(
InterceptAjaxRequestJS.FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE,
newCustomSettings.interceptOnlyAsyncAjaxRequests,
interceptOnlyAsyncAjaxRequestsPluginScript
);
}
if (newSettingsMap.get("useShouldInterceptFetchRequest") != null && customSettings.useShouldInterceptFetchRequest != newCustomSettings.useShouldInterceptFetchRequest) { if (newSettingsMap.get("useShouldInterceptFetchRequest") != null && customSettings.useShouldInterceptFetchRequest != newCustomSettings.useShouldInterceptFetchRequest) {
enablePluginScriptAtRuntime( enablePluginScriptAtRuntime(
InterceptFetchRequestJS.FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE, InterceptFetchRequestJS.FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE,
@ -2030,6 +2043,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
destroy(); destroy();
} }
}); });
interceptOnlyAsyncAjaxRequestsPluginScript = null;
userContentController.dispose(); userContentController.dispose();
if (findInteractionController != null) { if (findInteractionController != null) {
findInteractionController.dispose(); findInteractionController.dispose();

View File

@ -44,6 +44,7 @@ public class InAppWebViewSettings implements ISettings<InAppWebViewInterface> {
public List<Map<String, Map<String, Object>>> contentBlockers = new ArrayList<>(); public List<Map<String, Map<String, Object>>> contentBlockers = new ArrayList<>();
public Integer preferredContentMode = PreferredContentModeOptionType.RECOMMENDED.toValue(); public Integer preferredContentMode = PreferredContentModeOptionType.RECOMMENDED.toValue();
public Boolean useShouldInterceptAjaxRequest = false; public Boolean useShouldInterceptAjaxRequest = false;
public Boolean interceptOnlyAsyncAjaxRequests = true;
public Boolean useShouldInterceptFetchRequest = false; public Boolean useShouldInterceptFetchRequest = false;
public Boolean incognito = false; public Boolean incognito = false;
public Boolean cacheEnabled = true; public Boolean cacheEnabled = true;
@ -184,6 +185,9 @@ public class InAppWebViewSettings implements ISettings<InAppWebViewInterface> {
case "useShouldInterceptAjaxRequest": case "useShouldInterceptAjaxRequest":
useShouldInterceptAjaxRequest = (Boolean) value; useShouldInterceptAjaxRequest = (Boolean) value;
break; break;
case "interceptOnlyAsyncAjaxRequests":
interceptOnlyAsyncAjaxRequests = (Boolean) value;
break;
case "useShouldInterceptFetchRequest": case "useShouldInterceptFetchRequest":
useShouldInterceptFetchRequest = (Boolean) value; useShouldInterceptFetchRequest = (Boolean) value;
break; break;
@ -426,6 +430,7 @@ public class InAppWebViewSettings implements ISettings<InAppWebViewInterface> {
settings.put("contentBlockers", contentBlockers); settings.put("contentBlockers", contentBlockers);
settings.put("preferredContentMode", preferredContentMode); settings.put("preferredContentMode", preferredContentMode);
settings.put("useShouldInterceptAjaxRequest", useShouldInterceptAjaxRequest); settings.put("useShouldInterceptAjaxRequest", useShouldInterceptAjaxRequest);
settings.put("interceptOnlyAsyncAjaxRequests", interceptOnlyAsyncAjaxRequests);
settings.put("useShouldInterceptFetchRequest", useShouldInterceptFetchRequest); settings.put("useShouldInterceptFetchRequest", useShouldInterceptFetchRequest);
settings.put("incognito", incognito); settings.put("incognito", incognito);
settings.put("cacheEnabled", cacheEnabled); settings.put("cacheEnabled", cacheEnabled);

View File

@ -281,43 +281,41 @@ class AndroidInAppWebViewWidget extends PlatformInAppWebViewWidget {
AndroidInAppWebViewController? _controller; AndroidInAppWebViewController? _controller;
AndroidHeadlessInAppWebView? get _androidHeadlessInAppWebView => AndroidHeadlessInAppWebView? get _androidHeadlessInAppWebView =>
_androidParams.headlessWebView as AndroidHeadlessInAppWebView?; params.headlessWebView as AndroidHeadlessInAppWebView?;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final initialSettings = final initialSettings = params.initialSettings ?? InAppWebViewSettings();
_androidParams.initialSettings ?? InAppWebViewSettings();
_inferInitialSettings(initialSettings); _inferInitialSettings(initialSettings);
Map<String, dynamic> settingsMap = (_androidParams.initialSettings != null Map<String, dynamic> settingsMap =
? initialSettings.toMap() (params.initialSettings != null ? initialSettings.toMap() : null) ??
: null) ??
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
_androidParams.initialOptions?.toMap() ?? params.initialOptions?.toMap() ??
initialSettings.toMap(); initialSettings.toMap();
Map<String, dynamic> pullToRefreshSettings = Map<String, dynamic> pullToRefreshSettings =
_androidParams.pullToRefreshController?.params.settings.toMap() ?? params.pullToRefreshController?.params.settings.toMap() ??
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
_androidParams.pullToRefreshController?.params.options.toMap() ?? params.pullToRefreshController?.params.options.toMap() ??
PullToRefreshSettings(enabled: false).toMap(); PullToRefreshSettings(enabled: false).toMap();
if ((_androidParams.headlessWebView?.isRunning() ?? false) && if ((params.headlessWebView?.isRunning() ?? false) &&
_androidParams.keepAlive != null) { params.keepAlive != null) {
final headlessId = _androidParams.headlessWebView?.id; final headlessId = params.headlessWebView?.id;
if (headlessId != null) { if (headlessId != null) {
// force keep alive id to match headless webview id // force keep alive id to match headless webview id
_androidParams.keepAlive?.id = headlessId; params.keepAlive?.id = headlessId;
} }
} }
var useHybridComposition = (_androidParams.initialSettings != null var useHybridComposition = (params.initialSettings != null
? initialSettings.useHybridComposition ? initialSettings.useHybridComposition
: _androidParams.initialOptions?.android.useHybridComposition) ?? : params.initialOptions?.android.useHybridComposition) ??
true; true;
return PlatformViewLink( return PlatformViewLink(
key: _androidParams.key, key: params.key,
viewType: 'com.pichillilorenzo/flutter_inappwebview', viewType: 'com.pichillilorenzo/flutter_inappwebview',
surfaceFactory: ( surfaceFactory: (
BuildContext context, BuildContext context,
@ -325,7 +323,7 @@ class AndroidInAppWebViewWidget extends PlatformInAppWebViewWidget {
) { ) {
return AndroidViewSurface( return AndroidViewSurface(
controller: controller as AndroidViewController, controller: controller as AndroidViewController,
gestureRecognizers: _androidParams.gestureRecognizers ?? gestureRecognizers: params.gestureRecognizers ??
const <Factory<OneSequenceGestureRecognizer>>{}, const <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque, hitTestBehavior: PlatformViewHitTestBehavior.opaque,
); );
@ -335,26 +333,28 @@ class AndroidInAppWebViewWidget extends PlatformInAppWebViewWidget {
hybridComposition: useHybridComposition, hybridComposition: useHybridComposition,
id: params.id, id: params.id,
viewType: 'com.pichillilorenzo/flutter_inappwebview', viewType: 'com.pichillilorenzo/flutter_inappwebview',
layoutDirection: _androidParams.layoutDirection ?? layoutDirection: this.params.layoutDirection ??
Directionality.maybeOf(context) ?? Directionality.maybeOf(context) ??
TextDirection.rtl, TextDirection.rtl,
creationParams: <String, dynamic>{ creationParams: <String, dynamic>{
'initialUrlRequest': _androidParams.initialUrlRequest?.toMap(), 'initialUrlRequest': this.params.initialUrlRequest?.toMap(),
'initialFile': _androidParams.initialFile, 'initialFile': this.params.initialFile,
'initialData': _androidParams.initialData?.toMap(), 'initialData': this.params.initialData?.toMap(),
'initialSettings': settingsMap, 'initialSettings': settingsMap,
'contextMenu': _androidParams.contextMenu?.toMap() ?? {}, 'contextMenu': this.params.contextMenu?.toMap() ?? {},
'windowId': _androidParams.windowId, 'windowId': this.params.windowId,
'headlessWebViewId': 'headlessWebViewId':
_androidParams.headlessWebView?.isRunning() ?? false this.params.headlessWebView?.isRunning() ?? false
? _androidParams.headlessWebView?.id ? this.params.headlessWebView?.id
: null, : null,
'initialUserScripts': _androidParams.initialUserScripts 'initialUserScripts': this
.params
.initialUserScripts
?.map((e) => e.toMap()) ?.map((e) => e.toMap())
.toList() ?? .toList() ??
[], [],
'pullToRefreshSettings': pullToRefreshSettings, 'pullToRefreshSettings': pullToRefreshSettings,
'keepAliveId': _androidParams.keepAlive?.id 'keepAliveId': this.params.keepAlive?.id
}, },
) )
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
@ -391,10 +391,10 @@ class AndroidInAppWebViewWidget extends PlatformInAppWebViewWidget {
void _onPlatformViewCreated(int id) { void _onPlatformViewCreated(int id) {
dynamic viewId = id; dynamic viewId = id;
if (_androidParams.headlessWebView?.isRunning() ?? false) { if (params.headlessWebView?.isRunning() ?? false) {
viewId = _androidParams.headlessWebView?.id; viewId = params.headlessWebView?.id;
} }
viewId = _androidParams.keepAlive?.id ?? viewId ?? id; viewId = params.keepAlive?.id ?? viewId ?? id;
_androidHeadlessInAppWebView?.internalDispose(); _androidHeadlessInAppWebView?.internalDispose();
_controller = AndroidInAppWebViewController( _controller = AndroidInAppWebViewController(
PlatformInAppWebViewControllerCreationParams( PlatformInAppWebViewControllerCreationParams(
@ -408,42 +408,43 @@ class AndroidInAppWebViewWidget extends PlatformInAppWebViewWidget {
PlatformInAppWebViewController.debugLoggingSettings, PlatformInAppWebViewController.debugLoggingSettings,
method: "onWebViewCreated", method: "onWebViewCreated",
args: []); args: []);
if (_androidParams.onWebViewCreated != null) { if (params.onWebViewCreated != null) {
_androidParams.onWebViewCreated!( params.onWebViewCreated!(
params.controllerFromPlatform?.call(_controller!) ?? _controller!); params.controllerFromPlatform?.call(_controller!) ?? _controller!);
} }
} }
void _inferInitialSettings(InAppWebViewSettings settings) { void _inferInitialSettings(InAppWebViewSettings settings) {
if (_androidParams.shouldOverrideUrlLoading != null && if (params.shouldOverrideUrlLoading != null &&
settings.useShouldOverrideUrlLoading == null) { settings.useShouldOverrideUrlLoading == null) {
settings.useShouldOverrideUrlLoading = true; settings.useShouldOverrideUrlLoading = true;
} }
if (_androidParams.onLoadResource != null && if (params.onLoadResource != null && settings.useOnLoadResource == null) {
settings.useOnLoadResource == null) {
settings.useOnLoadResource = true; settings.useOnLoadResource = true;
} }
if (_androidParams.onDownloadStartRequest != null && if (params.onDownloadStartRequest != null &&
settings.useOnDownloadStart == null) { settings.useOnDownloadStart == null) {
settings.useOnDownloadStart = true; settings.useOnDownloadStart = true;
} }
if (_androidParams.shouldInterceptAjaxRequest != null && if ((params.shouldInterceptAjaxRequest != null ||
params.onAjaxProgress != null ||
params.onAjaxReadyStateChange != null) &&
settings.useShouldInterceptAjaxRequest == null) { settings.useShouldInterceptAjaxRequest == null) {
settings.useShouldInterceptAjaxRequest = true; settings.useShouldInterceptAjaxRequest = true;
} }
if (_androidParams.shouldInterceptFetchRequest != null && if (params.shouldInterceptFetchRequest != null &&
settings.useShouldInterceptFetchRequest == null) { settings.useShouldInterceptFetchRequest == null) {
settings.useShouldInterceptFetchRequest = true; settings.useShouldInterceptFetchRequest = true;
} }
if (_androidParams.shouldInterceptRequest != null && if (params.shouldInterceptRequest != null &&
settings.useShouldInterceptRequest == null) { settings.useShouldInterceptRequest == null) {
settings.useShouldInterceptRequest = true; settings.useShouldInterceptRequest = true;
} }
if (_androidParams.onRenderProcessGone != null && if (params.onRenderProcessGone != null &&
settings.useOnRenderProcessGone == null) { settings.useOnRenderProcessGone == null) {
settings.useOnRenderProcessGone = true; settings.useOnRenderProcessGone = true;
} }
if (_androidParams.onNavigationResponse != null && if (params.onNavigationResponse != null &&
settings.useOnNavigationResponse == null) { settings.useOnNavigationResponse == null) {
settings.useOnNavigationResponse = true; settings.useOnNavigationResponse = true;
} }
@ -459,11 +460,11 @@ class AndroidInAppWebViewWidget extends PlatformInAppWebViewWidget {
PlatformInAppWebViewController.debugLoggingSettings, PlatformInAppWebViewController.debugLoggingSettings,
method: "dispose", method: "dispose",
args: []); args: []);
final isKeepAlive = _androidParams.keepAlive != null; final isKeepAlive = params.keepAlive != null;
_controller?.dispose(isKeepAlive: isKeepAlive); _controller?.dispose(isKeepAlive: isKeepAlive);
_controller = null; _controller = null;
_androidParams.pullToRefreshController?.dispose(isKeepAlive: isKeepAlive); params.pullToRefreshController?.dispose(isKeepAlive: isKeepAlive);
_androidParams.findInteractionController?.dispose(isKeepAlive: isKeepAlive); params.findInteractionController?.dispose(isKeepAlive: isKeepAlive);
} }
@override @override

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview_android name: flutter_inappwebview_android
description: Android implementation of the flutter_inappwebview plugin. description: Android implementation of the flutter_inappwebview plugin.
version: 1.0.7 version: 1.0.8
homepage: https://inappwebview.dev/ homepage: https://inappwebview.dev/
repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_android repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_android
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
@ -18,7 +18,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_inappwebview_platform_interface: ^1.0.5 flutter_inappwebview_platform_interface: ^1.0.6
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -1,3 +1,8 @@
## 1.0.9
- Implemented `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests`
- Updated `useShouldInterceptAjaxRequest` automatic infer logic
## 1.0.8 ## 1.0.8
- Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property' - Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property'

View File

@ -67,6 +67,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
var oldZoomScale = Float(1.0) var oldZoomScale = Float(1.0)
fileprivate var interceptOnlyAsyncAjaxRequestsPluginScript: PluginScript?
init(id: Any?, plugin: SwiftFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration, init(id: Any?, plugin: SwiftFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration,
contextMenu: [String: Any]?, userScripts: [UserScript] = []) { contextMenu: [String: Any]?, userScripts: [UserScript] = []) {
super.init(frame: frame, configuration: configuration) super.init(frame: frame, configuration: configuration)
@ -562,7 +564,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
configuration.userContentController.addPluginScript(FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT) configuration.userContentController.addPluginScript(FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT)
configuration.userContentController.addPluginScript(ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT) configuration.userContentController.addPluginScript(ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT)
if let settings = settings { if let settings = settings {
interceptOnlyAsyncAjaxRequestsPluginScript = createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: settings.interceptOnlyAsyncAjaxRequests)
if settings.useShouldInterceptAjaxRequest { if settings.useShouldInterceptAjaxRequest {
if let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript {
configuration.userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript)
}
configuration.userContentController.addPluginScript(INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT) configuration.userContentController.addPluginScript(INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT)
} }
if settings.useShouldInterceptFetchRequest { if settings.useShouldInterceptFetchRequest {
@ -1063,7 +1069,16 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
enable: newSettings.useShouldInterceptAjaxRequest, enable: newSettings.useShouldInterceptAjaxRequest,
pluginScript: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT) pluginScript: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT)
} else { } else {
newSettings.useShouldInterceptFetchRequest = false newSettings.useShouldInterceptAjaxRequest = false
}
}
if newSettingsMap["interceptOnlyAsyncAjaxRequests"] != nil && settings?.interceptOnlyAsyncAjaxRequests != newSettings.interceptOnlyAsyncAjaxRequests {
if let applePayAPIEnabled = settings?.applePayAPIEnabled, !applePayAPIEnabled,
let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript {
enablePluginScriptAtRuntime(flagVariable: FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE,
enable: newSettings.interceptOnlyAsyncAjaxRequests,
pluginScript: interceptOnlyAsyncAjaxRequestsPluginScript)
} }
} }
@ -3266,6 +3281,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
webMessageListener.dispose() webMessageListener.dispose()
} }
webMessageListeners.removeAll() webMessageListeners.removeAll()
interceptOnlyAsyncAjaxRequestsPluginScript = nil
if windowId == nil { if windowId == nil {
configuration.userContentController.removeAllPluginScriptMessageHandlers() configuration.userContentController.removeAllPluginScriptMessageHandlers()
configuration.userContentController.removeScriptMessageHandler(forName: "onCallAsyncJavaScriptResultBelowIOS14Received") configuration.userContentController.removeScriptMessageHandler(forName: "onCallAsyncJavaScriptResultBelowIOS14Received")

View File

@ -26,6 +26,7 @@ public class InAppWebViewSettings: ISettings<InAppWebView> {
var contentBlockers: [[String: [String : Any]]] = [] var contentBlockers: [[String: [String : Any]]] = []
var minimumFontSize = 0 var minimumFontSize = 0
var useShouldInterceptAjaxRequest = false var useShouldInterceptAjaxRequest = false
var interceptOnlyAsyncAjaxRequests = true
var useShouldInterceptFetchRequest = false var useShouldInterceptFetchRequest = false
var incognito = false var incognito = false
var cacheEnabled = true var cacheEnabled = true

View File

@ -10,6 +10,8 @@ import Foundation
let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT" let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT"
let FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._useShouldInterceptAjaxRequest" let FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._useShouldInterceptAjaxRequest"
let FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._interceptOnlyAsyncAjaxRequests";
let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = PluginScript( let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = PluginScript(
groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
source: INTERCEPT_AJAX_REQUEST_JS_SOURCE, source: INTERCEPT_AJAX_REQUEST_JS_SOURCE,
@ -18,6 +20,16 @@ let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = PluginScript(
requiredInAllContentWorlds: true, requiredInAllContentWorlds: true,
messageHandlerNames: []) messageHandlerNames: [])
func createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: Bool) -> PluginScript {
return PluginScript(groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
source: "\(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE) = \(onlyAsync);",
injectionTime: .atDocumentStart,
forMainFrameOnly: false,
requiredInAllContentWorlds: true,
messageHandlerNames: []
);
}
let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) = true; \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) = true;
(function(ajax) { (function(ajax) {
@ -122,7 +134,8 @@ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
}; };
ajax.prototype.send = function(data) { ajax.prototype.send = function(data) {
var self = this; var self = this;
if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == true) { var canBeIntercepted = self._flutter_inappwebview_isAsync || \(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE) === false;
if (canBeIntercepted && (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == true)) {
if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) { if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) {
this._flutter_inappwebview_already_onreadystatechange_wrapped = true; this._flutter_inappwebview_already_onreadystatechange_wrapped = true;
var onreadystatechange = this.onreadystatechange; var onreadystatechange = this.onreadystatechange;
@ -219,7 +232,7 @@ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
data = new Uint8Array(result.data); data = new Uint8Array(result.data);
} }
self.withCredentials = result.withCredentials; self.withCredentials = result.withCredentials;
if (result.responseType != null && self.isAsync) { if (result.responseType != null && self._flutter_inappwebview_isAsync) {
self.responseType = result.responseType; self.responseType = result.responseType;
}; };
if (result.headers != null) { if (result.headers != null) {

View File

@ -87,4 +87,23 @@ public class PluginScript : UserScript {
messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames
) )
} }
static func == (lhs: PluginScript, rhs: PluginScript) -> Bool {
if #available(iOS 14.0, *) {
return lhs.groupName == rhs.groupName &&
lhs.source == rhs.source &&
lhs.injectionTime == rhs.injectionTime &&
lhs.isForMainFrameOnly == rhs.isForMainFrameOnly &&
lhs.contentWorld == rhs.contentWorld &&
lhs.requiredInAllContentWorlds == rhs.requiredInAllContentWorlds &&
lhs.messageHandlerNames == rhs.messageHandlerNames
} else {
return lhs.groupName == rhs.groupName &&
lhs.source == rhs.source &&
lhs.injectionTime == rhs.injectionTime &&
lhs.isForMainFrameOnly == rhs.isForMainFrameOnly &&
lhs.requiredInAllContentWorlds == rhs.requiredInAllContentWorlds &&
lhs.messageHandlerNames == rhs.messageHandlerNames
}
}
} }

View File

@ -91,7 +91,7 @@ extension WKUserContentController {
public func sync(scriptMessageHandler: WKScriptMessageHandler) { public func sync(scriptMessageHandler: WKScriptMessageHandler) {
let pluginScriptsList = pluginScripts.compactMap({ $0.value }).joined() let pluginScriptsList = pluginScripts.compactMap({ $0.value }).joined()
for pluginScript in pluginScriptsList { for pluginScript in pluginScriptsList {
if !containsPluginScript(with: pluginScript.groupName!) { if !containsPluginScript(pluginScript: pluginScript) {
addUserScript(pluginScript) addUserScript(pluginScript)
for messageHandlerName in pluginScript.messageHandlerNames { for messageHandlerName in pluginScript.messageHandlerNames {
removeScriptMessageHandler(forName: messageHandlerName) removeScriptMessageHandler(forName: messageHandlerName)
@ -100,8 +100,8 @@ extension WKUserContentController {
} }
if #available(iOS 14.0, *), pluginScript.requiredInAllContentWorlds { if #available(iOS 14.0, *), pluginScript.requiredInAllContentWorlds {
for contentWorld in contentWorlds { for contentWorld in contentWorlds {
if !containsPluginScript(pluginScript: pluginScript, in: contentWorld) {
let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld) let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld)
if !containsPluginScript(with: pluginScriptWithContentWorld.groupName!, in: contentWorld) {
addUserScript(pluginScriptWithContentWorld) addUserScript(pluginScriptWithContentWorld)
for messageHandlerName in pluginScriptWithContentWorld.messageHandlerNames { for messageHandlerName in pluginScriptWithContentWorld.messageHandlerNames {
removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld) removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld)
@ -314,6 +314,16 @@ extension WKUserContentController {
removeUserScripts(scriptsToRemove: scriptsToRemove, shouldAddPreviousScripts: shouldAddPreviousScripts) removeUserScripts(scriptsToRemove: scriptsToRemove, shouldAddPreviousScripts: shouldAddPreviousScripts)
} }
public func containsPluginScript(pluginScript: PluginScript) -> Bool {
let userScripts = useCopyOfUserScripts()
for script in userScripts {
if let script = script as? PluginScript, script == pluginScript {
return true
}
}
return false
}
public func containsPluginScript(with groupName: String) -> Bool { public func containsPluginScript(with groupName: String) -> Bool {
let userScripts = useCopyOfUserScripts() let userScripts = useCopyOfUserScripts()
for script in userScripts { for script in userScripts {
@ -324,6 +334,17 @@ extension WKUserContentController {
return false return false
} }
@available(iOS 14.0, *)
public func containsPluginScript(pluginScript: PluginScript, in contentWorld: WKContentWorld) -> Bool {
let userScripts = useCopyOfUserScripts()
for script in userScripts {
if let script = script as? PluginScript, script == pluginScript, script.contentWorld == contentWorld {
return true
}
}
return false
}
@available(iOS 14.0, *) @available(iOS 14.0, *)
public func containsPluginScript(with groupName: String, in contentWorld: WKContentWorld) -> Bool { public func containsPluginScript(with groupName: String, in contentWorld: WKContentWorld) -> Bool {
let userScripts = useCopyOfUserScripts() let userScripts = useCopyOfUserScripts()

View File

@ -278,54 +278,53 @@ class IOSInAppWebViewWidget extends PlatformInAppWebViewWidget {
IOSInAppWebViewController? _controller; IOSInAppWebViewController? _controller;
IOSHeadlessInAppWebView? get _iosHeadlessInAppWebView => IOSHeadlessInAppWebView? get _iosHeadlessInAppWebView =>
_iosParams.headlessWebView as IOSHeadlessInAppWebView?; params.headlessWebView as IOSHeadlessInAppWebView?;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final initialSettings = final initialSettings = params.initialSettings ?? InAppWebViewSettings();
_iosParams.initialSettings ?? InAppWebViewSettings();
_inferInitialSettings(initialSettings); _inferInitialSettings(initialSettings);
Map<String, dynamic> settingsMap = Map<String, dynamic> settingsMap =
(_iosParams.initialSettings != null ? initialSettings.toMap() : null) ?? (params.initialSettings != null ? initialSettings.toMap() : null) ??
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
_iosParams.initialOptions?.toMap() ?? params.initialOptions?.toMap() ??
initialSettings.toMap(); initialSettings.toMap();
Map<String, dynamic> pullToRefreshSettings = Map<String, dynamic> pullToRefreshSettings =
_iosParams.pullToRefreshController?.params.settings.toMap() ?? params.pullToRefreshController?.params.settings.toMap() ??
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
_iosParams.pullToRefreshController?.params.options.toMap() ?? params.pullToRefreshController?.params.options.toMap() ??
PullToRefreshSettings(enabled: false).toMap(); PullToRefreshSettings(enabled: false).toMap();
if ((_iosParams.headlessWebView?.isRunning() ?? false) && if ((params.headlessWebView?.isRunning() ?? false) &&
_iosParams.keepAlive != null) { params.keepAlive != null) {
final headlessId = _iosParams.headlessWebView?.id; final headlessId = params.headlessWebView?.id;
if (headlessId != null) { if (headlessId != null) {
// force keep alive id to match headless webview id // force keep alive id to match headless webview id
_iosParams.keepAlive?.id = headlessId; params.keepAlive?.id = headlessId;
} }
} }
return UiKitView( return UiKitView(
viewType: 'com.pichillilorenzo/flutter_inappwebview', viewType: 'com.pichillilorenzo/flutter_inappwebview',
onPlatformViewCreated: _onPlatformViewCreated, onPlatformViewCreated: _onPlatformViewCreated,
gestureRecognizers: _iosParams.gestureRecognizers, gestureRecognizers: params.gestureRecognizers,
creationParams: <String, dynamic>{ creationParams: <String, dynamic>{
'initialUrlRequest': _iosParams.initialUrlRequest?.toMap(), 'initialUrlRequest': params.initialUrlRequest?.toMap(),
'initialFile': _iosParams.initialFile, 'initialFile': params.initialFile,
'initialData': _iosParams.initialData?.toMap(), 'initialData': params.initialData?.toMap(),
'initialSettings': settingsMap, 'initialSettings': settingsMap,
'contextMenu': _iosParams.contextMenu?.toMap() ?? {}, 'contextMenu': params.contextMenu?.toMap() ?? {},
'windowId': _iosParams.windowId, 'windowId': params.windowId,
'headlessWebViewId': _iosParams.headlessWebView?.isRunning() ?? false 'headlessWebViewId': params.headlessWebView?.isRunning() ?? false
? _iosParams.headlessWebView?.id ? params.headlessWebView?.id
: null, : null,
'initialUserScripts': 'initialUserScripts':
_iosParams.initialUserScripts?.map((e) => e.toMap()).toList() ?? [], params.initialUserScripts?.map((e) => e.toMap()).toList() ?? [],
'pullToRefreshSettings': pullToRefreshSettings, 'pullToRefreshSettings': pullToRefreshSettings,
'keepAliveId': _iosParams.keepAlive?.id, 'keepAliveId': params.keepAlive?.id,
'preventGestureDelay': _iosParams.preventGestureDelay 'preventGestureDelay': params.preventGestureDelay
}, },
creationParamsCodec: const StandardMessageCodec(), creationParamsCodec: const StandardMessageCodec(),
); );
@ -333,10 +332,10 @@ class IOSInAppWebViewWidget extends PlatformInAppWebViewWidget {
void _onPlatformViewCreated(int id) { void _onPlatformViewCreated(int id) {
dynamic viewId = id; dynamic viewId = id;
if (_iosParams.headlessWebView?.isRunning() ?? false) { if (params.headlessWebView?.isRunning() ?? false) {
viewId = _iosParams.headlessWebView?.id; viewId = params.headlessWebView?.id;
} }
viewId = _iosParams.keepAlive?.id ?? viewId ?? id; viewId = params.keepAlive?.id ?? viewId ?? id;
_iosHeadlessInAppWebView?.internalDispose(); _iosHeadlessInAppWebView?.internalDispose();
_controller = IOSInAppWebViewController( _controller = IOSInAppWebViewController(
PlatformInAppWebViewControllerCreationParams( PlatformInAppWebViewControllerCreationParams(
@ -350,42 +349,43 @@ class IOSInAppWebViewWidget extends PlatformInAppWebViewWidget {
PlatformInAppWebViewController.debugLoggingSettings, PlatformInAppWebViewController.debugLoggingSettings,
method: "onWebViewCreated", method: "onWebViewCreated",
args: []); args: []);
if (_iosParams.onWebViewCreated != null) { if (params.onWebViewCreated != null) {
_iosParams.onWebViewCreated!( params.onWebViewCreated!(
params.controllerFromPlatform?.call(_controller!) ?? _controller!); params.controllerFromPlatform?.call(_controller!) ?? _controller!);
} }
} }
void _inferInitialSettings(InAppWebViewSettings settings) { void _inferInitialSettings(InAppWebViewSettings settings) {
if (_iosParams.shouldOverrideUrlLoading != null && if (params.shouldOverrideUrlLoading != null &&
settings.useShouldOverrideUrlLoading == null) { settings.useShouldOverrideUrlLoading == null) {
settings.useShouldOverrideUrlLoading = true; settings.useShouldOverrideUrlLoading = true;
} }
if (_iosParams.onLoadResource != null && if (params.onLoadResource != null && settings.useOnLoadResource == null) {
settings.useOnLoadResource == null) {
settings.useOnLoadResource = true; settings.useOnLoadResource = true;
} }
if (_iosParams.onDownloadStartRequest != null && if (params.onDownloadStartRequest != null &&
settings.useOnDownloadStart == null) { settings.useOnDownloadStart == null) {
settings.useOnDownloadStart = true; settings.useOnDownloadStart = true;
} }
if (_iosParams.shouldInterceptAjaxRequest != null && if ((params.shouldInterceptAjaxRequest != null ||
params.onAjaxProgress != null ||
params.onAjaxReadyStateChange != null) &&
settings.useShouldInterceptAjaxRequest == null) { settings.useShouldInterceptAjaxRequest == null) {
settings.useShouldInterceptAjaxRequest = true; settings.useShouldInterceptAjaxRequest = true;
} }
if (_iosParams.shouldInterceptFetchRequest != null && if (params.shouldInterceptFetchRequest != null &&
settings.useShouldInterceptFetchRequest == null) { settings.useShouldInterceptFetchRequest == null) {
settings.useShouldInterceptFetchRequest = true; settings.useShouldInterceptFetchRequest = true;
} }
if (_iosParams.shouldInterceptRequest != null && if (params.shouldInterceptRequest != null &&
settings.useShouldInterceptRequest == null) { settings.useShouldInterceptRequest == null) {
settings.useShouldInterceptRequest = true; settings.useShouldInterceptRequest = true;
} }
if (_iosParams.onRenderProcessGone != null && if (params.onRenderProcessGone != null &&
settings.useOnRenderProcessGone == null) { settings.useOnRenderProcessGone == null) {
settings.useOnRenderProcessGone = true; settings.useOnRenderProcessGone = true;
} }
if (_iosParams.onNavigationResponse != null && if (params.onNavigationResponse != null &&
settings.useOnNavigationResponse == null) { settings.useOnNavigationResponse == null) {
settings.useOnNavigationResponse = true; settings.useOnNavigationResponse = true;
} }
@ -401,11 +401,11 @@ class IOSInAppWebViewWidget extends PlatformInAppWebViewWidget {
PlatformInAppWebViewController.debugLoggingSettings, PlatformInAppWebViewController.debugLoggingSettings,
method: "dispose", method: "dispose",
args: []); args: []);
final isKeepAlive = _iosParams.keepAlive != null; final isKeepAlive = params.keepAlive != null;
_controller?.dispose(isKeepAlive: isKeepAlive); _controller?.dispose(isKeepAlive: isKeepAlive);
_controller = null; _controller = null;
_iosParams.pullToRefreshController?.dispose(isKeepAlive: isKeepAlive); params.pullToRefreshController?.dispose(isKeepAlive: isKeepAlive);
_iosParams.findInteractionController?.dispose(isKeepAlive: isKeepAlive); params.findInteractionController?.dispose(isKeepAlive: isKeepAlive);
} }
@override @override

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview_ios name: flutter_inappwebview_ios
description: iOS implementation of the flutter_inappwebview plugin. description: iOS implementation of the flutter_inappwebview plugin.
version: 1.0.8 version: 1.0.9
homepage: https://inappwebview.dev/ homepage: https://inappwebview.dev/
repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_ios repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_ios
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
@ -18,7 +18,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_inappwebview_platform_interface: ^1.0.5 flutter_inappwebview_platform_interface: ^1.0.6
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -1,3 +1,8 @@
## 1.0.7
- Implemented `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests`
- Updated `useShouldInterceptAjaxRequest` automatic infer logic
## 1.0.6 ## 1.0.6
- Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property' - Fixed error in InterceptAjaxRequestJS 'Failed to set responseType property'

View File

@ -272,56 +272,53 @@ class MacOSInAppWebViewWidget extends PlatformInAppWebViewWidget {
MacOSInAppWebViewController? _controller; MacOSInAppWebViewController? _controller;
MacOSHeadlessInAppWebView? get _macosHeadlessInAppWebView => MacOSHeadlessInAppWebView? get _macosHeadlessInAppWebView =>
_macosParams.headlessWebView as MacOSHeadlessInAppWebView?; params.headlessWebView as MacOSHeadlessInAppWebView?;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final initialSettings = final initialSettings = params.initialSettings ?? InAppWebViewSettings();
_macosParams.initialSettings ?? InAppWebViewSettings();
_inferInitialSettings(initialSettings); _inferInitialSettings(initialSettings);
Map<String, dynamic> settingsMap = (_macosParams.initialSettings != null Map<String, dynamic> settingsMap =
? initialSettings.toMap() (params.initialSettings != null ? initialSettings.toMap() : null) ??
: null) ??
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
_macosParams.initialOptions?.toMap() ?? params.initialOptions?.toMap() ??
initialSettings.toMap(); initialSettings.toMap();
Map<String, dynamic> pullToRefreshSettings = Map<String, dynamic> pullToRefreshSettings =
_macosParams.pullToRefreshController?.params.settings.toMap() ?? params.pullToRefreshController?.params.settings.toMap() ??
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
_macosParams.pullToRefreshController?.params.options.toMap() ?? params.pullToRefreshController?.params.options.toMap() ??
PullToRefreshSettings(enabled: false).toMap(); PullToRefreshSettings(enabled: false).toMap();
if ((_macosParams.headlessWebView?.isRunning() ?? false) && if ((params.headlessWebView?.isRunning() ?? false) &&
_macosParams.keepAlive != null) { params.keepAlive != null) {
final headlessId = _macosParams.headlessWebView?.id; final headlessId = params.headlessWebView?.id;
if (headlessId != null) { if (headlessId != null) {
// force keep alive id to match headless webview id // force keep alive id to match headless webview id
_macosParams.keepAlive?.id = headlessId; params.keepAlive?.id = headlessId;
} }
} }
return UiKitView( return UiKitView(
viewType: 'com.pichillilorenzo/flutter_inappwebview', viewType: 'com.pichillilorenzo/flutter_inappwebview',
onPlatformViewCreated: _onPlatformViewCreated, onPlatformViewCreated: _onPlatformViewCreated,
gestureRecognizers: _macosParams.gestureRecognizers, gestureRecognizers: params.gestureRecognizers,
creationParams: <String, dynamic>{ creationParams: <String, dynamic>{
'initialUrlRequest': _macosParams.initialUrlRequest?.toMap(), 'initialUrlRequest': params.initialUrlRequest?.toMap(),
'initialFile': _macosParams.initialFile, 'initialFile': params.initialFile,
'initialData': _macosParams.initialData?.toMap(), 'initialData': params.initialData?.toMap(),
'initialSettings': settingsMap, 'initialSettings': settingsMap,
'contextMenu': _macosParams.contextMenu?.toMap() ?? {}, 'contextMenu': params.contextMenu?.toMap() ?? {},
'windowId': _macosParams.windowId, 'windowId': params.windowId,
'headlessWebViewId': _macosParams.headlessWebView?.isRunning() ?? false 'headlessWebViewId': params.headlessWebView?.isRunning() ?? false
? _macosParams.headlessWebView?.id ? params.headlessWebView?.id
: null, : null,
'initialUserScripts': 'initialUserScripts':
_macosParams.initialUserScripts?.map((e) => e.toMap()).toList() ?? params.initialUserScripts?.map((e) => e.toMap()).toList() ?? [],
[],
'pullToRefreshSettings': pullToRefreshSettings, 'pullToRefreshSettings': pullToRefreshSettings,
'keepAliveId': _macosParams.keepAlive?.id, 'keepAliveId': params.keepAlive?.id,
'preventGestureDelay': _macosParams.preventGestureDelay 'preventGestureDelay': params.preventGestureDelay
}, },
creationParamsCodec: const StandardMessageCodec(), creationParamsCodec: const StandardMessageCodec(),
); );
@ -329,10 +326,10 @@ class MacOSInAppWebViewWidget extends PlatformInAppWebViewWidget {
void _onPlatformViewCreated(int id) { void _onPlatformViewCreated(int id) {
dynamic viewId = id; dynamic viewId = id;
if (_macosParams.headlessWebView?.isRunning() ?? false) { if (params.headlessWebView?.isRunning() ?? false) {
viewId = _macosParams.headlessWebView?.id; viewId = params.headlessWebView?.id;
} }
viewId = _macosParams.keepAlive?.id ?? viewId ?? id; viewId = params.keepAlive?.id ?? viewId ?? id;
_macosHeadlessInAppWebView?.internalDispose(); _macosHeadlessInAppWebView?.internalDispose();
_controller = MacOSInAppWebViewController( _controller = MacOSInAppWebViewController(
PlatformInAppWebViewControllerCreationParams( PlatformInAppWebViewControllerCreationParams(
@ -345,42 +342,43 @@ class MacOSInAppWebViewWidget extends PlatformInAppWebViewWidget {
PlatformInAppWebViewController.debugLoggingSettings, PlatformInAppWebViewController.debugLoggingSettings,
method: "onWebViewCreated", method: "onWebViewCreated",
args: []); args: []);
if (_macosParams.onWebViewCreated != null) { if (params.onWebViewCreated != null) {
_macosParams.onWebViewCreated!( params.onWebViewCreated!(
params.controllerFromPlatform?.call(_controller!) ?? _controller!); params.controllerFromPlatform?.call(_controller!) ?? _controller!);
} }
} }
void _inferInitialSettings(InAppWebViewSettings settings) { void _inferInitialSettings(InAppWebViewSettings settings) {
if (_macosParams.shouldOverrideUrlLoading != null && if (params.shouldOverrideUrlLoading != null &&
settings.useShouldOverrideUrlLoading == null) { settings.useShouldOverrideUrlLoading == null) {
settings.useShouldOverrideUrlLoading = true; settings.useShouldOverrideUrlLoading = true;
} }
if (_macosParams.onLoadResource != null && if (params.onLoadResource != null && settings.useOnLoadResource == null) {
settings.useOnLoadResource == null) {
settings.useOnLoadResource = true; settings.useOnLoadResource = true;
} }
if (_macosParams.onDownloadStartRequest != null && if (params.onDownloadStartRequest != null &&
settings.useOnDownloadStart == null) { settings.useOnDownloadStart == null) {
settings.useOnDownloadStart = true; settings.useOnDownloadStart = true;
} }
if (_macosParams.shouldInterceptAjaxRequest != null && if ((params.shouldInterceptAjaxRequest != null ||
params.onAjaxProgress != null ||
params.onAjaxReadyStateChange != null) &&
settings.useShouldInterceptAjaxRequest == null) { settings.useShouldInterceptAjaxRequest == null) {
settings.useShouldInterceptAjaxRequest = true; settings.useShouldInterceptAjaxRequest = true;
} }
if (_macosParams.shouldInterceptFetchRequest != null && if (params.shouldInterceptFetchRequest != null &&
settings.useShouldInterceptFetchRequest == null) { settings.useShouldInterceptFetchRequest == null) {
settings.useShouldInterceptFetchRequest = true; settings.useShouldInterceptFetchRequest = true;
} }
if (_macosParams.shouldInterceptRequest != null && if (params.shouldInterceptRequest != null &&
settings.useShouldInterceptRequest == null) { settings.useShouldInterceptRequest == null) {
settings.useShouldInterceptRequest = true; settings.useShouldInterceptRequest = true;
} }
if (_macosParams.onRenderProcessGone != null && if (params.onRenderProcessGone != null &&
settings.useOnRenderProcessGone == null) { settings.useOnRenderProcessGone == null) {
settings.useOnRenderProcessGone = true; settings.useOnRenderProcessGone = true;
} }
if (_macosParams.onNavigationResponse != null && if (params.onNavigationResponse != null &&
settings.useOnNavigationResponse == null) { settings.useOnNavigationResponse == null) {
settings.useOnNavigationResponse = true; settings.useOnNavigationResponse = true;
} }
@ -396,11 +394,10 @@ class MacOSInAppWebViewWidget extends PlatformInAppWebViewWidget {
PlatformInAppWebViewController.debugLoggingSettings, PlatformInAppWebViewController.debugLoggingSettings,
method: "dispose", method: "dispose",
args: []); args: []);
final isKeepAlive = _macosParams.keepAlive != null; final isKeepAlive = params.keepAlive != null;
_controller?.dispose(isKeepAlive: isKeepAlive); _controller?.dispose(isKeepAlive: isKeepAlive);
_controller = null; _controller = null;
_macosParams.pullToRefreshController?.dispose(isKeepAlive: isKeepAlive); params.findInteractionController?.dispose(isKeepAlive: isKeepAlive);
_macosParams.findInteractionController?.dispose(isKeepAlive: isKeepAlive);
} }
@override @override

View File

@ -48,6 +48,8 @@ public class InAppWebView: WKWebView, WKUIDelegate,
var currentOpenPanel: NSOpenPanel? var currentOpenPanel: NSOpenPanel?
fileprivate var interceptOnlyAsyncAjaxRequestsPluginScript: PluginScript?
init(id: Any?, plugin: InAppWebViewFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration, init(id: Any?, plugin: InAppWebViewFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration,
userScripts: [UserScript] = []) { userScripts: [UserScript] = []) {
super.init(frame: frame, configuration: configuration) super.init(frame: frame, configuration: configuration)
@ -209,7 +211,11 @@ public class InAppWebView: WKWebView, WKUIDelegate,
configuration.userContentController.addPluginScript(ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT) configuration.userContentController.addPluginScript(ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT)
configuration.userContentController.addPluginScript(ON_SCROLL_CHANGED_EVENT_JS_PLUGIN_SCRIPT) configuration.userContentController.addPluginScript(ON_SCROLL_CHANGED_EVENT_JS_PLUGIN_SCRIPT)
if let settings = settings { if let settings = settings {
interceptOnlyAsyncAjaxRequestsPluginScript = createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: settings.interceptOnlyAsyncAjaxRequests)
if settings.useShouldInterceptAjaxRequest { if settings.useShouldInterceptAjaxRequest {
if let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript {
configuration.userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript)
}
configuration.userContentController.addPluginScript(INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT) configuration.userContentController.addPluginScript(INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT)
} }
if settings.useShouldInterceptFetchRequest { if settings.useShouldInterceptFetchRequest {
@ -598,7 +604,16 @@ public class InAppWebView: WKWebView, WKUIDelegate,
enable: newSettings.useShouldInterceptAjaxRequest, enable: newSettings.useShouldInterceptAjaxRequest,
pluginScript: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT) pluginScript: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT)
} else { } else {
newSettings.useShouldInterceptFetchRequest = false newSettings.useShouldInterceptAjaxRequest = false
}
}
if newSettingsMap["interceptOnlyAsyncAjaxRequests"] != nil && settings?.interceptOnlyAsyncAjaxRequests != newSettings.interceptOnlyAsyncAjaxRequests {
if let applePayAPIEnabled = settings?.applePayAPIEnabled, !applePayAPIEnabled,
let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript {
enablePluginScriptAtRuntime(flagVariable: FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE,
enable: newSettings.interceptOnlyAsyncAjaxRequests,
pluginScript: interceptOnlyAsyncAjaxRequestsPluginScript)
} }
} }
@ -2606,6 +2621,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
webMessageListener.dispose() webMessageListener.dispose()
} }
webMessageListeners.removeAll() webMessageListeners.removeAll()
interceptOnlyAsyncAjaxRequestsPluginScript = nil
if windowId == nil { if windowId == nil {
configuration.userContentController.removeAllPluginScriptMessageHandlers() configuration.userContentController.removeAllPluginScriptMessageHandlers()
configuration.userContentController.removeScriptMessageHandler(forName: "onCallAsyncJavaScriptResultBelowIOS14Received") configuration.userContentController.removeScriptMessageHandler(forName: "onCallAsyncJavaScriptResultBelowIOS14Received")

View File

@ -24,6 +24,7 @@ public class InAppWebViewSettings: ISettings<InAppWebView> {
var contentBlockers: [[String: [String : Any]]] = [] var contentBlockers: [[String: [String : Any]]] = []
var minimumFontSize = 0 var minimumFontSize = 0
var useShouldInterceptAjaxRequest = false var useShouldInterceptAjaxRequest = false
var interceptOnlyAsyncAjaxRequests = true
var useShouldInterceptFetchRequest = false var useShouldInterceptFetchRequest = false
var incognito = false var incognito = false
var cacheEnabled = true var cacheEnabled = true

View File

@ -10,6 +10,9 @@ import Foundation
let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT" let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT"
let FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._useShouldInterceptAjaxRequest" let FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._useShouldInterceptAjaxRequest"
let FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._interceptOnlyAsyncAjaxRequests";
let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = PluginScript( let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = PluginScript(
groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME, groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
source: INTERCEPT_AJAX_REQUEST_JS_SOURCE, source: INTERCEPT_AJAX_REQUEST_JS_SOURCE,
@ -18,6 +21,16 @@ let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = PluginScript(
requiredInAllContentWorlds: true, requiredInAllContentWorlds: true,
messageHandlerNames: []) messageHandlerNames: [])
func createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: Bool) -> PluginScript {
return PluginScript(groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
source: "\(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE) = \(onlyAsync);",
injectionTime: .atDocumentStart,
forMainFrameOnly: false,
requiredInAllContentWorlds: true,
messageHandlerNames: []
);
}
let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) = true; \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) = true;
(function(ajax) { (function(ajax) {
@ -122,7 +135,8 @@ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
}; };
ajax.prototype.send = function(data) { ajax.prototype.send = function(data) {
var self = this; var self = this;
if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == true) { var canBeIntercepted = self._flutter_inappwebview_isAsync || \(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE) === false;
if (canBeIntercepted && (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == true)) {
if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) { if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) {
this._flutter_inappwebview_already_onreadystatechange_wrapped = true; this._flutter_inappwebview_already_onreadystatechange_wrapped = true;
var onreadystatechange = this.onreadystatechange; var onreadystatechange = this.onreadystatechange;
@ -219,7 +233,7 @@ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
data = new Uint8Array(result.data); data = new Uint8Array(result.data);
} }
self.withCredentials = result.withCredentials; self.withCredentials = result.withCredentials;
if (result.responseType != null && self.isAsync) { if (result.responseType != null && self._flutter_inappwebview_isAsync) {
self.responseType = result.responseType; self.responseType = result.responseType;
}; };
if (result.headers != null) { if (result.headers != null) {

View File

@ -87,4 +87,23 @@ public class PluginScript : UserScript {
messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames messageHandlerNames: messageHandlerNames ?? self.messageHandlerNames
) )
} }
static func == (lhs: PluginScript, rhs: PluginScript) -> Bool {
if #available(macOS 11.0, *) {
return lhs.groupName == rhs.groupName &&
lhs.source == rhs.source &&
lhs.injectionTime == rhs.injectionTime &&
lhs.isForMainFrameOnly == rhs.isForMainFrameOnly &&
lhs.contentWorld == rhs.contentWorld &&
lhs.requiredInAllContentWorlds == rhs.requiredInAllContentWorlds &&
lhs.messageHandlerNames == rhs.messageHandlerNames
} else {
return lhs.groupName == rhs.groupName &&
lhs.source == rhs.source &&
lhs.injectionTime == rhs.injectionTime &&
lhs.isForMainFrameOnly == rhs.isForMainFrameOnly &&
lhs.requiredInAllContentWorlds == rhs.requiredInAllContentWorlds &&
lhs.messageHandlerNames == rhs.messageHandlerNames
}
}
} }

View File

@ -91,7 +91,7 @@ extension WKUserContentController {
public func sync(scriptMessageHandler: WKScriptMessageHandler) { public func sync(scriptMessageHandler: WKScriptMessageHandler) {
let pluginScriptsList = pluginScripts.compactMap({ $0.value }).joined() let pluginScriptsList = pluginScripts.compactMap({ $0.value }).joined()
for pluginScript in pluginScriptsList { for pluginScript in pluginScriptsList {
if !containsPluginScript(with: pluginScript.groupName!) { if !containsPluginScript(pluginScript: pluginScript) {
addUserScript(pluginScript) addUserScript(pluginScript)
for messageHandlerName in pluginScript.messageHandlerNames { for messageHandlerName in pluginScript.messageHandlerNames {
removeScriptMessageHandler(forName: messageHandlerName) removeScriptMessageHandler(forName: messageHandlerName)
@ -100,8 +100,8 @@ extension WKUserContentController {
} }
if #available(macOS 11.0, *), pluginScript.requiredInAllContentWorlds { if #available(macOS 11.0, *), pluginScript.requiredInAllContentWorlds {
for contentWorld in contentWorlds { for contentWorld in contentWorlds {
if !containsPluginScript(pluginScript: pluginScript, in: contentWorld) {
let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld) let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld)
if !containsPluginScript(with: pluginScriptWithContentWorld.groupName!, in: contentWorld) {
addUserScript(pluginScriptWithContentWorld) addUserScript(pluginScriptWithContentWorld)
for messageHandlerName in pluginScriptWithContentWorld.messageHandlerNames { for messageHandlerName in pluginScriptWithContentWorld.messageHandlerNames {
removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld) removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld)
@ -314,6 +314,16 @@ extension WKUserContentController {
removeUserScripts(scriptsToRemove: scriptsToRemove, shouldAddPreviousScripts: shouldAddPreviousScripts) removeUserScripts(scriptsToRemove: scriptsToRemove, shouldAddPreviousScripts: shouldAddPreviousScripts)
} }
public func containsPluginScript(pluginScript: PluginScript) -> Bool {
let userScripts = useCopyOfUserScripts()
for script in userScripts {
if let script = script as? PluginScript, script == pluginScript {
return true
}
}
return false
}
public func containsPluginScript(with groupName: String) -> Bool { public func containsPluginScript(with groupName: String) -> Bool {
let userScripts = useCopyOfUserScripts() let userScripts = useCopyOfUserScripts()
for script in userScripts { for script in userScripts {
@ -324,6 +334,17 @@ extension WKUserContentController {
return false return false
} }
@available(macOS 11.0, *)
public func containsPluginScript(pluginScript: PluginScript, in contentWorld: WKContentWorld) -> Bool {
let userScripts = useCopyOfUserScripts()
for script in userScripts {
if let script = script as? PluginScript, script == pluginScript, script.contentWorld == contentWorld {
return true
}
}
return false
}
@available(macOS 11.0, *) @available(macOS 11.0, *)
public func containsPluginScript(with groupName: String, in contentWorld: WKContentWorld) -> Bool { public func containsPluginScript(with groupName: String, in contentWorld: WKContentWorld) -> Bool {
let userScripts = useCopyOfUserScripts() let userScripts = useCopyOfUserScripts()

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview_macos name: flutter_inappwebview_macos
description: macOS implementation of the flutter_inappwebview plugin. description: macOS implementation of the flutter_inappwebview plugin.
version: 1.0.6 version: 1.0.7
homepage: https://inappwebview.dev/ homepage: https://inappwebview.dev/
repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_macos repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_macos
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
@ -18,7 +18,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_inappwebview_platform_interface: ^1.0.5 flutter_inappwebview_platform_interface: ^1.0.6
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -1,3 +1,8 @@
## 1.0.6
- Updated `InAppWebViewSettings.useShouldInterceptAjaxRequest` docs
- Added `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests` [#1905](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1905)
## 1.0.5 ## 1.0.5
- Must call super `dispose` method for `PlatformInAppBrowser` and `PlatformChromeSafariBrowser` - Must call super `dispose` method for `PlatformInAppBrowser` and `PlatformChromeSafariBrowser`

View File

@ -255,13 +255,28 @@ class InAppWebViewSettings_ {
///Set to `true` to be able to listen at the [PlatformWebViewCreationParams.shouldInterceptAjaxRequest] event. ///Set to `true` to be able to listen at the [PlatformWebViewCreationParams.shouldInterceptAjaxRequest] event.
/// ///
///If the [PlatformWebViewCreationParams.shouldInterceptAjaxRequest] event is implemented and this value is `null`, ///Due to the async nature of [PlatformWebViewCreationParams.shouldInterceptAjaxRequest] event implementation,
///it will intercept only async `XMLHttpRequest`s ([AjaxRequest.isAsync] with `true`).
///To be able to intercept sync `XMLHttpRequest`s, use [InAppWebViewSettings.interceptOnlyAsyncAjaxRequests] to `false`.
///
///If the [PlatformWebViewCreationParams.shouldInterceptAjaxRequest] event or
///any other Ajax event is implemented and this value is `null`,
///it will be automatically inferred as `true`, otherwise, the default value is `false`. ///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. ///This logic will not be applied for [PlatformInAppBrowser], where you must set the value manually.
@SupportedPlatforms( @SupportedPlatforms(
platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()]) platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()])
bool? useShouldInterceptAjaxRequest; bool? useShouldInterceptAjaxRequest;
///Set to `false` to be able to listen to also sync `XMLHttpRequest`s at the
///[PlatformWebViewCreationParams.shouldInterceptAjaxRequest] event.
///
///**NOTE**: Using `false` will cause the `XMLHttpRequest.send()` method for sync
///requests to not wait on the JavaScript code the response synchronously,
///as if it was an async `XMLHttpRequest`.
@SupportedPlatforms(
platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()])
bool? interceptOnlyAsyncAjaxRequests;
///Set to `true` to be able to listen at the [PlatformWebViewCreationParams.shouldInterceptFetchRequest] event. ///Set to `true` to be able to listen at the [PlatformWebViewCreationParams.shouldInterceptFetchRequest] event.
/// ///
///If the [PlatformWebViewCreationParams.shouldInterceptFetchRequest] event is implemented and this value is `null`, ///If the [PlatformWebViewCreationParams.shouldInterceptFetchRequest] event is implemented and this value is `null`,
@ -1621,6 +1636,7 @@ as it can cause framerate drops on animations in Android 9 and lower (see [Hybri
this.contentBlockers = const [], this.contentBlockers = const [],
this.preferredContentMode = UserPreferredContentMode_.RECOMMENDED, this.preferredContentMode = UserPreferredContentMode_.RECOMMENDED,
this.useShouldInterceptAjaxRequest, this.useShouldInterceptAjaxRequest,
this.interceptOnlyAsyncAjaxRequests = true,
this.useShouldInterceptFetchRequest, this.useShouldInterceptFetchRequest,
this.incognito = false, this.incognito = false,
this.cacheEnabled = true, this.cacheEnabled = true,

View File

@ -403,6 +403,9 @@ class PlatformWebViewCreationParams<T> {
///Event fired when an `XMLHttpRequest` is sent to a server. ///Event fired when an `XMLHttpRequest` is sent to a server.
///It gives the host application a chance to take control over the request before sending it. ///It gives the host application a chance to take control over the request before sending it.
/// ///
///Due to the async nature of this event implementation, it will intercept only async `XMLHttpRequest`s ([AjaxRequest.isAsync] with `true`).
///To be able to intercept sync `XMLHttpRequest`s, use [InAppWebViewSettings.interceptOnlyAsyncAjaxRequests] to `false`.
///
///[ajaxRequest] represents the `XMLHttpRequest`. ///[ajaxRequest] represents the `XMLHttpRequest`.
/// ///
///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewSettings.useShouldInterceptAjaxRequest] setting to `true`. ///**NOTE**: In order to be able to listen this event, you need to set [InAppWebViewSettings.useShouldInterceptAjaxRequest] setting to `true`.

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview_platform_interface name: flutter_inappwebview_platform_interface
description: A common platform interface for the flutter_inappwebview plugin. description: A common platform interface for the flutter_inappwebview plugin.
version: 1.0.5 version: 1.0.6
homepage: https://inappwebview.dev/ homepage: https://inappwebview.dev/
repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_platform_interface repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_platform_interface
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
@ -25,7 +25,7 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.0 flutter_lints: ^2.0.0
build_runner: ^2.2.1 build_runner: ^2.4.0
generators: generators:
path: ../dev_packages/generators path: ../dev_packages/generators

View File

@ -1,3 +1,7 @@
## 1.0.4
- Updated `flutter_inappwebview_platform_interface` version dependency to `1.0.6`
## 1.0.3 ## 1.0.3
- Fixed "Flutter 3.7.10 error Dart library 'dart:ui_web' is not available on this platform" [#1900](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1900) - Fixed "Flutter 3.7.10 error Dart library 'dart:ui_web' is not available on this platform" [#1900](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1900)

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview_web name: flutter_inappwebview_web
description: Web implementation of the flutter_inappwebview plugin. description: Web implementation of the flutter_inappwebview plugin.
version: 1.0.3 version: 1.0.4
homepage: https://inappwebview.dev/ homepage: https://inappwebview.dev/
repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_web repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_web
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
@ -21,7 +21,7 @@ dependencies:
flutter_web_plugins: flutter_web_plugins:
sdk: flutter sdk: flutter
js: ^0.6.4 js: ^0.6.4
flutter_inappwebview_platform_interface: ^1.0.5 flutter_inappwebview_platform_interface: ^1.0.6
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: