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:
flutter:
sdk: flutter
build: 2.3.1
build: ^2.4.0
source_gen: ^1.3.1
flutter_inappwebview_internal_annotations: ^1.1.1
dev_dependencies:
build_runner: 2.3.3
build_runner: ^2.4.0
build_test: ^2.1.7
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
- Updated minimum platform interface and implementation versions

View File

@ -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.0.0-beta.31
version: 6.0.0-beta.32
homepage: https://inappwebview.dev/
repository: https://github.com/pichillilorenzo/flutter_inappwebview
issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues
@ -22,7 +22,7 @@ dependencies:
flutter_inappwebview_android: ^1.0.5
flutter_inappwebview_ios: ^1.0.5
flutter_inappwebview_macos: ^1.0.3
flutter_inappwebview_web: ^1.0.2
flutter_inappwebview_web: ^1.0.3
dev_dependencies:
flutter_test:
@ -30,7 +30,7 @@ dev_dependencies:
flutter_driver:
sdk: flutter
flutter_lints: ^2.0.1
build_runner: 2.3.3
build_runner: ^2.4.0
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
- 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 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,
@ -16,6 +17,17 @@ public class InterceptAjaxRequestJS {
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) {" +
" var w = (window.top == null || window.top === window) ? window : window.top;" +
" w." + FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE + " = true;" +
@ -122,7 +134,8 @@ public class InterceptAjaxRequestJS {
" ajax.prototype.send = function(data) {" +
" 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 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;" +
@ -220,7 +233,7 @@ public class InterceptAjaxRequestJS {
" data = new Uint8Array(result.data);" +
" }" +
" self.withCredentials = result.withCredentials;" +
" if (result.responseType != null && self.isAsync) {" +
" if (result.responseType != null && self._flutter_inappwebview_isAsync) {" +
" self.responseType = result.responseType;" +
" };" +
" for (var header in result.headers) {" +

View File

@ -174,6 +174,9 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
@Nullable
public WebViewAssetLoaderExt webViewAssetLoaderExt;
@Nullable
private PluginScript interceptOnlyAsyncAjaxRequestsPluginScript;
public InAppWebView(Context context) {
super(context);
}
@ -565,7 +568,9 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
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);
interceptOnlyAsyncAjaxRequestsPluginScript = InterceptAjaxRequestJS.createInterceptOnlyAsyncAjaxRequestsPluginScript(customSettings.interceptOnlyAsyncAjaxRequests);
if (customSettings.useShouldInterceptAjaxRequest) {
userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript);
userContentController.addPluginScript(InterceptAjaxRequestJS.INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT);
}
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) {
enablePluginScriptAtRuntime(
InterceptFetchRequestJS.FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_FETCH_REQUEST_JS_SOURCE,
@ -2030,6 +2043,7 @@ final public class InAppWebView extends InputAwareWebView implements InAppWebVie
destroy();
}
});
interceptOnlyAsyncAjaxRequestsPluginScript = null;
userContentController.dispose();
if (findInteractionController != null) {
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 Integer preferredContentMode = PreferredContentModeOptionType.RECOMMENDED.toValue();
public Boolean useShouldInterceptAjaxRequest = false;
public Boolean interceptOnlyAsyncAjaxRequests = true;
public Boolean useShouldInterceptFetchRequest = false;
public Boolean incognito = false;
public Boolean cacheEnabled = true;
@ -184,6 +185,9 @@ public class InAppWebViewSettings implements ISettings<InAppWebViewInterface> {
case "useShouldInterceptAjaxRequest":
useShouldInterceptAjaxRequest = (Boolean) value;
break;
case "interceptOnlyAsyncAjaxRequests":
interceptOnlyAsyncAjaxRequests = (Boolean) value;
break;
case "useShouldInterceptFetchRequest":
useShouldInterceptFetchRequest = (Boolean) value;
break;
@ -426,6 +430,7 @@ public class InAppWebViewSettings implements ISettings<InAppWebViewInterface> {
settings.put("contentBlockers", contentBlockers);
settings.put("preferredContentMode", preferredContentMode);
settings.put("useShouldInterceptAjaxRequest", useShouldInterceptAjaxRequest);
settings.put("interceptOnlyAsyncAjaxRequests", interceptOnlyAsyncAjaxRequests);
settings.put("useShouldInterceptFetchRequest", useShouldInterceptFetchRequest);
settings.put("incognito", incognito);
settings.put("cacheEnabled", cacheEnabled);

View File

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

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview_android
description: Android implementation of the flutter_inappwebview plugin.
version: 1.0.7
version: 1.0.8
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
@ -18,7 +18,7 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_inappwebview_platform_interface: ^1.0.5
flutter_inappwebview_platform_interface: ^1.0.6
dev_dependencies:
flutter_test:

View File

@ -1,3 +1,8 @@
## 1.0.9
- Implemented `InAppWebViewSettings.interceptOnlyAsyncAjaxRequests`
- Updated `useShouldInterceptAjaxRequest` automatic infer logic
## 1.0.8
- 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)
fileprivate var interceptOnlyAsyncAjaxRequestsPluginScript: PluginScript?
init(id: Any?, plugin: SwiftFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration,
contextMenu: [String: Any]?, userScripts: [UserScript] = []) {
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(ORIGINAL_VIEWPORT_METATAG_CONTENT_JS_PLUGIN_SCRIPT)
if let settings = settings {
interceptOnlyAsyncAjaxRequestsPluginScript = createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: settings.interceptOnlyAsyncAjaxRequests)
if settings.useShouldInterceptAjaxRequest {
if let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript {
configuration.userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript)
}
configuration.userContentController.addPluginScript(INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT)
}
if settings.useShouldInterceptFetchRequest {
@ -1063,7 +1069,16 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate,
enable: newSettings.useShouldInterceptAjaxRequest,
pluginScript: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT)
} 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()
}
webMessageListeners.removeAll()
interceptOnlyAsyncAjaxRequestsPluginScript = nil
if windowId == nil {
configuration.userContentController.removeAllPluginScriptMessageHandlers()
configuration.userContentController.removeScriptMessageHandler(forName: "onCallAsyncJavaScriptResultBelowIOS14Received")

View File

@ -26,6 +26,7 @@ public class InAppWebViewSettings: ISettings<InAppWebView> {
var contentBlockers: [[String: [String : Any]]] = []
var minimumFontSize = 0
var useShouldInterceptAjaxRequest = false
var interceptOnlyAsyncAjaxRequests = true
var useShouldInterceptFetchRequest = false
var incognito = false
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 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(
groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
source: INTERCEPT_AJAX_REQUEST_JS_SOURCE,
@ -18,6 +20,16 @@ let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = PluginScript(
requiredInAllContentWorlds: true,
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 = """
\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) = true;
(function(ajax) {
@ -122,7 +134,8 @@ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
};
ajax.prototype.send = function(data) {
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) {
this._flutter_inappwebview_already_onreadystatechange_wrapped = true;
var onreadystatechange = this.onreadystatechange;
@ -219,7 +232,7 @@ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
data = new Uint8Array(result.data);
}
self.withCredentials = result.withCredentials;
if (result.responseType != null && self.isAsync) {
if (result.responseType != null && self._flutter_inappwebview_isAsync) {
self.responseType = result.responseType;
};
if (result.headers != null) {

View File

@ -87,4 +87,23 @@ public class PluginScript : UserScript {
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) {
let pluginScriptsList = pluginScripts.compactMap({ $0.value }).joined()
for pluginScript in pluginScriptsList {
if !containsPluginScript(with: pluginScript.groupName!) {
if !containsPluginScript(pluginScript: pluginScript) {
addUserScript(pluginScript)
for messageHandlerName in pluginScript.messageHandlerNames {
removeScriptMessageHandler(forName: messageHandlerName)
@ -100,8 +100,8 @@ extension WKUserContentController {
}
if #available(iOS 14.0, *), pluginScript.requiredInAllContentWorlds {
for contentWorld in contentWorlds {
let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld)
if !containsPluginScript(with: pluginScriptWithContentWorld.groupName!, in: contentWorld) {
if !containsPluginScript(pluginScript: pluginScript, in: contentWorld) {
let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld)
addUserScript(pluginScriptWithContentWorld)
for messageHandlerName in pluginScriptWithContentWorld.messageHandlerNames {
removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld)
@ -314,6 +314,16 @@ extension WKUserContentController {
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 {
let userScripts = useCopyOfUserScripts()
for script in userScripts {
@ -324,6 +334,17 @@ extension WKUserContentController {
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, *)
public func containsPluginScript(with groupName: String, in contentWorld: WKContentWorld) -> Bool {
let userScripts = useCopyOfUserScripts()

View File

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

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview_ios
description: iOS implementation of the flutter_inappwebview plugin.
version: 1.0.8
version: 1.0.9
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
@ -18,7 +18,7 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_inappwebview_platform_interface: ^1.0.5
flutter_inappwebview_platform_interface: ^1.0.6
dev_dependencies:
flutter_test:

View File

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

View File

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

View File

@ -48,6 +48,8 @@ public class InAppWebView: WKWebView, WKUIDelegate,
var currentOpenPanel: NSOpenPanel?
fileprivate var interceptOnlyAsyncAjaxRequestsPluginScript: PluginScript?
init(id: Any?, plugin: InAppWebViewFlutterPlugin?, frame: CGRect, configuration: WKWebViewConfiguration,
userScripts: [UserScript] = []) {
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(ON_SCROLL_CHANGED_EVENT_JS_PLUGIN_SCRIPT)
if let settings = settings {
interceptOnlyAsyncAjaxRequestsPluginScript = createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: settings.interceptOnlyAsyncAjaxRequests)
if settings.useShouldInterceptAjaxRequest {
if let interceptOnlyAsyncAjaxRequestsPluginScript = interceptOnlyAsyncAjaxRequestsPluginScript {
configuration.userContentController.addPluginScript(interceptOnlyAsyncAjaxRequestsPluginScript)
}
configuration.userContentController.addPluginScript(INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT)
}
if settings.useShouldInterceptFetchRequest {
@ -598,7 +604,16 @@ public class InAppWebView: WKWebView, WKUIDelegate,
enable: newSettings.useShouldInterceptAjaxRequest,
pluginScript: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT)
} 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()
}
webMessageListeners.removeAll()
interceptOnlyAsyncAjaxRequestsPluginScript = nil
if windowId == nil {
configuration.userContentController.removeAllPluginScriptMessageHandlers()
configuration.userContentController.removeScriptMessageHandler(forName: "onCallAsyncJavaScriptResultBelowIOS14Received")

View File

@ -24,6 +24,7 @@ public class InAppWebViewSettings: ISettings<InAppWebView> {
var contentBlockers: [[String: [String : Any]]] = []
var minimumFontSize = 0
var useShouldInterceptAjaxRequest = false
var interceptOnlyAsyncAjaxRequests = true
var useShouldInterceptFetchRequest = false
var incognito = false
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 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(
groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
source: INTERCEPT_AJAX_REQUEST_JS_SOURCE,
@ -18,6 +21,16 @@ let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = PluginScript(
requiredInAllContentWorlds: true,
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 = """
\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) = true;
(function(ajax) {
@ -122,7 +135,8 @@ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
};
ajax.prototype.send = function(data) {
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) {
this._flutter_inappwebview_already_onreadystatechange_wrapped = true;
var onreadystatechange = this.onreadystatechange;
@ -219,7 +233,7 @@ let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
data = new Uint8Array(result.data);
}
self.withCredentials = result.withCredentials;
if (result.responseType != null && self.isAsync) {
if (result.responseType != null && self._flutter_inappwebview_isAsync) {
self.responseType = result.responseType;
};
if (result.headers != null) {

View File

@ -87,4 +87,23 @@ public class PluginScript : UserScript {
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) {
let pluginScriptsList = pluginScripts.compactMap({ $0.value }).joined()
for pluginScript in pluginScriptsList {
if !containsPluginScript(with: pluginScript.groupName!) {
if !containsPluginScript(pluginScript: pluginScript) {
addUserScript(pluginScript)
for messageHandlerName in pluginScript.messageHandlerNames {
removeScriptMessageHandler(forName: messageHandlerName)
@ -100,8 +100,8 @@ extension WKUserContentController {
}
if #available(macOS 11.0, *), pluginScript.requiredInAllContentWorlds {
for contentWorld in contentWorlds {
let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld)
if !containsPluginScript(with: pluginScriptWithContentWorld.groupName!, in: contentWorld) {
if !containsPluginScript(pluginScript: pluginScript, in: contentWorld) {
let pluginScriptWithContentWorld = pluginScript.copyAndSet(contentWorld: contentWorld)
addUserScript(pluginScriptWithContentWorld)
for messageHandlerName in pluginScriptWithContentWorld.messageHandlerNames {
removeScriptMessageHandler(forName: messageHandlerName, contentWorld: contentWorld)
@ -313,6 +313,16 @@ extension WKUserContentController {
}
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 {
let userScripts = useCopyOfUserScripts()
@ -324,6 +334,17 @@ extension WKUserContentController {
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, *)
public func containsPluginScript(with groupName: String, in contentWorld: WKContentWorld) -> Bool {
let userScripts = useCopyOfUserScripts()

View File

@ -1,6 +1,6 @@
name: flutter_inappwebview_macos
description: macOS implementation of the flutter_inappwebview plugin.
version: 1.0.6
version: 1.0.7
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
@ -18,7 +18,7 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_inappwebview_platform_interface: ^1.0.5
flutter_inappwebview_platform_interface: ^1.0.6
dev_dependencies:
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
- 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.
///
///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`.
///This logic will not be applied for [PlatformInAppBrowser], where you must set the value manually.
@SupportedPlatforms(
platforms: [AndroidPlatform(), IOSPlatform(), MacOSPlatform()])
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.
///
///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.preferredContentMode = UserPreferredContentMode_.RECOMMENDED,
this.useShouldInterceptAjaxRequest,
this.interceptOnlyAsyncAjaxRequests = true,
this.useShouldInterceptFetchRequest,
this.incognito = false,
this.cacheEnabled = true,

View File

@ -403,6 +403,9 @@ class PlatformWebViewCreationParams<T> {
///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.
///
///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`.
///
///**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
description: A common platform interface for the flutter_inappwebview plugin.
version: 1.0.5
version: 1.0.6
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
@ -25,7 +25,7 @@ dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
build_runner: ^2.2.1
build_runner: ^2.4.0
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
- 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
description: Web implementation of the flutter_inappwebview plugin.
version: 1.0.3
version: 1.0.4
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
@ -21,7 +21,7 @@ dependencies:
flutter_web_plugins:
sdk: flutter
js: ^0.6.4
flutter_inappwebview_platform_interface: ^1.0.5
flutter_inappwebview_platform_interface: ^1.0.6
dev_dependencies:
flutter_test: