From be570be6b0f584fced04b0878c683a4cf8366202 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 11 Nov 2023 17:32:59 +0100 Subject: [PATCH] CookieManager.deleteCookies wait for all delete cookie completion handler to be completed on iOS and macOS, fix #1678 --- CHANGELOG.md | 2 + ios/Classes/InAppWebView/InAppWebView.swift | 10 +++-- .../InAppWebView/WebViewChannelDelegate.swift | 44 +++++++++++++++---- ios/Classes/MyCookieManager.swift | 10 ++++- macos/Classes/InAppWebView/InAppWebView.swift | 10 +++-- .../InAppWebView/WebViewChannelDelegate.swift | 44 +++++++++++++++---- macos/Classes/MyCookieManager.swift | 10 ++++- scripts/test.sh | 9 ++-- 8 files changed, 109 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 282cb60d..b901229c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 6.0.0-beta.26 - Throw an error if any controller is used after being disposed +- `CookieManager.deleteCookies` wait for all delete cookie completion handler to be completed on iOS and macOS - Updated return value for `CookieManager.setCookie` method to be `Future`. The return value indicates whether the cookie was set successfully - Merged "feat(ios): optional tradeoff to fix ios input delay" [#1665](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1665) (thanks to [andreasgangso](https://github.com/andreasgangso)) - Merged "Fix ios multiple flutter presenting error" [#1736](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1736) (thanks to [AlexT84](https://github.com/AlexT84)) @@ -10,6 +11,7 @@ - Merged "fix: chrome tab open failed due to chrome process not running" [#1772](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1772) (thanks to [YumengNevix](https://github.com/YumengNevix)) - Merged "Android - Fix context menu position for pages with horizontal scroll" [#1504](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1504) (thanks to [lrorpilla](https://github.com/lrorpilla)) - Fixed "iOS about:blank popup not loading page" [#1500](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1500) +- Fixed "iOS macOS - This method should not be called on the main thread as it may lead to UI unresponsiveness" [#1678](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678) ## 6.0.0-beta.25 diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index 9b30b023..d21a9e06 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -2042,9 +2042,13 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, return } - if let scheme = challenge.protectionSpace.protocol, scheme == "https", - let sslCertificate = challenge.protectionSpace.sslCertificate { - InAppWebView.sslCertificatesMap[challenge.protectionSpace.host] = sslCertificate + // workaround for ProtectionSpace SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + if let scheme = challenge.protectionSpace.protocol, scheme == "https", + let sslCertificate = challenge.protectionSpace.sslCertificate { + InAppWebView.sslCertificatesMap[challenge.protectionSpace.host] = sslCertificate + } } let callback = WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback() diff --git a/ios/Classes/InAppWebView/WebViewChannelDelegate.swift b/ios/Classes/InAppWebView/WebViewChannelDelegate.swift index 3e94be8d..4a4f2b61 100644 --- a/ios/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/ios/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -886,7 +886,7 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onPermissionRequest", arguments: request.toMap(), callback: callback); + channel.invokeMethod("onPermissionRequest", arguments: request.toMap(), callback: callback) } public class ShouldOverrideUrlLoadingCallback : BaseCallbackResult { @@ -910,7 +910,7 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("shouldOverrideUrlLoading", arguments: navigationAction.toMap(), callback: callback); + channel.invokeMethod("shouldOverrideUrlLoading", arguments: navigationAction.toMap(), callback: callback) } public func onLoadStart(url: String?) { @@ -965,7 +965,14 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onReceivedHttpAuthRequest", arguments: challenge.toMap(), callback: callback) + // workaround for ProtectionSpace.toMap() SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + let arguments = challenge.toMap() + DispatchQueue.main.async { + channel.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, callback: callback) + } + } } public class ReceivedServerTrustAuthRequestCallback : BaseCallbackResult { @@ -986,7 +993,14 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onReceivedServerTrustAuthRequest", arguments: challenge.toMap(), callback: callback); + // workaround for ProtectionSpace.toMap() SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + let arguments = challenge.toMap() + DispatchQueue.main.async { + channel.invokeMethod("onReceivedServerTrustAuthRequest", arguments: arguments, callback: callback) + } + } } public class ReceivedClientCertRequestCallback : BaseCallbackResult { @@ -1007,7 +1021,14 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onReceivedClientCertRequest", arguments: challenge.toMap(), callback: callback); + // workaround for ProtectionSpace.toMap() SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + let arguments = challenge.toMap() + DispatchQueue.main.async { + channel.invokeMethod("onReceivedClientCertRequest", arguments: arguments, callback: callback) + } + } } public func onZoomScaleChanged(newScale: Float, oldScale: Float) { @@ -1061,7 +1082,7 @@ public class WebViewChannelDelegate : ChannelDelegate { "handlerName": handlerName, "args": args ] - channel.invokeMethod("onCallJsHandler", arguments: arguments, callback: callback); + channel.invokeMethod("onCallJsHandler", arguments: arguments, callback: callback) } public class NavigationResponseCallback : BaseCallbackResult { @@ -1085,7 +1106,7 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onNavigationResponse", arguments: navigationResponse.toMap(), callback: callback); + channel.invokeMethod("onNavigationResponse", arguments: navigationResponse.toMap(), callback: callback) } public class ShouldAllowDeprecatedTLSCallback : BaseCallbackResult { @@ -1109,7 +1130,14 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("shouldAllowDeprecatedTLS", arguments: challenge.toMap(), callback: callback) + // workaround for ProtectionSpace.toMap() SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + let arguments = challenge.toMap() + DispatchQueue.main.async { + channel.invokeMethod("shouldAllowDeprecatedTLS", arguments: arguments, callback: callback) + } + } } public func onWebContentProcessDidTerminate() { diff --git a/ios/Classes/MyCookieManager.swift b/ios/Classes/MyCookieManager.swift index 1af7f8d6..5bcbb601 100755 --- a/ios/Classes/MyCookieManager.swift +++ b/ios/Classes/MyCookieManager.swift @@ -249,6 +249,7 @@ public class MyCookieManager: ChannelDelegate { public static func deleteCookies(url: String, path: String, domain: String?, result: @escaping FlutterResult) { var domain = domain + let dispatchGroup = DispatchGroup() MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { var originURL = url @@ -266,10 +267,15 @@ public class MyCookieManager: ChannelDelegate { } } if let domain = domain, cookie.domain == domain, cookie.path == path { - MyCookieManager.httpCookieStore.delete(cookie, completionHandler: nil) + dispatchGroup.enter() + MyCookieManager.httpCookieStore.delete(cookie) { + dispatchGroup.leave() + } } } - result(true) + dispatchGroup.notify(queue: .main) { + result(true) + } } } diff --git a/macos/Classes/InAppWebView/InAppWebView.swift b/macos/Classes/InAppWebView/InAppWebView.swift index 5cee0329..ecbfdaed 100755 --- a/macos/Classes/InAppWebView/InAppWebView.swift +++ b/macos/Classes/InAppWebView/InAppWebView.swift @@ -1424,9 +1424,13 @@ public class InAppWebView: WKWebView, WKUIDelegate, return } - if let scheme = challenge.protectionSpace.protocol, scheme == "https", - let sslCertificate = challenge.protectionSpace.sslCertificate { - InAppWebView.sslCertificatesMap[challenge.protectionSpace.host] = sslCertificate + // workaround for ProtectionSpace SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + if let scheme = challenge.protectionSpace.protocol, scheme == "https", + let sslCertificate = challenge.protectionSpace.sslCertificate { + InAppWebView.sslCertificatesMap[challenge.protectionSpace.host] = sslCertificate + } } let callback = WebViewChannelDelegate.ReceivedServerTrustAuthRequestCallback() diff --git a/macos/Classes/InAppWebView/WebViewChannelDelegate.swift b/macos/Classes/InAppWebView/WebViewChannelDelegate.swift index e90154c2..b2079b8d 100644 --- a/macos/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/macos/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -849,7 +849,7 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onPermissionRequest", arguments: request.toMap(), callback: callback); + channel.invokeMethod("onPermissionRequest", arguments: request.toMap(), callback: callback) } public class ShouldOverrideUrlLoadingCallback : BaseCallbackResult { @@ -873,7 +873,7 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("shouldOverrideUrlLoading", arguments: navigationAction.toMap(), callback: callback); + channel.invokeMethod("shouldOverrideUrlLoading", arguments: navigationAction.toMap(), callback: callback) } public func onLoadStart(url: String?) { @@ -928,7 +928,14 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onReceivedHttpAuthRequest", arguments: challenge.toMap(), callback: callback) + // workaround for ProtectionSpace.toMap() SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + let arguments = challenge.toMap() + DispatchQueue.main.async { + channel.invokeMethod("onReceivedHttpAuthRequest", arguments: arguments, callback: callback) + } + } } public class ReceivedServerTrustAuthRequestCallback : BaseCallbackResult { @@ -949,7 +956,14 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onReceivedServerTrustAuthRequest", arguments: challenge.toMap(), callback: callback); + // workaround for ProtectionSpace.toMap() SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + let arguments = challenge.toMap() + DispatchQueue.main.async { + channel.invokeMethod("onReceivedServerTrustAuthRequest", arguments: arguments, callback: callback) + } + } } public class ReceivedClientCertRequestCallback : BaseCallbackResult { @@ -970,7 +984,14 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onReceivedClientCertRequest", arguments: challenge.toMap(), callback: callback); + // workaround for ProtectionSpace.toMap() SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + let arguments = challenge.toMap() + DispatchQueue.main.async { + channel.invokeMethod("onReceivedClientCertRequest", arguments: arguments, callback: callback) + } + } } public func onZoomScaleChanged(newScale: Float, oldScale: Float) { @@ -1024,7 +1045,7 @@ public class WebViewChannelDelegate : ChannelDelegate { "handlerName": handlerName, "args": args ] - channel.invokeMethod("onCallJsHandler", arguments: arguments, callback: callback); + channel.invokeMethod("onCallJsHandler", arguments: arguments, callback: callback) } public class NavigationResponseCallback : BaseCallbackResult { @@ -1048,7 +1069,7 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("onNavigationResponse", arguments: navigationResponse.toMap(), callback: callback); + channel.invokeMethod("onNavigationResponse", arguments: navigationResponse.toMap(), callback: callback) } public class ShouldAllowDeprecatedTLSCallback : BaseCallbackResult { @@ -1072,7 +1093,14 @@ public class WebViewChannelDelegate : ChannelDelegate { callback.defaultBehaviour(nil) return } - channel.invokeMethod("shouldAllowDeprecatedTLS", arguments: challenge.toMap(), callback: callback) + // workaround for ProtectionSpace.toMap() SSL Certificate + // https://github.com/pichillilorenzo/flutter_inappwebview/issues/1678 + DispatchQueue.global(qos: .background).async { + let arguments = challenge.toMap() + DispatchQueue.main.async { + channel.invokeMethod("shouldAllowDeprecatedTLS", arguments: arguments, callback: callback) + } + } } public func onWebContentProcessDidTerminate() { diff --git a/macos/Classes/MyCookieManager.swift b/macos/Classes/MyCookieManager.swift index eed128a8..86e62d7e 100755 --- a/macos/Classes/MyCookieManager.swift +++ b/macos/Classes/MyCookieManager.swift @@ -245,6 +245,7 @@ public class MyCookieManager: ChannelDelegate { public static func deleteCookies(url: String, path: String, domain: String?, result: @escaping FlutterResult) { var domain = domain + let dispatchGroup = DispatchGroup() MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { var originURL = url @@ -258,10 +259,15 @@ public class MyCookieManager: ChannelDelegate { domain = domainUrl.host } if let domain = domain, cookie.domain == domain, cookie.path == path { - MyCookieManager.httpCookieStore.delete(cookie, completionHandler: nil) + dispatchGroup.enter() + MyCookieManager.httpCookieStore.delete(cookie) { + dispatchGroup.leave() + } } } - result(true) + dispatchGroup.notify(queue: .main) { + result(true) + } } } diff --git a/scripts/test.sh b/scripts/test.sh index dcbb98c7..7e553097 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -22,10 +22,10 @@ if [ -z "$NODE_SERVER_IP" ]; then exit 1 fi -PLATFORM=$2 +DEVICE_ID=$2 FAILED=0 -if [ ! -z "$2" ] && [ $PLATFORM = "web" ]; then +if [ ! -z "$2" ] && [ $DEVICE_ID = "chrome" ]; then $PROJECT_DIR/tool/chromedriver --port=4444 & fi @@ -39,12 +39,13 @@ node index.js & adb shell "echo '_ --disable-digital-asset-link-verification-for-url=\"https://flutter.dev\"' > /data/local/tmp/chrome-command-line" || true flutter --version +flutter devices flutter clean flutter pub get cd $PROJECT_DIR/example flutter clean -if [ ! -z "$2" ] && [ $PLATFORM = "web" ]; then - flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart --device-id=chrome +if [ ! -z "$2" ]; then + flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart --device-id=$DEVICE_ID else flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart fi