From 18c3c1fa514dc1570c22c929a76430aba1353c04 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Sat, 11 Nov 2023 19:08:14 +0100 Subject: [PATCH] Fixed iOS and macOS InAppWebView memory leaks --- CHANGELOG.md | 1 + ios/Classes/InAppWebView/InAppWebView.swift | 28 +++++++++--------- macos/Classes/InAppWebView/InAppWebView.swift | 29 +++++++++---------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b901229c..419fb13b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - 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) +- Fixed iOS and macOS InAppWebView memory leaks ## 6.0.0-beta.25 diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index d21a9e06..8c035f7f 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -2256,12 +2256,12 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, } return true } - callback.defaultBehaviour = { (response: JsAlertResponse?) in + callback.defaultBehaviour = { [weak self] (response: JsAlertResponse?) in if !completionHandlerCalled { completionHandlerCalled = true let responseMessage = response?.message let confirmButtonTitle = response?.confirmButtonTitle - self.createAlertDialog(message: message, responseMessage: responseMessage, + self?.createAlertDialog(message: message, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, completionHandler: completionHandler) } } @@ -2325,13 +2325,13 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, } return true } - callback.defaultBehaviour = { (response: JsConfirmResponse?) in + callback.defaultBehaviour = { [weak self] (response: JsConfirmResponse?) in if !completionHandlerCalled { completionHandlerCalled = true let responseMessage = response?.message let confirmButtonTitle = response?.confirmButtonTitle let cancelButtonTitle = response?.cancelButtonTitle - self.createConfirmDialog(message: message, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, completionHandler: completionHandler) + self?.createConfirmDialog(message: message, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, completionHandler: completionHandler) } } callback.error = { (code: String, message: String?, details: Any?) in @@ -2406,14 +2406,14 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, } return true } - callback.defaultBehaviour = { (response: JsPromptResponse?) in + callback.defaultBehaviour = { [weak self] (response: JsPromptResponse?) in if !completionHandlerCalled { completionHandlerCalled = true let responseMessage = response?.message let confirmButtonTitle = response?.confirmButtonTitle let cancelButtonTitle = response?.cancelButtonTitle let value = response?.value - self.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, + self?.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, value: value, completionHandler: completionHandler) } } @@ -2520,11 +2520,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, callback.nonNullSuccess = { (handledByClient: Bool) in return !handledByClient } - callback.defaultBehaviour = { (handledByClient: Bool?) in + callback.defaultBehaviour = { [weak self] (handledByClient: Bool?) in if inAppWebViewManager?.windowWebViews[windowId] != nil { inAppWebViewManager?.windowWebViews.removeValue(forKey: windowId) } - self.loadUrl(urlRequest: navigationAction.request, allowingReadAccessTo: nil) + self?.loadUrl(urlRequest: navigationAction.request, allowingReadAccessTo: nil) } callback.error = { [weak callback] (code: String, message: String?, details: Any?) in print(code + ", " + (message ?? "")) @@ -2807,8 +2807,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, callback.nonNullSuccess = { (handledByClient: Bool) in return !handledByClient } - callback.defaultBehaviour = { (handledByClient: Bool?) in - if let printJob = self.plugin?.printJobManager?.jobs[printJobId] { + callback.defaultBehaviour = { [weak self] (handledByClient: Bool?) in + if let printJob = self?.plugin?.printJobManager?.jobs[printJobId] { printJob?.disposeNoDismiss() } } @@ -2831,24 +2831,24 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, } let callback = WebViewChannelDelegate.CallJsHandlerCallback() - callback.defaultBehaviour = { (response: Any?) in + callback.defaultBehaviour = { [weak self] (response: Any?) in var json = "null" if let r = response as? String { json = r } - self.evaluateJavaScript(""" + self?.evaluateJavaScript(""" if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)].resolve(\(json)); delete window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)]; } """, completionHandler: nil) } - callback.error = { (code: String, message: String?, details: Any?) in + callback.error = { [weak self] (code: String, message: String?, details: Any?) in let errorMessage = code + (message != nil ? ", " + (message ?? "") : "") print(errorMessage) - self.evaluateJavaScript(""" + self?.evaluateJavaScript(""" if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)].reject(new Error('\(errorMessage.replacingOccurrences(of: "\'", with: "\\'"))')); delete window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)]; diff --git a/macos/Classes/InAppWebView/InAppWebView.swift b/macos/Classes/InAppWebView/InAppWebView.swift index ecbfdaed..36f6ebd4 100755 --- a/macos/Classes/InAppWebView/InAppWebView.swift +++ b/macos/Classes/InAppWebView/InAppWebView.swift @@ -1653,12 +1653,12 @@ public class InAppWebView: WKWebView, WKUIDelegate, } return true } - callback.defaultBehaviour = { (response: JsAlertResponse?) in + callback.defaultBehaviour = { [weak self] (response: JsAlertResponse?) in if !completionHandlerCalled { completionHandlerCalled = true let responseMessage = response?.message let confirmButtonTitle = response?.confirmButtonTitle - self.createAlertDialog(message: message, responseMessage: responseMessage, + self?.createAlertDialog(message: message, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, completionHandler: completionHandler) } } @@ -1714,13 +1714,13 @@ public class InAppWebView: WKWebView, WKUIDelegate, } return true } - callback.defaultBehaviour = { (response: JsConfirmResponse?) in + callback.defaultBehaviour = { [weak self] (response: JsConfirmResponse?) in if !completionHandlerCalled { completionHandlerCalled = true let responseMessage = response?.message let confirmButtonTitle = response?.confirmButtonTitle let cancelButtonTitle = response?.cancelButtonTitle - self.createConfirmDialog(message: message, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, completionHandler: completionHandler) + self?.createConfirmDialog(message: message, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, completionHandler: completionHandler) } } callback.error = { (code: String, message: String?, details: Any?) in @@ -1780,14 +1780,14 @@ public class InAppWebView: WKWebView, WKUIDelegate, } return true } - callback.defaultBehaviour = { (response: JsPromptResponse?) in + callback.defaultBehaviour = { [weak self] (response: JsPromptResponse?) in if !completionHandlerCalled { completionHandlerCalled = true let responseMessage = response?.message let confirmButtonTitle = response?.confirmButtonTitle let cancelButtonTitle = response?.cancelButtonTitle let value = response?.value - self.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, + self?.createPromptDialog(message: message, defaultValue: defaultValue, responseMessage: responseMessage, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, value: value, completionHandler: completionHandler) } } @@ -1826,7 +1826,6 @@ public class InAppWebView: WKWebView, WKUIDelegate, ) inAppWebViewManager?.windowWebViews[windowId] = webViewTransport - windowWebView.stopLoading() let createWindowAction = CreateWindowAction(navigationAction: navigationAction, windowId: windowId, windowFeatures: windowFeatures, isDialog: nil) @@ -1834,11 +1833,11 @@ public class InAppWebView: WKWebView, WKUIDelegate, callback.nonNullSuccess = { (handledByClient: Bool) in return !handledByClient } - callback.defaultBehaviour = { (handledByClient: Bool?) in + callback.defaultBehaviour = { [weak self] (handledByClient: Bool?) in if inAppWebViewManager?.windowWebViews[windowId] != nil { inAppWebViewManager?.windowWebViews.removeValue(forKey: windowId) } - self.loadUrl(urlRequest: navigationAction.request, allowingReadAccessTo: nil) + self?.loadUrl(urlRequest: navigationAction.request, allowingReadAccessTo: nil) } callback.error = { [weak callback] (code: String, message: String?, details: Any?) in print(code + ", " + (message ?? "")) @@ -2111,8 +2110,8 @@ public class InAppWebView: WKWebView, WKUIDelegate, callback.nonNullSuccess = { (handledByClient: Bool) in return !handledByClient } - callback.defaultBehaviour = { (handledByClient: Bool?) in - if let printJob = self.plugin?.printJobManager?.jobs[printJobId] { + callback.defaultBehaviour = { [weak self] (handledByClient: Bool?) in + if let printJob = self?.plugin?.printJobManager?.jobs[printJobId] { printJob?.disposeNoDismiss() } } @@ -2135,24 +2134,24 @@ public class InAppWebView: WKWebView, WKUIDelegate, } let callback = WebViewChannelDelegate.CallJsHandlerCallback() - callback.defaultBehaviour = { (response: Any?) in + callback.defaultBehaviour = { [weak self] (response: Any?) in var json = "null" if let r = response as? String { json = r } - self.evaluateJavaScript(""" + self?.evaluateJavaScript(""" if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)].resolve(\(json)); delete window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)]; } """, completionHandler: nil) } - callback.error = { (code: String, message: String?, details: Any?) in + callback.error = { [weak self] (code: String, message: String?, details: Any?) in let errorMessage = code + (message != nil ? ", " + (message ?? "") : "") print(errorMessage) - self.evaluateJavaScript(""" + self?.evaluateJavaScript(""" if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)].reject(new Error('\(errorMessage.replacingOccurrences(of: "\'", with: "\\'"))')); delete window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)];