From b6725128a837bb883171316e033464e8bb229e3b Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Tue, 16 May 2023 20:06:53 +0200 Subject: [PATCH] fix #1640, fix #1632, Fixed InAppBrowser.show() possible crash on macOS, Fixed missing windowTitlebarSeparatorStyle, windowAlphaValue, windowStyleMask, windowFrame macOS settings updates when using setSettings() --- CHANGELOG.md | 3 + README.md | 2 +- ios/Classes/CredentialDatabase.swift | 60 ++++--------- .../HeadlessInAppWebView.swift | 7 +- .../HeadlessInAppWebViewManager.swift | 21 +++-- .../InAppBrowser/InAppBrowserManager.swift | 11 +-- .../InAppBrowserWebViewController.swift | 12 ++- .../FlutterWebViewController.swift | 2 +- ios/Classes/InAppWebView/InAppWebView.swift | 31 ++++--- .../WebMessage/WebMessageChannel.swift | 11 ++- .../WebMessage/WebMessageListener.swift | 10 ++- .../InAppWebView/WebViewChannelDelegate.swift | 8 +- ios/Classes/InAppWebViewStatic.swift | 30 +++---- ios/Classes/MyCookieManager.swift | 53 +++--------- ios/Classes/MyWebStorageManager.swift | 41 +++------ ios/Classes/PlatformUtil.swift | 10 +-- ios/Classes/PrintJob/PrintJobController.swift | 7 +- .../ChromeSafariBrowserManager.swift | 16 ++-- .../SafariViewController.swift | 12 ++- ios/Classes/SwiftFlutterPlugin.swift | 21 +++-- ios/Classes/Util.swift | 8 +- .../WebAuthenticationSession.swift | 7 +- .../WebAuthenticationSessionManager.swift | 14 +-- macos/Classes/CredentialDatabase.swift | 63 ++++---------- .../HeadlessInAppWebView.swift | 7 +- .../HeadlessInAppWebViewManager.swift | 21 +++-- .../InAppBrowser/InAppBrowserManager.swift | 11 +-- .../InAppBrowserWebViewController.swift | 10 ++- .../InAppBrowser/InAppBrowserWindow.swift | 26 ++++-- .../FlutterWebViewController.swift | 2 +- macos/Classes/InAppWebView/InAppWebView.swift | 19 ++-- .../WebMessage/WebMessageChannel.swift | 11 ++- .../WebMessage/WebMessageListener.swift | 10 ++- .../InAppWebView/WebViewChannelDelegate.swift | 8 +- macos/Classes/InAppWebViewFlutterPlugin.swift | 84 +++++++++++++++++- macos/Classes/InAppWebViewStatic.swift | 30 +++---- macos/Classes/MyCookieManager.swift | 53 +++--------- macos/Classes/MyWebStorageManager.swift | 35 ++------ macos/Classes/PlatformUtil.swift | 10 +-- .../Classes/PrintJob/PrintJobController.swift | 7 +- macos/Classes/SwiftFlutterPlugin.swift | 86 ------------------- .../WebAuthenticationSession.swift | 7 +- .../WebAuthenticationSessionManager.swift | 14 +-- 43 files changed, 426 insertions(+), 485 deletions(-) delete mode 100755 macos/Classes/SwiftFlutterPlugin.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d976667..7e066fbc 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ - Merged "Fix AndroidX migration URL in README.md" [#1529](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1529) (thanks to [cslee](https://github.com/cslee)) - Merged "InAppBrowser Bugfix/viewgroup index crash" [#1618](https://github.com/pichillilorenzo/flutter_inappwebview/pull/1618) (thanks to [KhatibFX](https://github.com/KhatibFX)) - Fixed old iOS versions crash "dyld: Library not loaded: /usr/lib/swift/libswiftCoreGraphics.dylib Reason: image not found" (thanks to [guide-flutter](https://github.com/guide-flutter)) +- Fixed `InAppBrowser.show()` possible crash on macOS +- Fixed missing `windowTitlebarSeparatorStyle`, `windowAlphaValue`, `windowStyleMask`, `windowFrame` macOS settings updates when using `setSettings()` +- Fixed "iOS and macOS flutter multiple engine" [#1632](https://github.com/pichillilorenzo/flutter_inappwebview/issues/1632) ## 6.0.0-beta.23 diff --git a/README.md b/README.md index a2c1aaf0..2a7ed71f 100755 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Send a submission request to the [Submit App](https://inappwebview.dev/submit-ap - Flutter: ">=3.0.0" - Android: `minSdkVersion 19` and add support for `androidx` (see [AndroidX Migration](https://docs.flutter.dev/development/platform-integration/android/androidx-migration) to migrate an existing app) - iOS 9.0+: `--ios-language swift`, Xcode version `>= 14.3` -- MacOS 10.11+: Xcode version `>= 14` +- MacOS 10.11+: Xcode version `>= 14.3` ## Installation diff --git a/ios/Classes/CredentialDatabase.swift b/ios/Classes/CredentialDatabase.swift index 3fe15a91..8a48275f 100755 --- a/ios/Classes/CredentialDatabase.swift +++ b/ios/Classes/CredentialDatabase.swift @@ -9,13 +9,12 @@ import Foundation public class CredentialDatabase: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database" - static var registrar: FlutterPluginRegistrar? - static var credentialStore: URLCredentialStorage? + var plugin: SwiftFlutterPlugin? + static var credentialStore = URLCredentialStorage.shared - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: CredentialDatabase.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())) - CredentialDatabase.registrar = registrar - CredentialDatabase.credentialStore = URLCredentialStorage.shared + init(plugin: SwiftFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: CredentialDatabase.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -23,11 +22,7 @@ public class CredentialDatabase: ChannelDelegate { switch call.method { case "getAllAuthCredentials": var allCredentials: [[String: Any?]] = [] - guard let credentialStore = CredentialDatabase.credentialStore else { - result(allCredentials) - return - } - for (protectionSpace, credentials) in credentialStore.allCredentials { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { var crendentials: [[String: Any?]] = [] for c in credentials { let credential: [String: Any?] = c.value.toMap() @@ -45,10 +40,6 @@ public class CredentialDatabase: ChannelDelegate { break case "getHttpAuthCredentials": var crendentials: [[String: Any?]] = [] - guard let credentialStore = CredentialDatabase.credentialStore else { - result(crendentials) - return - } let host = arguments!["host"] as! String let urlProtocol = arguments!["protocol"] as? String @@ -58,7 +49,7 @@ public class CredentialDatabase: ChannelDelegate { realm = nil } - for (protectionSpace, credentials) in credentialStore.allCredentials { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { if protectionSpace.host == host && protectionSpace.realm == realm && protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { for c in credentials { @@ -70,11 +61,6 @@ public class CredentialDatabase: ChannelDelegate { result(crendentials) break case "setHttpAuthCredential": - guard let credentialStore = CredentialDatabase.credentialStore else { - result(false) - return - } - let host = arguments!["host"] as! String let urlProtocol = arguments!["protocol"] as? String let urlPort = arguments!["port"] as? Int ?? 0 @@ -85,17 +71,12 @@ public class CredentialDatabase: ChannelDelegate { let username = arguments!["username"] as! String let password = arguments!["password"] as! String let credential = URLCredential(user: username, password: password, persistence: .permanent) - credentialStore.set(credential, + CredentialDatabase.credentialStore.set(credential, for: URLProtectionSpace(host: host, port: urlPort, protocol: urlProtocol, realm: realm, authenticationMethod: NSURLAuthenticationMethodHTTPBasic)) result(true) break case "removeHttpAuthCredential": - guard let credentialStore = CredentialDatabase.credentialStore else { - result(false) - return - } - let host = arguments!["host"] as! String let urlProtocol = arguments!["protocol"] as? String let urlPort = arguments!["port"] as? Int ?? 0 @@ -109,7 +90,7 @@ public class CredentialDatabase: ChannelDelegate { var credential: URLCredential? = nil; var protectionSpaceCredential: URLProtectionSpace? = nil - for (protectionSpace, credentials) in credentialStore.allCredentials { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { if protectionSpace.host == host && protectionSpace.realm == realm && protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { for c in credentials { @@ -126,17 +107,12 @@ public class CredentialDatabase: ChannelDelegate { } if let c = credential, let protectionSpace = protectionSpaceCredential { - credentialStore.remove(c, for: protectionSpace) + CredentialDatabase.credentialStore.remove(c, for: protectionSpace) } result(true) break case "removeHttpAuthCredentials": - guard let credentialStore = CredentialDatabase.credentialStore else { - result(false) - return - } - let host = arguments!["host"] as! String let urlProtocol = arguments!["protocol"] as? String let urlPort = arguments!["port"] as? Int ?? 0 @@ -148,7 +124,7 @@ public class CredentialDatabase: ChannelDelegate { var credentialsToRemove: [URLCredential] = []; var protectionSpaceCredential: URLProtectionSpace? = nil - for (protectionSpace, credentials) in credentialStore.allCredentials { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { if protectionSpace.host == host && protectionSpace.realm == realm && protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { protectionSpaceCredential = protectionSpace @@ -163,21 +139,16 @@ public class CredentialDatabase: ChannelDelegate { if let protectionSpace = protectionSpaceCredential { for credential in credentialsToRemove { - credentialStore.remove(credential, for: protectionSpace) + CredentialDatabase.credentialStore.remove(credential, for: protectionSpace) } } result(true) break case "clearAllAuthCredentials": - guard let credentialStore = CredentialDatabase.credentialStore else { - result(false) - return - } - - for (protectionSpace, credentials) in credentialStore.allCredentials { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { for credential in credentials { - credentialStore.remove(credential.value, for: protectionSpace) + CredentialDatabase.credentialStore.remove(credential.value, for: protectionSpace) } } result(true) @@ -190,8 +161,7 @@ public class CredentialDatabase: ChannelDelegate { public override func dispose() { super.dispose() - CredentialDatabase.registrar = nil - CredentialDatabase.credentialStore = nil + plugin = nil } deinit { diff --git a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift index 5759b20b..657cb151 100644 --- a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift +++ b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift @@ -12,12 +12,14 @@ public class HeadlessInAppWebView : Disposable { var id: String var channelDelegate: HeadlessWebViewChannelDelegate? var flutterWebView: FlutterWebViewController? + var plugin: SwiftFlutterPlugin? - public init(id: String, flutterWebView: FlutterWebViewController) { + public init(plugin: SwiftFlutterPlugin, id: String, flutterWebView: FlutterWebViewController) { self.id = id self.flutterWebView = flutterWebView + self.plugin = plugin let channel = FlutterMethodChannel(name: HeadlessInAppWebView.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) + binaryMessenger: plugin.registrar!.messenger()) self.channelDelegate = HeadlessWebViewChannelDelegate(headlessWebView: self, channel: channel) } @@ -79,6 +81,7 @@ public class HeadlessInAppWebView : Disposable { channelDelegate = nil HeadlessInAppWebViewManager.webViews[id] = nil flutterWebView = nil + plugin = nil } deinit { diff --git a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift index d9afab44..020ffb2e 100644 --- a/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift +++ b/ios/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift @@ -15,12 +15,12 @@ import AVFoundation public class HeadlessInAppWebViewManager: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview" - static var registrar: FlutterPluginRegistrar? + var plugin: SwiftFlutterPlugin? static var webViews: [String: HeadlessInAppWebView?] = [:] - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())) - HeadlessInAppWebViewManager.registrar = registrar + init(plugin: SwiftFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -30,7 +30,7 @@ public class HeadlessInAppWebViewManager: ChannelDelegate { switch call.method { case "run": let params = arguments!["params"] as! [String: Any?] - HeadlessInAppWebViewManager.run(id: id, params: params) + run(id: id, params: params) result(true) break default: @@ -39,12 +39,15 @@ public class HeadlessInAppWebViewManager: ChannelDelegate { } } - public static func run(id: String, params: [String: Any?]) { - let flutterWebView = FlutterWebViewController(registrar: HeadlessInAppWebViewManager.registrar!, + public func run(id: String, params: [String: Any?]) { + guard let plugin = plugin, let registrar = plugin.registrar else { + return + } + let flutterWebView = FlutterWebViewController(registrar: registrar, withFrame: CGRect.zero, viewIdentifier: id, params: params as NSDictionary) - let headlessInAppWebView = HeadlessInAppWebView(id: id, flutterWebView: flutterWebView) + let headlessInAppWebView = HeadlessInAppWebView(plugin: plugin, id: id, flutterWebView: flutterWebView) HeadlessInAppWebViewManager.webViews[id] = headlessInAppWebView headlessInAppWebView.prepare(params: params as NSDictionary) @@ -54,12 +57,12 @@ public class HeadlessInAppWebViewManager: ChannelDelegate { public override func dispose() { super.dispose() - HeadlessInAppWebViewManager.registrar = nil let headlessWebViews = HeadlessInAppWebViewManager.webViews.values headlessWebViews.forEach { (headlessWebView: HeadlessInAppWebView?) in headlessWebView?.dispose() } HeadlessInAppWebViewManager.webViews.removeAll() + plugin = nil } deinit { diff --git a/ios/Classes/InAppBrowser/InAppBrowserManager.swift b/ios/Classes/InAppBrowser/InAppBrowserManager.swift index ac621910..dce4c390 100755 --- a/ios/Classes/InAppBrowser/InAppBrowserManager.swift +++ b/ios/Classes/InAppBrowser/InAppBrowserManager.swift @@ -16,13 +16,13 @@ public class InAppBrowserManager: ChannelDelegate { static let WEBVIEW_STORYBOARD = "WebView" static let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController" static let NAV_STORYBOARD_CONTROLLER_ID = "navController" - static var registrar: FlutterPluginRegistrar? + var plugin: SwiftFlutterPlugin? private var previousStatusBarStyle = -1 - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: InAppBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())) - InAppBrowserManager.registrar = registrar + init(plugin: SwiftFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: InAppBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -55,6 +55,7 @@ public class InAppBrowserManager: ChannelDelegate { let _ = webViewSettings.parse(settings: settings) let webViewController = InAppBrowserWebViewController() + webViewController.plugin = plugin webViewController.browserSettings = browserSettings webViewController.isHidden = browserSettings.hidden webViewController.webViewSettings = webViewSettings @@ -137,7 +138,7 @@ public class InAppBrowserManager: ChannelDelegate { public override func dispose() { super.dispose() - InAppBrowserManager.registrar = nil + plugin = nil } deinit { diff --git a/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift b/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift index ab6d8c35..b6789ed7 100755 --- a/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift +++ b/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift @@ -23,6 +23,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega var tmpWindow: UIWindow? var id: String = "" + var plugin: SwiftFlutterPlugin? var windowId: Int64? var webView: InAppWebView? var channelDelegate: InAppBrowserChannelDelegate? @@ -41,7 +42,11 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega var isHidden = false public override func loadView() { - let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) + guard let registrar = plugin?.registrar else { + return + } + + let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: registrar.messenger()) channelDelegate = InAppBrowserChannelDelegate(channel: channel) var userScripts: [UserScript] = [] @@ -73,13 +78,13 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega let pullToRefreshSettings = PullToRefreshSettings() let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings) - let pullToRefreshControl = PullToRefreshControl(registrar: SwiftFlutterPlugin.instance!.registrar!, id: id, settings: pullToRefreshSettings) + let pullToRefreshControl = PullToRefreshControl(registrar: registrar, id: id, settings: pullToRefreshSettings) webView.pullToRefreshControl = pullToRefreshControl pullToRefreshControl.delegate = webView pullToRefreshControl.prepare() let findInteractionController = FindInteractionController( - registrar: SwiftFlutterPlugin.instance!.registrar!, + registrar: registrar, id: id, webView: webView, settings: nil) webView.findInteractionController = findInteractionController findInteractionController.prepare() @@ -578,6 +583,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega backButton.target = nil reloadButton.target = nil shareButton.target = nil + plugin = nil } deinit { diff --git a/ios/Classes/InAppWebView/FlutterWebViewController.swift b/ios/Classes/InAppWebView/FlutterWebViewController.swift index 5c50084c..1c38d7e7 100755 --- a/ios/Classes/InAppWebView/FlutterWebViewController.swift +++ b/ios/Classes/InAppWebView/FlutterWebViewController.swift @@ -63,7 +63,7 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView, Disposable pullToRefreshControl.prepare() let findInteractionController = FindInteractionController( - registrar: SwiftFlutterPlugin.instance!.registrar!, + registrar: registrar, id: viewId, webView: webView!, settings: nil) webView!.findInteractionController = findInteractionController findInteractionController.prepare() diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index 4d89ab00..ccbd7ead 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -17,6 +17,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_" var id: Any? // viewId + var registrar: FlutterPluginRegistrar? var windowId: Int64? var windowCreated = false var inAppBrowserDelegate: InAppBrowserDelegate? @@ -71,6 +72,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, contextMenu: [String: Any]?, userScripts: [UserScript] = []) { super.init(frame: frame, configuration: configuration) self.id = id + self.registrar = registrar if let id = id, let registrar = registrar { let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: id), binaryMessenger: registrar.messenger()) @@ -938,9 +940,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, } public func loadFile(assetFilePath: String) throws { - let assetURL = try Util.getUrlAsset(assetFilePath: assetFilePath) - let urlRequest = URLRequest(url: assetURL) - loadUrl(urlRequest: urlRequest, allowingReadAccessTo: nil) + if let registrar = registrar { + let assetURL = try Util.getUrlAsset(registrar: registrar, assetFilePath: assetFilePath) + let urlRequest = URLRequest(url: assetURL) + loadUrl(urlRequest: urlRequest, allowingReadAccessTo: nil) + } } func setSettings(newSettings: InAppWebViewSettings, newSettingsMap: [String: Any]) { @@ -1973,8 +1977,8 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, completionHandler(.useCredential, credential) break case 2: - if InAppWebView.credentialsProposed.count == 0, let credentialStore = CredentialDatabase.credentialStore { - for (protectionSpace, credentials) in credentialStore.allCredentials { + if InAppWebView.credentialsProposed.count == 0 { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { if protectionSpace.host == host && protectionSpace.realm == realm && protectionSpace.protocol == prot && protectionSpace.port == port { for credential in credentials { @@ -2086,7 +2090,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, var path: String = certificatePath do { - path = try Util.getAbsPathAsset(assetFilePath: certificatePath) + if let registrar = self.registrar { + path = try Util.getAbsPathAsset(registrar: registrar, assetFilePath: certificatePath) + } } catch {} if let PKCS12Data = NSData(contentsOfFile: path), @@ -2973,8 +2979,8 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { } let animated = settings?.animated ?? true - if let id = printJobId { - let printJob = PrintJobController(id: id, job: printController, settings: settings) + if let id = printJobId, let registrar = registrar { + let printJob = PrintJobController(registrar: registrar, id: id, job: printController, settings: settings) PrintJobManager.jobs[id] = printJob printJob.present(animated: animated, completionHandler: completionHandler) } else { @@ -3116,9 +3122,13 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { } } - public func createWebMessageChannel(completionHandler: ((WebMessageChannel) -> Void)? = nil) -> WebMessageChannel { + public func createWebMessageChannel(completionHandler: ((WebMessageChannel?) -> Void)? = nil) -> WebMessageChannel? { + guard let registrar = registrar else { + completionHandler?(nil) + return nil + } let id = NSUUID().uuidString - let webMessageChannel = WebMessageChannel(id: id) + let webMessageChannel = WebMessageChannel(registrar: registrar, id: id) webMessageChannel.initJsInstance(webView: self, completionHandler: completionHandler) webMessageChannels[id] = webMessageChannel @@ -3235,6 +3245,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { SharedLastTouchPointTimestamp.removeValue(forKey: self) callAsyncJavaScriptBelowIOS14Results.removeAll() super.removeFromSuperview() + registrar = nil } deinit { diff --git a/ios/Classes/InAppWebView/WebMessage/WebMessageChannel.swift b/ios/Classes/InAppWebView/WebMessage/WebMessageChannel.swift index b249382e..dc89b45b 100644 --- a/ios/Classes/InAppWebView/WebMessage/WebMessageChannel.swift +++ b/ios/Classes/InAppWebView/WebMessage/WebMessageChannel.swift @@ -13,12 +13,14 @@ public class WebMessageChannel : FlutterMethodCallDelegate { var channelDelegate: WebMessageChannelChannelDelegate? weak var webView: InAppWebView? var ports: [WebMessagePort] = [] + var registrar: FlutterPluginRegistrar? - public init(id: String) { + public init(registrar: FlutterPluginRegistrar, id: String) { self.id = id + self.registrar = registrar super.init() let channel = FlutterMethodChannel(name: WebMessageChannel.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) + binaryMessenger: registrar.messenger()) self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel) self.ports = [ WebMessagePort(name: "port1", webMessageChannel: self), @@ -26,7 +28,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate { ] } - public func initJsInstance(webView: InAppWebView, completionHandler: ((WebMessageChannel) -> Void)? = nil) { + public func initJsInstance(webView: InAppWebView, completionHandler: ((WebMessageChannel?) -> Void)? = nil) { self.webView = webView if let webView = self.webView { webView.evaluateJavascript(source: """ @@ -37,7 +39,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate { completionHandler?(self) } } else { - completionHandler?(self) + completionHandler?(nil) } } @@ -65,6 +67,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate { })(); """) webView = nil + registrar = nil } deinit { diff --git a/ios/Classes/InAppWebView/WebMessage/WebMessageListener.swift b/ios/Classes/InAppWebView/WebMessage/WebMessageListener.swift index 6a55170f..c8853fbf 100644 --- a/ios/Classes/InAppWebView/WebMessage/WebMessageListener.swift +++ b/ios/Classes/InAppWebView/WebMessage/WebMessageListener.swift @@ -15,14 +15,16 @@ public class WebMessageListener : FlutterMethodCallDelegate { var allowedOriginRules: Set var channelDelegate: WebMessageListenerChannelDelegate? weak var webView: InAppWebView? + var registrar: FlutterPluginRegistrar? - public init(id: String, jsObjectName: String, allowedOriginRules: Set) { + public init(registrar: FlutterPluginRegistrar, id: String, jsObjectName: String, allowedOriginRules: Set) { self.id = id + self.registrar = registrar self.jsObjectName = jsObjectName self.allowedOriginRules = allowedOriginRules super.init() let channel = FlutterMethodChannel(name: WebMessageListener.METHOD_CHANNEL_NAME_PREFIX + self.id + "_" + self.jsObjectName, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) + binaryMessenger: registrar.messenger()) self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel) } @@ -114,11 +116,12 @@ public class WebMessageListener : FlutterMethodCallDelegate { } } - public static func fromMap(map: [String:Any?]?) -> WebMessageListener? { + public static func fromMap(registrar: FlutterPluginRegistrar, map: [String:Any?]?) -> WebMessageListener? { guard let map = map else { return nil } return WebMessageListener( + registrar: registrar, id: map["id"] as! String, jsObjectName: map["jsObjectName"] as! String, allowedOriginRules: Set(map["allowedOriginRules"] as! [String]) @@ -177,6 +180,7 @@ public class WebMessageListener : FlutterMethodCallDelegate { channelDelegate?.dispose() channelDelegate = nil webView = nil + registrar = nil } deinit { diff --git a/ios/Classes/InAppWebView/WebViewChannelDelegate.swift b/ios/Classes/InAppWebView/WebViewChannelDelegate.swift index 960dd50f..acdad64b 100644 --- a/ios/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/ios/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -497,6 +497,10 @@ public class WebViewChannelDelegate : ChannelDelegate { case .createWebMessageChannel: if let webView = webView { let _ = webView.createWebMessageChannel { (webMessageChannel) in + guard let webMessageChannel = webMessageChannel else { + result(nil) + return + } result(webMessageChannel.toMap()) } } else { @@ -532,9 +536,9 @@ public class WebViewChannelDelegate : ChannelDelegate { } break case .addWebMessageListener: - if let webView = webView { + if let webView = webView, let registrar = webView.registrar { let webMessageListenerMap = arguments!["webMessageListener"] as! [String: Any?] - let webMessageListener = WebMessageListener.fromMap(map: webMessageListenerMap)! + let webMessageListener = WebMessageListener.fromMap(registrar: registrar, map: webMessageListenerMap)! do { try webView.addWebMessageListener(webMessageListener: webMessageListener) result(false) diff --git a/ios/Classes/InAppWebViewStatic.swift b/ios/Classes/InAppWebViewStatic.swift index 1982cc66..a14792c5 100755 --- a/ios/Classes/InAppWebViewStatic.swift +++ b/ios/Classes/InAppWebViewStatic.swift @@ -10,13 +10,13 @@ import WebKit public class InAppWebViewStatic: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static" - static var registrar: FlutterPluginRegistrar? - static var webViewForUserAgent: WKWebView? - static var defaultUserAgent: String? + var plugin: SwiftFlutterPlugin? + var webViewForUserAgent: WKWebView? + var defaultUserAgent: String? - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: InAppWebViewStatic.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())) - InAppWebViewStatic.registrar = registrar + init(plugin: SwiftFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: InAppWebViewStatic.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -24,7 +24,7 @@ public class InAppWebViewStatic: ChannelDelegate { switch call.method { case "getDefaultUserAgent": - InAppWebViewStatic.getDefaultUserAgent(completionHandler: { (value) in + getDefaultUserAgent(completionHandler: { (value) in result(value) }) break @@ -42,10 +42,10 @@ public class InAppWebViewStatic: ChannelDelegate { } } - static public func getDefaultUserAgent(completionHandler: @escaping (_ value: String?) -> Void) { + public func getDefaultUserAgent(completionHandler: @escaping (_ value: String?) -> Void) { if defaultUserAgent == nil { - InAppWebViewStatic.webViewForUserAgent = WKWebView() - InAppWebViewStatic.webViewForUserAgent?.evaluateJavaScript("navigator.userAgent") { (value, error) in + webViewForUserAgent = WKWebView() + webViewForUserAgent?.evaluateJavaScript("navigator.userAgent") { (value, error) in if error != nil { print("Error occured to get userAgent") @@ -55,8 +55,8 @@ public class InAppWebViewStatic: ChannelDelegate { } if let unwrappedUserAgent = value as? String { - InAppWebViewStatic.defaultUserAgent = unwrappedUserAgent - completionHandler(defaultUserAgent) + self.defaultUserAgent = unwrappedUserAgent + completionHandler(self.defaultUserAgent) } else { print("Failed to get userAgent") } @@ -69,9 +69,9 @@ public class InAppWebViewStatic: ChannelDelegate { public override func dispose() { super.dispose() - InAppWebViewStatic.registrar = nil - InAppWebViewStatic.webViewForUserAgent = nil - InAppWebViewStatic.defaultUserAgent = nil + plugin = nil + webViewForUserAgent = nil + defaultUserAgent = nil } deinit { diff --git a/ios/Classes/MyCookieManager.swift b/ios/Classes/MyCookieManager.swift index 182f31cf..f8fca748 100755 --- a/ios/Classes/MyCookieManager.swift +++ b/ios/Classes/MyCookieManager.swift @@ -11,13 +11,12 @@ import WebKit @available(iOS 11.0, *) public class MyCookieManager: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager" - static var registrar: FlutterPluginRegistrar? - static var httpCookieStore: WKHTTPCookieStore? + var plugin: SwiftFlutterPlugin? + static var httpCookieStore = WKWebsiteDataStore.default().httpCookieStore - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: MyCookieManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())) - MyCookieManager.registrar = registrar - MyCookieManager.httpCookieStore = WKWebsiteDataStore.default().httpCookieStore + init(plugin: SwiftFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: MyCookieManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -92,11 +91,6 @@ public class MyCookieManager: ChannelDelegate { isHttpOnly: Bool?, sameSite: String?, result: @escaping FlutterResult) { - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(false) - return - } - var properties: [HTTPCookiePropertyKey: Any] = [:] properties[.originURL] = url properties[.name] = name @@ -139,7 +133,7 @@ public class MyCookieManager: ChannelDelegate { let cookie = HTTPCookie(properties: properties)! - httpCookieStore.setCookie(cookie, completionHandler: {() in + MyCookieManager.httpCookieStore.setCookie(cookie, completionHandler: {() in result(true) }) } @@ -147,13 +141,8 @@ public class MyCookieManager: ChannelDelegate { public static func getCookies(url: String, result: @escaping FlutterResult) { var cookieList: [[String: Any?]] = [] - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(cookieList) - return - } - if let urlHost = URL(string: url)?.host { - httpCookieStore.getAllCookies { (cookies) in + MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { if urlHost.hasSuffix(cookie.domain) || ".\(urlHost)".hasSuffix(cookie.domain) { var sameSite: String? = nil @@ -195,12 +184,7 @@ public class MyCookieManager: ChannelDelegate { public static func getAllCookies(result: @escaping FlutterResult) { var cookieList: [[String: Any?]] = [] - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(cookieList) - return - } - - httpCookieStore.getAllCookies { (cookies) in + MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { var sameSite: String? = nil if #available(iOS 13.0, *) { @@ -232,13 +216,8 @@ public class MyCookieManager: ChannelDelegate { } public static func deleteCookie(url: String, name: String, path: String, domain: String?, result: @escaping FlutterResult) { - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(false) - return - } - var domain = domain - httpCookieStore.getAllCookies { (cookies) in + MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { var originURL = url if cookie.properties![.originURL] is String { @@ -255,7 +234,7 @@ public class MyCookieManager: ChannelDelegate { } } if let domain = domain, cookie.domain == domain, cookie.name == name, cookie.path == path { - httpCookieStore.delete(cookie, completionHandler: { + MyCookieManager.httpCookieStore.delete(cookie, completionHandler: { result(true) }) return @@ -266,13 +245,8 @@ public class MyCookieManager: ChannelDelegate { } public static func deleteCookies(url: String, path: String, domain: String?, result: @escaping FlutterResult) { - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(false) - return - } - var domain = domain - httpCookieStore.getAllCookies { (cookies) in + MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { var originURL = url if cookie.properties![.originURL] is String { @@ -289,7 +263,7 @@ public class MyCookieManager: ChannelDelegate { } } if let domain = domain, cookie.domain == domain, cookie.path == path { - httpCookieStore.delete(cookie, completionHandler: nil) + MyCookieManager.httpCookieStore.delete(cookie, completionHandler: nil) } } result(true) @@ -306,8 +280,7 @@ public class MyCookieManager: ChannelDelegate { public override func dispose() { super.dispose() - MyCookieManager.registrar = nil - MyCookieManager.httpCookieStore = nil + plugin = nil } deinit { diff --git a/ios/Classes/MyWebStorageManager.swift b/ios/Classes/MyWebStorageManager.swift index dd010724..131afc48 100755 --- a/ios/Classes/MyWebStorageManager.swift +++ b/ios/Classes/MyWebStorageManager.swift @@ -11,13 +11,12 @@ import WebKit @available(iOS 9.0, *) public class MyWebStorageManager: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager" - static var registrar: FlutterPluginRegistrar? - static var websiteDataStore: WKWebsiteDataStore? + var plugin: SwiftFlutterPlugin? + static var websiteDataStore = WKWebsiteDataStore.default() - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: MyWebStorageManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())) - MyWebStorageManager.registrar = registrar - MyWebStorageManager.websiteDataStore = WKWebsiteDataStore.default() + init(plugin: SwiftFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: MyWebStorageManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -45,13 +44,8 @@ public class MyWebStorageManager: ChannelDelegate { public static func fetchDataRecords(dataTypes: Set, result: @escaping FlutterResult) { var recordList: [[String: Any?]] = [] - - guard let websiteDataStore = MyWebStorageManager.websiteDataStore else { - result(recordList) - return - } - - websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in + + MyWebStorageManager.websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in for record in data { recordList.append([ "displayName": record.displayName, @@ -66,13 +60,8 @@ public class MyWebStorageManager: ChannelDelegate { public static func removeDataFor(dataTypes: Set, recordList: [[String: Any?]], result: @escaping FlutterResult) { var records: [WKWebsiteDataRecord] = [] - - guard let websiteDataStore = MyWebStorageManager.websiteDataStore else { - result(false) - return - } - - websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in + + MyWebStorageManager.websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in for record in data { for r in recordList { let displayName = r["displayName"] as! String @@ -82,28 +71,22 @@ public class MyWebStorageManager: ChannelDelegate { } } } - websiteDataStore.removeData(ofTypes: dataTypes, for: records) { + MyWebStorageManager.websiteDataStore.removeData(ofTypes: dataTypes, for: records) { result(true) } } } public static func removeDataModifiedSince(dataTypes: Set, timestamp: Int64, result: @escaping FlutterResult) { - guard let websiteDataStore = MyWebStorageManager.websiteDataStore else { - result(false) - return - } - let date = NSDate(timeIntervalSince1970: TimeInterval(timestamp)) - websiteDataStore.removeData(ofTypes: dataTypes, modifiedSince: date as Date) { + MyWebStorageManager.websiteDataStore.removeData(ofTypes: dataTypes, modifiedSince: date as Date) { result(true) } } public override func dispose() { super.dispose() - MyWebStorageManager.registrar = nil - MyWebStorageManager.websiteDataStore = nil + plugin = nil } deinit { diff --git a/ios/Classes/PlatformUtil.swift b/ios/Classes/PlatformUtil.swift index 9aa88e29..a49d5316 100644 --- a/ios/Classes/PlatformUtil.swift +++ b/ios/Classes/PlatformUtil.swift @@ -9,11 +9,11 @@ import Foundation public class PlatformUtil: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil" - static var registrar: FlutterPluginRegistrar? + var plugin: SwiftFlutterPlugin? - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: PlatformUtil.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())) - InAppWebViewStatic.registrar = registrar + init(plugin: SwiftFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: PlatformUtil.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -57,7 +57,7 @@ public class PlatformUtil: ChannelDelegate { public override func dispose() { super.dispose() - PlatformUtil.registrar = nil + plugin = nil } deinit { diff --git a/ios/Classes/PrintJob/PrintJobController.swift b/ios/Classes/PrintJob/PrintJobController.swift index bf28d131..84a2886c 100644 --- a/ios/Classes/PrintJob/PrintJobController.swift +++ b/ios/Classes/PrintJob/PrintJobController.swift @@ -18,6 +18,7 @@ public enum PrintJobState: Int { public class PrintJobController : NSObject, Disposable, UIPrintInteractionControllerDelegate { static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_printjobcontroller_" var id: String + var registrar: FlutterPluginRegistrar? var job: UIPrintInteractionController? var settings: PrintJobSettings? var printFormatter: UIPrintFormatter? @@ -26,8 +27,9 @@ public class PrintJobController : NSObject, Disposable, UIPrintInteractionContro var state = PrintJobState.created var creationTime = Int64(Date().timeIntervalSince1970 * 1000) - public init(id: String, job: UIPrintInteractionController? = nil, settings: PrintJobSettings? = nil) { + public init(registrar: FlutterPluginRegistrar, id: String, job: UIPrintInteractionController? = nil, settings: PrintJobSettings? = nil) { self.id = id + self.registrar = registrar super.init() self.job = job self.settings = settings @@ -35,7 +37,7 @@ public class PrintJobController : NSObject, Disposable, UIPrintInteractionContro self.printPageRenderer = job?.printPageRenderer self.job?.delegate = self let channel = FlutterMethodChannel(name: PrintJobController.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) + binaryMessenger: registrar.messenger()) self.channelDelegate = PrintJobChannelDelegate(printJobController: self, channel: channel) } @@ -92,5 +94,6 @@ public class PrintJobController : NSObject, Disposable, UIPrintInteractionContro job?.dismiss(animated: false) job = nil PrintJobManager.jobs[id] = nil + registrar = nil } } diff --git a/ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift b/ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift index ce189047..a8af3ed1 100755 --- a/ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift +++ b/ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift @@ -14,14 +14,14 @@ import SafariServices public class ChromeSafariBrowserManager: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_chromesafaribrowser" - static var registrar: FlutterPluginRegistrar? + var plugin: SwiftFlutterPlugin? static var browsers: [String: SafariViewController?] = [:] @available(iOS 15.0, *) static var prewarmingTokens: [String: SFSafariViewController.PrewarmingToken?] = [:] - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: ChromeSafariBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())) - ChromeSafariBrowserManager.registrar = registrar + init(plugin: SwiftFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: ChromeSafariBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -89,7 +89,7 @@ public class ChromeSafariBrowserManager: ChannelDelegate { public func open(id: String, url: String, settings: [String: Any?], menuItemList: [[String: Any]], result: @escaping FlutterResult) { let absoluteUrl = URL(string: url)!.absoluteURL - if #available(iOS 9.0, *) { + if #available(iOS 9.0, *), let plugin = plugin { if let flutterViewController = UIApplication.shared.delegate?.window.unsafelyUnwrapped?.rootViewController { // flutterViewController could be casted to FlutterViewController if needed @@ -101,11 +101,11 @@ public class ChromeSafariBrowserManager: ChannelDelegate { if #available(iOS 11.0, *) { let config = SFSafariViewController.Configuration() - safari = SafariViewController(id: id, url: absoluteUrl, configuration: config, + safari = SafariViewController(plugin: plugin, id: id, url: absoluteUrl, configuration: config, menuItemList: menuItemList, safariSettings: safariSettings) } else { // Fallback on earlier versions - safari = SafariViewController(id: id, url: absoluteUrl, entersReaderIfAvailable: safariSettings.entersReaderIfAvailable, + safari = SafariViewController(plugin: plugin, id: id, url: absoluteUrl, entersReaderIfAvailable: safariSettings.entersReaderIfAvailable, menuItemList: menuItemList, safariSettings: safariSettings) } @@ -125,7 +125,6 @@ public class ChromeSafariBrowserManager: ChannelDelegate { public override func dispose() { super.dispose() - ChromeSafariBrowserManager.registrar = nil let browsers = ChromeSafariBrowserManager.browsers.values browsers.forEach { (browser: SafariViewController?) in browser?.close(result: nil) @@ -138,6 +137,7 @@ public class ChromeSafariBrowserManager: ChannelDelegate { } ChromeSafariBrowserManager.prewarmingTokens.removeAll() } + plugin = nil } deinit { diff --git a/ios/Classes/SafariViewController/SafariViewController.swift b/ios/Classes/SafariViewController/SafariViewController.swift index 5bb41086..675e7f99 100755 --- a/ios/Classes/SafariViewController/SafariViewController.swift +++ b/ios/Classes/SafariViewController/SafariViewController.swift @@ -14,28 +14,31 @@ public class SafariViewController: SFSafariViewController, SFSafariViewControlle var channelDelegate: SafariViewControllerChannelDelegate? var safariSettings: SafariBrowserSettings var id: String + var plugin: SwiftFlutterPlugin? var menuItemList: [[String: Any]] = [] @available(iOS 11.0, *) - public init(id: String, url: URL, configuration: SFSafariViewController.Configuration, menuItemList: [[String: Any]] = [], safariSettings: SafariBrowserSettings) { + public init(plugin: SwiftFlutterPlugin, id: String, url: URL, configuration: SFSafariViewController.Configuration, menuItemList: [[String: Any]] = [], safariSettings: SafariBrowserSettings) { self.id = id + self.plugin = plugin self.menuItemList = menuItemList self.safariSettings = safariSettings SafariViewController.prepareConfig(configuration: configuration, safariSettings: safariSettings) super.init(url: url, configuration: configuration) let channel = FlutterMethodChannel(name: SafariViewController.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) + binaryMessenger: plugin.registrar!.messenger()) self.channelDelegate = SafariViewControllerChannelDelegate(safariViewController: self, channel: channel) self.delegate = self } - public init(id: String, url: URL, entersReaderIfAvailable: Bool, menuItemList: [[String: Any]] = [], safariSettings: SafariBrowserSettings) { + public init(plugin: SwiftFlutterPlugin, id: String, url: URL, entersReaderIfAvailable: Bool, menuItemList: [[String: Any]] = [], safariSettings: SafariBrowserSettings) { self.id = id + self.plugin = plugin self.menuItemList = menuItemList self.safariSettings = safariSettings super.init(url: url, entersReaderIfAvailable: entersReaderIfAvailable) let channel = FlutterMethodChannel(name: SafariViewController.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) + binaryMessenger: plugin.registrar!.messenger()) self.channelDelegate = SafariViewControllerChannelDelegate(safariViewController: self, channel: channel) self.delegate = self } @@ -123,6 +126,7 @@ public class SafariViewController: SFSafariViewController, SFSafariViewControlle channelDelegate = nil delegate = nil ChromeSafariBrowserManager.browsers[id] = nil + plugin = nil } deinit { diff --git a/ios/Classes/SwiftFlutterPlugin.swift b/ios/Classes/SwiftFlutterPlugin.swift index 03e97094..4dc52a7b 100755 --- a/ios/Classes/SwiftFlutterPlugin.swift +++ b/ios/Classes/SwiftFlutterPlugin.swift @@ -24,7 +24,6 @@ import SafariServices public class SwiftFlutterPlugin: NSObject, FlutterPlugin { - static var instance: SwiftFlutterPlugin? var registrar: FlutterPluginRegistrar? var platformUtil: PlatformUtil? var inAppWebViewStatic: InAppWebViewStatic? @@ -46,24 +45,24 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { self.registrar = registrar registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID) - platformUtil = PlatformUtil(registrar: registrar) - inAppBrowserManager = InAppBrowserManager(registrar: registrar) - headlessInAppWebViewManager = HeadlessInAppWebViewManager(registrar: registrar) - chromeSafariBrowserManager = ChromeSafariBrowserManager(registrar: registrar) - inAppWebViewStatic = InAppWebViewStatic(registrar: registrar) - credentialDatabase = CredentialDatabase(registrar: registrar) + platformUtil = PlatformUtil(plugin: self) + inAppBrowserManager = InAppBrowserManager(plugin: self) + headlessInAppWebViewManager = HeadlessInAppWebViewManager(plugin: self) + chromeSafariBrowserManager = ChromeSafariBrowserManager(plugin: self) + inAppWebViewStatic = InAppWebViewStatic(plugin: self) + credentialDatabase = CredentialDatabase(plugin: self) if #available(iOS 11.0, *) { - myCookieManager = MyCookieManager(registrar: registrar) + myCookieManager = MyCookieManager(plugin: self) } if #available(iOS 9.0, *) { - myWebStorageManager = MyWebStorageManager(registrar: registrar) + myWebStorageManager = MyWebStorageManager(plugin: self) } - webAuthenticationSessionManager = WebAuthenticationSessionManager(registrar: registrar) + webAuthenticationSessionManager = WebAuthenticationSessionManager(plugin: self) printJobManager = PrintJobManager() } public static func register(with registrar: FlutterPluginRegistrar) { - SwiftFlutterPlugin.instance = SwiftFlutterPlugin(with: registrar) + let _ = SwiftFlutterPlugin(with: registrar) } public func detachFromEngine(for registrar: FlutterPluginRegistrar) { diff --git a/ios/Classes/Util.swift b/ios/Classes/Util.swift index 419d25ce..c3313306 100644 --- a/ios/Classes/Util.swift +++ b/ios/Classes/Util.swift @@ -11,16 +11,16 @@ import WebKit var SharedLastTouchPointTimestamp: [InAppWebView: Int64] = [:] public class Util { - public static func getUrlAsset(assetFilePath: String) throws -> URL { - let key = SwiftFlutterPlugin.instance?.registrar?.lookupKey(forAsset: assetFilePath) + public static func getUrlAsset(registrar: FlutterPluginRegistrar, assetFilePath: String) throws -> URL { + let key = registrar.lookupKey(forAsset: assetFilePath) guard let assetURL = Bundle.main.url(forResource: key, withExtension: nil) else { throw NSError(domain: assetFilePath + " asset file cannot be found!", code: 0) } return assetURL } - public static func getAbsPathAsset(assetFilePath: String) throws -> String { - let key = SwiftFlutterPlugin.instance?.registrar?.lookupKey(forAsset: assetFilePath) + public static func getAbsPathAsset(registrar: FlutterPluginRegistrar, assetFilePath: String) throws -> String { + let key = registrar.lookupKey(forAsset: assetFilePath) guard let assetAbsPath = Bundle.main.path(forResource: key, ofType: nil) else { throw NSError(domain: assetFilePath + " asset file cannot be found!", code: 0) } diff --git a/ios/Classes/WebAuthenticationSession/WebAuthenticationSession.swift b/ios/Classes/WebAuthenticationSession/WebAuthenticationSession.swift index d69ad535..c38afc7c 100644 --- a/ios/Classes/WebAuthenticationSession/WebAuthenticationSession.swift +++ b/ios/Classes/WebAuthenticationSession/WebAuthenticationSession.swift @@ -12,6 +12,7 @@ import SafariServices public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentationContextProviding, Disposable { static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_webauthenticationsession_" var id: String + var plugin: SwiftFlutterPlugin? var url: URL var callbackURLScheme: String? var settings: WebAuthenticationSessionSettings @@ -19,8 +20,9 @@ public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentatio var channelDelegate: WebAuthenticationSessionChannelDelegate? private var _canStart = true - public init(id: String, url: URL, callbackURLScheme: String?, settings: WebAuthenticationSessionSettings) { + public init(plugin: SwiftFlutterPlugin, id: String, url: URL, callbackURLScheme: String?, settings: WebAuthenticationSessionSettings) { self.id = id + self.plugin = plugin self.url = url self.settings = settings super.init() @@ -35,7 +37,7 @@ public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentatio self.session = SFAuthenticationSession(url: self.url, callbackURLScheme: self.callbackURLScheme, completionHandler: self.completionHandler) } let channel = FlutterMethodChannel(name: WebAuthenticationSession.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) + binaryMessenger: plugin.registrar!.messenger()) self.channelDelegate = WebAuthenticationSessionChannelDelegate(webAuthenticationSession: self, channel: channel) } @@ -97,6 +99,7 @@ public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentatio channelDelegate = nil session = nil WebAuthenticationSessionManager.sessions[id] = nil + plugin = nil } deinit { diff --git a/ios/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift b/ios/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift index bfb21b9a..10536777 100644 --- a/ios/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift +++ b/ios/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift @@ -14,12 +14,12 @@ import SafariServices public class WebAuthenticationSessionManager: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_webauthenticationsession" - static var registrar: FlutterPluginRegistrar? + var plugin: SwiftFlutterPlugin? static var sessions: [String: WebAuthenticationSession?] = [:] - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: WebAuthenticationSessionManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger())) - WebAuthenticationSessionManager.registrar = registrar + init(plugin: SwiftFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: WebAuthenticationSessionManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger())) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -47,11 +47,11 @@ public class WebAuthenticationSessionManager: ChannelDelegate { } public func create(id: String, url: String, callbackURLScheme: String?, settings: [String: Any?], result: @escaping FlutterResult) { - if #available(iOS 11.0, *) { + if #available(iOS 11.0, *), let plugin = plugin { let sessionUrl = URL(string: url) ?? URL(string: "about:blank")! let initialSettings = WebAuthenticationSessionSettings() let _ = initialSettings.parse(settings: settings) - let session = WebAuthenticationSession(id: id, url: sessionUrl, callbackURLScheme: callbackURLScheme, settings: initialSettings) + let session = WebAuthenticationSession(plugin: plugin, id: id, url: sessionUrl, callbackURLScheme: callbackURLScheme, settings: initialSettings) session.prepare() WebAuthenticationSessionManager.sessions[id] = session result(true) @@ -63,13 +63,13 @@ public class WebAuthenticationSessionManager: ChannelDelegate { public override func dispose() { super.dispose() - WebAuthenticationSessionManager.registrar = nil let sessions = WebAuthenticationSessionManager.sessions.values sessions.forEach { (session: WebAuthenticationSession?) in session?.cancel() session?.dispose() } WebAuthenticationSessionManager.sessions.removeAll() + plugin = nil } deinit { diff --git a/macos/Classes/CredentialDatabase.swift b/macos/Classes/CredentialDatabase.swift index ff555380..c11ac05b 100755 --- a/macos/Classes/CredentialDatabase.swift +++ b/macos/Classes/CredentialDatabase.swift @@ -10,13 +10,12 @@ import FlutterMacOS public class CredentialDatabase: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database" - static var registrar: FlutterPluginRegistrar? - static var credentialStore: URLCredentialStorage? + var plugin: InAppWebViewFlutterPlugin? + static var credentialStore = URLCredentialStorage.shared - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: CredentialDatabase.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger)) - CredentialDatabase.registrar = registrar - CredentialDatabase.credentialStore = URLCredentialStorage.shared + init(plugin: InAppWebViewFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: CredentialDatabase.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger)) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -24,11 +23,8 @@ public class CredentialDatabase: ChannelDelegate { switch call.method { case "getAllAuthCredentials": var allCredentials: [[String: Any?]] = [] - guard let credentialStore = CredentialDatabase.credentialStore else { - result(allCredentials) - return - } - for (protectionSpace, credentials) in credentialStore.allCredentials { + + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { var crendentials: [[String: Any?]] = [] for c in credentials { let credential: [String: Any?] = c.value.toMap() @@ -46,11 +42,7 @@ public class CredentialDatabase: ChannelDelegate { break case "getHttpAuthCredentials": var crendentials: [[String: Any?]] = [] - guard let credentialStore = CredentialDatabase.credentialStore else { - result(crendentials) - return - } - + let host = arguments!["host"] as! String let urlProtocol = arguments!["protocol"] as? String let urlPort = arguments!["port"] as? Int ?? 0 @@ -59,7 +51,7 @@ public class CredentialDatabase: ChannelDelegate { realm = nil } - for (protectionSpace, credentials) in credentialStore.allCredentials { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { if protectionSpace.host == host && protectionSpace.realm == realm && protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { for c in credentials { @@ -71,11 +63,6 @@ public class CredentialDatabase: ChannelDelegate { result(crendentials) break case "setHttpAuthCredential": - guard let credentialStore = CredentialDatabase.credentialStore else { - result(false) - return - } - let host = arguments!["host"] as! String let urlProtocol = arguments!["protocol"] as? String let urlPort = arguments!["port"] as? Int ?? 0 @@ -86,17 +73,12 @@ public class CredentialDatabase: ChannelDelegate { let username = arguments!["username"] as! String let password = arguments!["password"] as! String let credential = URLCredential(user: username, password: password, persistence: .permanent) - credentialStore.set(credential, + CredentialDatabase.credentialStore.set(credential, for: URLProtectionSpace(host: host, port: urlPort, protocol: urlProtocol, realm: realm, authenticationMethod: NSURLAuthenticationMethodHTTPBasic)) result(true) break case "removeHttpAuthCredential": - guard let credentialStore = CredentialDatabase.credentialStore else { - result(false) - return - } - let host = arguments!["host"] as! String let urlProtocol = arguments!["protocol"] as? String let urlPort = arguments!["port"] as? Int ?? 0 @@ -110,7 +92,7 @@ public class CredentialDatabase: ChannelDelegate { var credential: URLCredential? = nil; var protectionSpaceCredential: URLProtectionSpace? = nil - for (protectionSpace, credentials) in credentialStore.allCredentials { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { if protectionSpace.host == host && protectionSpace.realm == realm && protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { for c in credentials { @@ -127,17 +109,12 @@ public class CredentialDatabase: ChannelDelegate { } if let c = credential, let protectionSpace = protectionSpaceCredential { - credentialStore.remove(c, for: protectionSpace) + CredentialDatabase.credentialStore.remove(c, for: protectionSpace) } result(true) break case "removeHttpAuthCredentials": - guard let credentialStore = CredentialDatabase.credentialStore else { - result(false) - return - } - let host = arguments!["host"] as! String let urlProtocol = arguments!["protocol"] as? String let urlPort = arguments!["port"] as? Int ?? 0 @@ -149,7 +126,7 @@ public class CredentialDatabase: ChannelDelegate { var credentialsToRemove: [URLCredential] = []; var protectionSpaceCredential: URLProtectionSpace? = nil - for (protectionSpace, credentials) in credentialStore.allCredentials { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { if protectionSpace.host == host && protectionSpace.realm == realm && protectionSpace.protocol == urlProtocol && protectionSpace.port == urlPort { protectionSpaceCredential = protectionSpace @@ -164,21 +141,16 @@ public class CredentialDatabase: ChannelDelegate { if let protectionSpace = protectionSpaceCredential { for credential in credentialsToRemove { - credentialStore.remove(credential, for: protectionSpace) + CredentialDatabase.credentialStore.remove(credential, for: protectionSpace) } } result(true) break case "clearAllAuthCredentials": - guard let credentialStore = CredentialDatabase.credentialStore else { - result(false) - return - } - - for (protectionSpace, credentials) in credentialStore.allCredentials { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { for credential in credentials { - credentialStore.remove(credential.value, for: protectionSpace) + CredentialDatabase.credentialStore.remove(credential.value, for: protectionSpace) } } result(true) @@ -191,8 +163,7 @@ public class CredentialDatabase: ChannelDelegate { public override func dispose() { super.dispose() - CredentialDatabase.registrar = nil - CredentialDatabase.credentialStore = nil + plugin = nil } deinit { diff --git a/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift b/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift index be9e42f1..8e947423 100644 --- a/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift +++ b/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebView.swift @@ -13,12 +13,14 @@ public class HeadlessInAppWebView : Disposable { var id: String var channelDelegate: HeadlessWebViewChannelDelegate? var flutterWebView: FlutterWebViewController? + var plugin: InAppWebViewFlutterPlugin? - public init(id: String, flutterWebView: FlutterWebViewController) { + public init(plugin: InAppWebViewFlutterPlugin, id: String, flutterWebView: FlutterWebViewController) { self.id = id self.flutterWebView = flutterWebView + self.plugin = plugin let channel = FlutterMethodChannel(name: HeadlessInAppWebView.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger) + binaryMessenger: plugin.registrar!.messenger) self.channelDelegate = HeadlessWebViewChannelDelegate(headlessWebView: self, channel: channel) } @@ -84,6 +86,7 @@ public class HeadlessInAppWebView : Disposable { view.superview?.removeFromSuperview() } flutterWebView = nil + plugin = nil } deinit { diff --git a/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift b/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift index 92354e8b..f2d14cbc 100644 --- a/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift +++ b/macos/Classes/HeadlessInAppWebView/HeadlessInAppWebViewManager.swift @@ -15,12 +15,12 @@ import AVFoundation public class HeadlessInAppWebViewManager: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_headless_inappwebview" - static var registrar: FlutterPluginRegistrar? + var plugin: InAppWebViewFlutterPlugin? static var webViews: [String: HeadlessInAppWebView?] = [:] - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger)) - HeadlessInAppWebViewManager.registrar = registrar + init(plugin: InAppWebViewFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: HeadlessInAppWebViewManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger)) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -30,7 +30,7 @@ public class HeadlessInAppWebViewManager: ChannelDelegate { switch call.method { case "run": let params = arguments!["params"] as! [String: Any?] - HeadlessInAppWebViewManager.run(id: id, params: params) + run(id: id, params: params) result(true) break default: @@ -39,12 +39,15 @@ public class HeadlessInAppWebViewManager: ChannelDelegate { } } - public static func run(id: String, params: [String: Any?]) { - let flutterWebView = FlutterWebViewController(registrar: HeadlessInAppWebViewManager.registrar!, + public func run(id: String, params: [String: Any?]) { + guard let plugin = plugin, let registrar = plugin.registrar else { + return + } + let flutterWebView = FlutterWebViewController(registrar: registrar, withFrame: CGRect.zero, viewIdentifier: id, params: params as NSDictionary) - let headlessInAppWebView = HeadlessInAppWebView(id: id, flutterWebView: flutterWebView) + let headlessInAppWebView = HeadlessInAppWebView(plugin: plugin, id: id, flutterWebView: flutterWebView) HeadlessInAppWebViewManager.webViews[id] = headlessInAppWebView headlessInAppWebView.prepare(params: params as NSDictionary) @@ -54,12 +57,12 @@ public class HeadlessInAppWebViewManager: ChannelDelegate { public override func dispose() { super.dispose() - HeadlessInAppWebViewManager.registrar = nil let headlessWebViews = HeadlessInAppWebViewManager.webViews.values headlessWebViews.forEach { (headlessWebView: HeadlessInAppWebView?) in headlessWebView?.dispose() } HeadlessInAppWebViewManager.webViews.removeAll() + plugin = nil } deinit { diff --git a/macos/Classes/InAppBrowser/InAppBrowserManager.swift b/macos/Classes/InAppBrowser/InAppBrowserManager.swift index fdc8ee5f..30fe7ca3 100755 --- a/macos/Classes/InAppBrowser/InAppBrowserManager.swift +++ b/macos/Classes/InAppBrowser/InAppBrowserManager.swift @@ -16,11 +16,11 @@ public class InAppBrowserManager: ChannelDelegate { static let WEBVIEW_STORYBOARD = "WebView" static let WEBVIEW_STORYBOARD_CONTROLLER_ID = "viewController" static let NAV_STORYBOARD_CONTROLLER_ID = "navController" - static var registrar: FlutterPluginRegistrar? + var plugin: InAppWebViewFlutterPlugin? - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: InAppBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger)) - InAppBrowserManager.registrar = registrar + init(plugin: InAppWebViewFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: InAppBrowserManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger)) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -60,6 +60,7 @@ public class InAppBrowserManager: ChannelDelegate { let _ = webViewSettings.parse(settings: settings) let webViewController = InAppBrowserWebViewController() + webViewController.plugin = plugin webViewController.browserSettings = browserSettings webViewController.webViewSettings = webViewSettings @@ -103,7 +104,7 @@ public class InAppBrowserManager: ChannelDelegate { public override func dispose() { super.dispose() - InAppBrowserManager.registrar = nil + plugin = nil } deinit { diff --git a/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift b/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift index 3080b552..8df02349 100755 --- a/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift +++ b/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift @@ -17,6 +17,7 @@ public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelega var window: InAppBrowserWindow? var id: String = "" + var plugin: InAppWebViewFlutterPlugin? var windowId: Int64? var webView: InAppWebView? var channelDelegate: InAppBrowserChannelDelegate? @@ -32,7 +33,11 @@ public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelega var isHidden = false public override func loadView() { - let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger) + guard let registrar = plugin?.registrar else { + return + } + + let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: registrar.messenger) channelDelegate = InAppBrowserChannelDelegate(channel: channel) var userScripts: [UserScript] = [] @@ -61,7 +66,7 @@ public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelega webView.channelDelegate = WebViewChannelDelegate(webView: webView, channel: channel) let findInteractionController = FindInteractionController( - registrar: SwiftFlutterPlugin.instance!.registrar!, + registrar: registrar, id: id, webView: webView, settings: nil) webView.findInteractionController = findInteractionController findInteractionController.prepare() @@ -304,6 +309,7 @@ public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelega webView?.dispose() webView = nil window = nil + plugin = nil } deinit { diff --git a/macos/Classes/InAppBrowser/InAppBrowserWindow.swift b/macos/Classes/InAppBrowser/InAppBrowserWindow.swift index d01d7bf5..613e3831 100644 --- a/macos/Classes/InAppBrowser/InAppBrowserWindow.swift +++ b/macos/Classes/InAppBrowser/InAppBrowserWindow.swift @@ -220,19 +220,18 @@ public class InAppBrowserWindow : NSWindow, NSWindowDelegate, NSToolbarDelegate, public func hide() { orderOut(self) - } public func show() { + let mainWindow = parent ?? NSApplication.shared.mainWindow if #available(macOS 10.12, *), - !(NSApplication.shared.mainWindow?.tabbedWindows?.contains(self) ?? false), + !(mainWindow?.tabbedWindows?.contains(self) ?? false), browserSettings?.windowType == .tabbed { - NSApplication.shared.mainWindow?.addTabbedWindow(self, ordered: .above) - } else if !(NSApplication.shared.mainWindow?.childWindows?.contains(self) ?? false) { - NSApplication.shared.mainWindow?.addChildWindow(self, ordered: .above) - } else { - orderFront(self) + mainWindow?.addTabbedWindow(self, ordered: .above) + } else if !(mainWindow?.childWindows?.contains(self) ?? false) { + mainWindow?.addChildWindow(self, ordered: .above) } + makeKeyAndOrderFront(self) NSApplication.shared.activate(ignoringOtherApps: true) } @@ -261,6 +260,19 @@ public class InAppBrowserWindow : NSWindow, NSWindowDelegate, NSToolbarDelegate, backgroundColor = nil } } + if #available(macOS 11.0, *), newSettingsMap["windowTitlebarSeparatorStyle"] != nil, + browserSettings?.windowTitlebarSeparatorStyle != newSettings.windowTitlebarSeparatorStyle { + titlebarSeparatorStyle = newSettings.windowTitlebarSeparatorStyle! + } + if newSettingsMap["windowAlphaValue"] != nil, browserSettings?.windowAlphaValue != newSettings.windowAlphaValue { + alphaValue = newSettings.windowAlphaValue + } + if newSettingsMap["windowStyleMask"] != nil, browserSettings?.windowStyleMask != newSettings.windowStyleMask { + styleMask = newSettings.windowStyleMask! + } + if newSettingsMap["windowFrame"] != nil, browserSettings?.windowFrame != newSettings.windowFrame { + setFrame(newSettings.windowFrame!, display: true) + } browserSettings = newSettings } diff --git a/macos/Classes/InAppWebView/FlutterWebViewController.swift b/macos/Classes/InAppWebView/FlutterWebViewController.swift index a8671f0e..1e11f30c 100755 --- a/macos/Classes/InAppWebView/FlutterWebViewController.swift +++ b/macos/Classes/InAppWebView/FlutterWebViewController.swift @@ -52,7 +52,7 @@ public class FlutterWebViewController: NSObject, /*FlutterPlatformView,*/ Dispos } let findInteractionController = FindInteractionController( - registrar: SwiftFlutterPlugin.instance!.registrar!, + registrar: registrar, id: viewId, webView: webView!, settings: nil) webView!.findInteractionController = findInteractionController findInteractionController.prepare() diff --git a/macos/Classes/InAppWebView/InAppWebView.swift b/macos/Classes/InAppWebView/InAppWebView.swift index a4bce0a5..010f9c34 100755 --- a/macos/Classes/InAppWebView/InAppWebView.swift +++ b/macos/Classes/InAppWebView/InAppWebView.swift @@ -16,6 +16,7 @@ public class InAppWebView: WKWebView, WKUIDelegate, static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_" var id: Any? // viewId + var registrar: FlutterPluginRegistrar? var windowId: Int64? var windowCreated = false var inAppBrowserDelegate: InAppBrowserDelegate? @@ -53,6 +54,7 @@ public class InAppWebView: WKWebView, WKUIDelegate, userScripts: [UserScript] = []) { super.init(frame: frame, configuration: configuration) self.id = id + self.registrar = registrar if let id = id, let registrar = registrar { let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: id), binaryMessenger: registrar.messenger) @@ -1367,8 +1369,8 @@ public class InAppWebView: WKWebView, WKUIDelegate, completionHandler(.useCredential, credential) break case 2: - if InAppWebView.credentialsProposed.count == 0, let credentialStore = CredentialDatabase.credentialStore { - for (protectionSpace, credentials) in credentialStore.allCredentials { + if InAppWebView.credentialsProposed.count == 0 { + for (protectionSpace, credentials) in CredentialDatabase.credentialStore.allCredentials { if protectionSpace.host == host && protectionSpace.realm == realm && protectionSpace.protocol == prot && protectionSpace.port == port { for credential in credentials { @@ -2356,8 +2358,8 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { } } - if let id = printJobId { - let printJob = PrintJobController(id: id, job: printOperation, settings: settings) + if let id = printJobId, let registrar = registrar { + let printJob = PrintJobController(registrar: registrar, id: id, job: printOperation, settings: settings) PrintJobManager.jobs[id] = printJob printJob.present(parentWindow: window, completionHandler: completionHandler) } else if let window = window { @@ -2455,9 +2457,13 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { } } - public func createWebMessageChannel(completionHandler: ((WebMessageChannel) -> Void)? = nil) -> WebMessageChannel { + public func createWebMessageChannel(completionHandler: ((WebMessageChannel?) -> Void)? = nil) -> WebMessageChannel? { + guard let registrar = registrar else { + completionHandler?(nil) + return nil + } let id = NSUUID().uuidString - let webMessageChannel = WebMessageChannel(id: id) + let webMessageChannel = WebMessageChannel(registrar: registrar, id: id) webMessageChannel.initJsInstance(webView: self, completionHandler: completionHandler) webMessageChannels[id] = webMessageChannel @@ -2576,6 +2582,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { isPausedTimersCompletionHandler = nil callAsyncJavaScriptBelowIOS14Results.removeAll() super.removeFromSuperview() + registrar = nil } deinit { diff --git a/macos/Classes/InAppWebView/WebMessage/WebMessageChannel.swift b/macos/Classes/InAppWebView/WebMessage/WebMessageChannel.swift index 79eb1feb..ef7639f2 100644 --- a/macos/Classes/InAppWebView/WebMessage/WebMessageChannel.swift +++ b/macos/Classes/InAppWebView/WebMessage/WebMessageChannel.swift @@ -14,12 +14,14 @@ public class WebMessageChannel : FlutterMethodCallDelegate { var channelDelegate: WebMessageChannelChannelDelegate? weak var webView: InAppWebView? var ports: [WebMessagePort] = [] + var registrar: FlutterPluginRegistrar? - public init(id: String) { + public init(registrar: FlutterPluginRegistrar, id: String) { self.id = id + self.registrar = registrar super.init() let channel = FlutterMethodChannel(name: WebMessageChannel.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger) + binaryMessenger: registrar.messenger) self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel) self.ports = [ WebMessagePort(name: "port1", webMessageChannel: self), @@ -27,7 +29,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate { ] } - public func initJsInstance(webView: InAppWebView, completionHandler: ((WebMessageChannel) -> Void)? = nil) { + public func initJsInstance(webView: InAppWebView, completionHandler: ((WebMessageChannel?) -> Void)? = nil) { self.webView = webView if let webView = self.webView { webView.evaluateJavascript(source: """ @@ -38,7 +40,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate { completionHandler?(self) } } else { - completionHandler?(self) + completionHandler?(nil) } } @@ -66,6 +68,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate { })(); """) webView = nil + registrar = nil } deinit { diff --git a/macos/Classes/InAppWebView/WebMessage/WebMessageListener.swift b/macos/Classes/InAppWebView/WebMessage/WebMessageListener.swift index dd7823ad..544481f7 100644 --- a/macos/Classes/InAppWebView/WebMessage/WebMessageListener.swift +++ b/macos/Classes/InAppWebView/WebMessage/WebMessageListener.swift @@ -16,14 +16,16 @@ public class WebMessageListener : FlutterMethodCallDelegate { var allowedOriginRules: Set var channelDelegate: WebMessageListenerChannelDelegate? weak var webView: InAppWebView? + var registrar: FlutterPluginRegistrar? - public init(id: String, jsObjectName: String, allowedOriginRules: Set) { + public init(registrar: FlutterPluginRegistrar, id: String, jsObjectName: String, allowedOriginRules: Set) { self.id = id + self.registrar = registrar self.jsObjectName = jsObjectName self.allowedOriginRules = allowedOriginRules super.init() let channel = FlutterMethodChannel(name: WebMessageListener.METHOD_CHANNEL_NAME_PREFIX + self.id + "_" + self.jsObjectName, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger) + binaryMessenger: registrar.messenger) self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel) } @@ -115,11 +117,12 @@ public class WebMessageListener : FlutterMethodCallDelegate { } } - public static func fromMap(map: [String:Any?]?) -> WebMessageListener? { + public static func fromMap(registrar: FlutterPluginRegistrar, map: [String:Any?]?) -> WebMessageListener? { guard let map = map else { return nil } return WebMessageListener( + registrar: registrar, id: map["id"] as! String, jsObjectName: map["jsObjectName"] as! String, allowedOriginRules: Set(map["allowedOriginRules"] as! [String]) @@ -178,6 +181,7 @@ public class WebMessageListener : FlutterMethodCallDelegate { channelDelegate?.dispose() channelDelegate = nil webView = nil + registrar = nil } deinit { diff --git a/macos/Classes/InAppWebView/WebViewChannelDelegate.swift b/macos/Classes/InAppWebView/WebViewChannelDelegate.swift index c8957c23..f4693c10 100644 --- a/macos/Classes/InAppWebView/WebViewChannelDelegate.swift +++ b/macos/Classes/InAppWebView/WebViewChannelDelegate.swift @@ -468,6 +468,10 @@ public class WebViewChannelDelegate : ChannelDelegate { case .createWebMessageChannel: if let webView = webView { let _ = webView.createWebMessageChannel { (webMessageChannel) in + guard let webMessageChannel = webMessageChannel else { + result(nil) + return + } result(webMessageChannel.toMap()) } } else { @@ -503,9 +507,9 @@ public class WebViewChannelDelegate : ChannelDelegate { } break case .addWebMessageListener: - if let webView = webView { + if let webView = webView, let registrar = webView.registrar { let webMessageListenerMap = arguments!["webMessageListener"] as! [String: Any?] - let webMessageListener = WebMessageListener.fromMap(map: webMessageListenerMap)! + let webMessageListener = WebMessageListener.fromMap(registrar: registrar, map: webMessageListenerMap)! do { try webView.addWebMessageListener(webMessageListener: webMessageListener) result(false) diff --git a/macos/Classes/InAppWebViewFlutterPlugin.swift b/macos/Classes/InAppWebViewFlutterPlugin.swift index c0c8043e..4e8bca9e 100644 --- a/macos/Classes/InAppWebViewFlutterPlugin.swift +++ b/macos/Classes/InAppWebViewFlutterPlugin.swift @@ -1,8 +1,86 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + import Cocoa import FlutterMacOS +import AppKit +import WebKit +import Foundation +import AVFoundation +import SafariServices public class InAppWebViewFlutterPlugin: NSObject, FlutterPlugin { - public static func register(with registrar: FlutterPluginRegistrar) { - SwiftFlutterPlugin.register(with: registrar) - } + + var registrar: FlutterPluginRegistrar? + var platformUtil: PlatformUtil? + var inAppWebViewStatic: InAppWebViewStatic? + var myCookieManager: Any? + var myWebStorageManager: MyWebStorageManager? + var credentialDatabase: CredentialDatabase? + var inAppBrowserManager: InAppBrowserManager? + var headlessInAppWebViewManager: HeadlessInAppWebViewManager? + var webAuthenticationSessionManager: WebAuthenticationSessionManager? +// var printJobManager: PrintJobManager? + + var webViewControllers: [String: InAppBrowserWebViewController?] = [:] + var safariViewControllers: [String: Any?] = [:] + + public init(with registrar: FlutterPluginRegistrar) { + super.init() + self.registrar = registrar + registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID) + + platformUtil = PlatformUtil(plugin: self) + inAppBrowserManager = InAppBrowserManager(plugin: self) + headlessInAppWebViewManager = HeadlessInAppWebViewManager(plugin: self) + inAppWebViewStatic = InAppWebViewStatic(plugin: self) + credentialDatabase = CredentialDatabase(plugin: self) + if #available(macOS 10.13, *) { + myCookieManager = MyCookieManager(plugin: self) + } + myWebStorageManager = MyWebStorageManager(plugin: self) + webAuthenticationSessionManager = WebAuthenticationSessionManager(plugin: self) +// printJobManager = PrintJobManager() + } + + public static func register(with registrar: FlutterPluginRegistrar) { + let _ = InAppWebViewFlutterPlugin(with: registrar) + } + + public func detachFromEngine(for registrar: FlutterPluginRegistrar) { + platformUtil?.dispose() + platformUtil = nil + inAppBrowserManager?.dispose() + inAppBrowserManager = nil + headlessInAppWebViewManager?.dispose() + headlessInAppWebViewManager = nil + inAppWebViewStatic?.dispose() + inAppWebViewStatic = nil + credentialDatabase?.dispose() + credentialDatabase = nil + if #available(macOS 10.13, *) { + (myCookieManager as! MyCookieManager?)?.dispose() + myCookieManager = nil + } + myWebStorageManager?.dispose() + myWebStorageManager = nil + webAuthenticationSessionManager?.dispose() + webAuthenticationSessionManager = nil +// printJobManager?.dispose() +// printJobManager = nil + } } diff --git a/macos/Classes/InAppWebViewStatic.swift b/macos/Classes/InAppWebViewStatic.swift index 8d28d1db..b8dc8c40 100755 --- a/macos/Classes/InAppWebViewStatic.swift +++ b/macos/Classes/InAppWebViewStatic.swift @@ -11,13 +11,13 @@ import FlutterMacOS public class InAppWebViewStatic: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static" - static var registrar: FlutterPluginRegistrar? - static var webViewForUserAgent: WKWebView? - static var defaultUserAgent: String? + var plugin: InAppWebViewFlutterPlugin? + var webViewForUserAgent: WKWebView? + var defaultUserAgent: String? - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: InAppWebViewStatic.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger)) - InAppWebViewStatic.registrar = registrar + init(plugin: InAppWebViewFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: InAppWebViewStatic.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger)) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -25,7 +25,7 @@ public class InAppWebViewStatic: ChannelDelegate { switch call.method { case "getDefaultUserAgent": - InAppWebViewStatic.getDefaultUserAgent(completionHandler: { (value) in + getDefaultUserAgent(completionHandler: { (value) in result(value) }) break @@ -43,10 +43,10 @@ public class InAppWebViewStatic: ChannelDelegate { } } - static public func getDefaultUserAgent(completionHandler: @escaping (_ value: String?) -> Void) { + public func getDefaultUserAgent(completionHandler: @escaping (_ value: String?) -> Void) { if defaultUserAgent == nil { - InAppWebViewStatic.webViewForUserAgent = WKWebView() - InAppWebViewStatic.webViewForUserAgent?.evaluateJavaScript("navigator.userAgent") { (value, error) in + webViewForUserAgent = WKWebView() + webViewForUserAgent?.evaluateJavaScript("navigator.userAgent") { (value, error) in if error != nil { print("Error occured to get userAgent") @@ -56,8 +56,8 @@ public class InAppWebViewStatic: ChannelDelegate { } if let unwrappedUserAgent = value as? String { - InAppWebViewStatic.defaultUserAgent = unwrappedUserAgent - completionHandler(defaultUserAgent) + self.defaultUserAgent = unwrappedUserAgent + completionHandler(self.defaultUserAgent) } else { print("Failed to get userAgent") } @@ -70,9 +70,9 @@ public class InAppWebViewStatic: ChannelDelegate { public override func dispose() { super.dispose() - InAppWebViewStatic.registrar = nil - InAppWebViewStatic.webViewForUserAgent = nil - InAppWebViewStatic.defaultUserAgent = nil + plugin = nil + webViewForUserAgent = nil + defaultUserAgent = nil } deinit { diff --git a/macos/Classes/MyCookieManager.swift b/macos/Classes/MyCookieManager.swift index f42f83d3..9ccce940 100755 --- a/macos/Classes/MyCookieManager.swift +++ b/macos/Classes/MyCookieManager.swift @@ -12,13 +12,12 @@ import FlutterMacOS @available(macOS 10.13, *) public class MyCookieManager: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager" - static var registrar: FlutterPluginRegistrar? - static var httpCookieStore: WKHTTPCookieStore? + var plugin: InAppWebViewFlutterPlugin? + static var httpCookieStore = WKWebsiteDataStore.default().httpCookieStore - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: MyCookieManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger)) - MyCookieManager.registrar = registrar - MyCookieManager.httpCookieStore = WKWebsiteDataStore.default().httpCookieStore + init(plugin: InAppWebViewFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: MyCookieManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger)) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -93,11 +92,6 @@ public class MyCookieManager: ChannelDelegate { isHttpOnly: Bool?, sameSite: String?, result: @escaping FlutterResult) { - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(false) - return - } - var properties: [HTTPCookiePropertyKey: Any] = [:] properties[.originURL] = url properties[.name] = name @@ -140,7 +134,7 @@ public class MyCookieManager: ChannelDelegate { let cookie = HTTPCookie(properties: properties)! - httpCookieStore.setCookie(cookie, completionHandler: {() in + MyCookieManager.httpCookieStore.setCookie(cookie, completionHandler: {() in result(true) }) } @@ -148,13 +142,8 @@ public class MyCookieManager: ChannelDelegate { public static func getCookies(url: String, result: @escaping FlutterResult) { var cookieList: [[String: Any?]] = [] - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(cookieList) - return - } - if let urlHost = URL(string: url)?.host { - httpCookieStore.getAllCookies { (cookies) in + MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { if urlHost.hasSuffix(cookie.domain) || ".\(urlHost)".hasSuffix(cookie.domain) { var sameSite: String? = nil @@ -196,12 +185,7 @@ public class MyCookieManager: ChannelDelegate { public static func getAllCookies(result: @escaping FlutterResult) { var cookieList: [[String: Any?]] = [] - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(cookieList) - return - } - - httpCookieStore.getAllCookies { (cookies) in + MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { var sameSite: String? = nil if #available(macOS 10.15, *) { @@ -233,13 +217,8 @@ public class MyCookieManager: ChannelDelegate { } public static func deleteCookie(url: String, name: String, path: String, domain: String?, result: @escaping FlutterResult) { - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(false) - return - } - var domain = domain - httpCookieStore.getAllCookies { (cookies) in + MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { var originURL = url if cookie.properties![.originURL] is String { @@ -252,7 +231,7 @@ public class MyCookieManager: ChannelDelegate { domain = domainUrl.host } if let domain = domain, cookie.domain == domain, cookie.name == name, cookie.path == path { - httpCookieStore.delete(cookie, completionHandler: { + MyCookieManager.httpCookieStore.delete(cookie, completionHandler: { result(true) }) return @@ -263,13 +242,8 @@ public class MyCookieManager: ChannelDelegate { } public static func deleteCookies(url: String, path: String, domain: String?, result: @escaping FlutterResult) { - guard let httpCookieStore = MyCookieManager.httpCookieStore else { - result(false) - return - } - var domain = domain - httpCookieStore.getAllCookies { (cookies) in + MyCookieManager.httpCookieStore.getAllCookies { (cookies) in for cookie in cookies { var originURL = url if cookie.properties![.originURL] is String { @@ -282,7 +256,7 @@ public class MyCookieManager: ChannelDelegate { domain = domainUrl.host } if let domain = domain, cookie.domain == domain, cookie.path == path { - httpCookieStore.delete(cookie, completionHandler: nil) + MyCookieManager.httpCookieStore.delete(cookie, completionHandler: nil) } } result(true) @@ -299,8 +273,7 @@ public class MyCookieManager: ChannelDelegate { public override func dispose() { super.dispose() - MyCookieManager.registrar = nil - MyCookieManager.httpCookieStore = nil + plugin = nil } deinit { diff --git a/macos/Classes/MyWebStorageManager.swift b/macos/Classes/MyWebStorageManager.swift index 274a8c3f..a20b46e6 100755 --- a/macos/Classes/MyWebStorageManager.swift +++ b/macos/Classes/MyWebStorageManager.swift @@ -11,13 +11,12 @@ import FlutterMacOS public class MyWebStorageManager: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager" - static var registrar: FlutterPluginRegistrar? - static var websiteDataStore: WKWebsiteDataStore? + var plugin: InAppWebViewFlutterPlugin? + static var websiteDataStore = WKWebsiteDataStore.default() - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: MyWebStorageManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger)) - MyWebStorageManager.registrar = registrar - MyWebStorageManager.websiteDataStore = WKWebsiteDataStore.default() + init(plugin: InAppWebViewFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: MyWebStorageManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger)) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -46,12 +45,7 @@ public class MyWebStorageManager: ChannelDelegate { public static func fetchDataRecords(dataTypes: Set, result: @escaping FlutterResult) { var recordList: [[String: Any?]] = [] - guard let websiteDataStore = MyWebStorageManager.websiteDataStore else { - result(recordList) - return - } - - websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in + MyWebStorageManager.websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in for record in data { recordList.append([ "displayName": record.displayName, @@ -67,12 +61,7 @@ public class MyWebStorageManager: ChannelDelegate { public static func removeDataFor(dataTypes: Set, recordList: [[String: Any?]], result: @escaping FlutterResult) { var records: [WKWebsiteDataRecord] = [] - guard let websiteDataStore = MyWebStorageManager.websiteDataStore else { - result(false) - return - } - - websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in + MyWebStorageManager.websiteDataStore.fetchDataRecords(ofTypes: dataTypes) { (data) in for record in data { for r in recordList { let displayName = r["displayName"] as! String @@ -89,21 +78,15 @@ public class MyWebStorageManager: ChannelDelegate { } public static func removeDataModifiedSince(dataTypes: Set, timestamp: Int64, result: @escaping FlutterResult) { - guard let websiteDataStore = MyWebStorageManager.websiteDataStore else { - result(false) - return - } - let date = NSDate(timeIntervalSince1970: TimeInterval(timestamp)) - websiteDataStore.removeData(ofTypes: dataTypes, modifiedSince: date as Date) { + MyWebStorageManager.websiteDataStore.removeData(ofTypes: dataTypes, modifiedSince: date as Date) { result(true) } } public override func dispose() { super.dispose() - MyWebStorageManager.registrar = nil - MyWebStorageManager.websiteDataStore = nil + plugin = nil } deinit { diff --git a/macos/Classes/PlatformUtil.swift b/macos/Classes/PlatformUtil.swift index 970d20e2..c9859d7d 100644 --- a/macos/Classes/PlatformUtil.swift +++ b/macos/Classes/PlatformUtil.swift @@ -10,11 +10,11 @@ import FlutterMacOS public class PlatformUtil: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil" - static var registrar: FlutterPluginRegistrar? + var plugin: InAppWebViewFlutterPlugin? - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: PlatformUtil.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger)) - InAppWebViewStatic.registrar = registrar + init(plugin: InAppWebViewFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: PlatformUtil.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger)) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -58,7 +58,7 @@ public class PlatformUtil: ChannelDelegate { public override func dispose() { super.dispose() - PlatformUtil.registrar = nil + plugin = nil } deinit { diff --git a/macos/Classes/PrintJob/PrintJobController.swift b/macos/Classes/PrintJob/PrintJobController.swift index 998038e9..a1780d9c 100644 --- a/macos/Classes/PrintJob/PrintJobController.swift +++ b/macos/Classes/PrintJob/PrintJobController.swift @@ -18,6 +18,7 @@ public enum PrintJobState: Int { public class PrintJobController : NSObject, Disposable { static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_printjobcontroller_" var id: String + var registrar: FlutterPluginRegistrar? var job: NSPrintOperation? var settings: PrintJobSettings? var channelDelegate: PrintJobChannelDelegate? @@ -29,13 +30,14 @@ public class PrintJobController : NSObject, Disposable { _ success: Bool, _ contextInfo: UnsafeMutableRawPointer?) -> Void - public init(id: String, job: NSPrintOperation? = nil, settings: PrintJobSettings? = nil) { + public init(registrar: FlutterPluginRegistrar, id: String, job: NSPrintOperation? = nil, settings: PrintJobSettings? = nil) { self.id = id + self.registrar = registrar super.init() self.job = job self.settings = settings let channel = FlutterMethodChannel(name: PrintJobController.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger) + binaryMessenger: registrar.messenger) self.channelDelegate = PrintJobChannelDelegate(printJobController: self, channel: channel) } @@ -83,5 +85,6 @@ public class PrintJobController : NSObject, Disposable { completionHandler = nil job = nil PrintJobManager.jobs[id] = nil + registrar = nil } } diff --git a/macos/Classes/SwiftFlutterPlugin.swift b/macos/Classes/SwiftFlutterPlugin.swift deleted file mode 100755 index 3a60cbca..00000000 --- a/macos/Classes/SwiftFlutterPlugin.swift +++ /dev/null @@ -1,86 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -import FlutterMacOS -import AppKit -import WebKit -import Foundation -import AVFoundation -import SafariServices - -public class SwiftFlutterPlugin: NSObject, FlutterPlugin { - - static var instance: SwiftFlutterPlugin? - var registrar: FlutterPluginRegistrar? - var platformUtil: PlatformUtil? - var inAppWebViewStatic: InAppWebViewStatic? - var myCookieManager: Any? - var myWebStorageManager: MyWebStorageManager? - var credentialDatabase: CredentialDatabase? - var inAppBrowserManager: InAppBrowserManager? - var headlessInAppWebViewManager: HeadlessInAppWebViewManager? - var webAuthenticationSessionManager: WebAuthenticationSessionManager? -// var printJobManager: PrintJobManager? - - var webViewControllers: [String: InAppBrowserWebViewController?] = [:] - var safariViewControllers: [String: Any?] = [:] - - public init(with registrar: FlutterPluginRegistrar) { - super.init() - self.registrar = registrar - registrar.register(FlutterWebViewFactory(registrar: registrar) as FlutterPlatformViewFactory, withId: FlutterWebViewFactory.VIEW_TYPE_ID) - - platformUtil = PlatformUtil(registrar: registrar) - inAppBrowserManager = InAppBrowserManager(registrar: registrar) - headlessInAppWebViewManager = HeadlessInAppWebViewManager(registrar: registrar) - inAppWebViewStatic = InAppWebViewStatic(registrar: registrar) - credentialDatabase = CredentialDatabase(registrar: registrar) - if #available(macOS 10.13, *) { - myCookieManager = MyCookieManager(registrar: registrar) - } - myWebStorageManager = MyWebStorageManager(registrar: registrar) - webAuthenticationSessionManager = WebAuthenticationSessionManager(registrar: registrar) -// printJobManager = PrintJobManager() - } - - public static func register(with registrar: FlutterPluginRegistrar) { - SwiftFlutterPlugin.instance = SwiftFlutterPlugin(with: registrar) - } - - public func detachFromEngine(for registrar: FlutterPluginRegistrar) { - platformUtil?.dispose() - platformUtil = nil - inAppBrowserManager?.dispose() - inAppBrowserManager = nil - headlessInAppWebViewManager?.dispose() - headlessInAppWebViewManager = nil - inAppWebViewStatic?.dispose() - inAppWebViewStatic = nil - credentialDatabase?.dispose() - credentialDatabase = nil - if #available(macOS 10.13, *) { - (myCookieManager as! MyCookieManager?)?.dispose() - myCookieManager = nil - } - myWebStorageManager?.dispose() - myWebStorageManager = nil - webAuthenticationSessionManager?.dispose() - webAuthenticationSessionManager = nil -// printJobManager?.dispose() -// printJobManager = nil - } -} diff --git a/macos/Classes/WebAuthenticationSession/WebAuthenticationSession.swift b/macos/Classes/WebAuthenticationSession/WebAuthenticationSession.swift index f25806e6..d48ec8ee 100644 --- a/macos/Classes/WebAuthenticationSession/WebAuthenticationSession.swift +++ b/macos/Classes/WebAuthenticationSession/WebAuthenticationSession.swift @@ -13,6 +13,7 @@ import FlutterMacOS public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentationContextProviding, Disposable { static let METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_webauthenticationsession_" var id: String + var plugin: InAppWebViewFlutterPlugin? var url: URL var callbackURLScheme: String? var settings: WebAuthenticationSessionSettings @@ -20,8 +21,9 @@ public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentatio var channelDelegate: WebAuthenticationSessionChannelDelegate? private var _canStart = true - public init(id: String, url: URL, callbackURLScheme: String?, settings: WebAuthenticationSessionSettings) { + public init(plugin: InAppWebViewFlutterPlugin, id: String, url: URL, callbackURLScheme: String?, settings: WebAuthenticationSessionSettings) { self.id = id + self.plugin = plugin self.url = url self.settings = settings super.init() @@ -32,7 +34,7 @@ public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentatio self.session = session } let channel = FlutterMethodChannel(name: WebAuthenticationSession.METHOD_CHANNEL_NAME_PREFIX + id, - binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger) + binaryMessenger: plugin.registrar!.messenger) self.channelDelegate = WebAuthenticationSessionChannelDelegate(webAuthenticationSession: self, channel: channel) } @@ -90,6 +92,7 @@ public class WebAuthenticationSession : NSObject, ASWebAuthenticationPresentatio channelDelegate = nil session = nil WebAuthenticationSessionManager.sessions[id] = nil + plugin = nil } deinit { diff --git a/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift b/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift index 43fae3ad..8267434b 100644 --- a/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift +++ b/macos/Classes/WebAuthenticationSession/WebAuthenticationSessionManager.swift @@ -14,12 +14,12 @@ import SafariServices public class WebAuthenticationSessionManager: ChannelDelegate { static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_webauthenticationsession" - static var registrar: FlutterPluginRegistrar? + var plugin: InAppWebViewFlutterPlugin? static var sessions: [String: WebAuthenticationSession?] = [:] - init(registrar: FlutterPluginRegistrar) { - super.init(channel: FlutterMethodChannel(name: WebAuthenticationSessionManager.METHOD_CHANNEL_NAME, binaryMessenger: registrar.messenger)) - WebAuthenticationSessionManager.registrar = registrar + init(plugin: InAppWebViewFlutterPlugin) { + super.init(channel: FlutterMethodChannel(name: WebAuthenticationSessionManager.METHOD_CHANNEL_NAME, binaryMessenger: plugin.registrar!.messenger)) + self.plugin = plugin } public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -47,11 +47,11 @@ public class WebAuthenticationSessionManager: ChannelDelegate { } public func create(id: String, url: String, callbackURLScheme: String?, settings: [String: Any?], result: @escaping FlutterResult) { - if #available(macOS 10.15, *) { + if #available(macOS 10.15, *), let plugin = plugin { let sessionUrl = URL(string: url) ?? URL(string: "about:blank")! let initialSettings = WebAuthenticationSessionSettings() let _ = initialSettings.parse(settings: settings) - let session = WebAuthenticationSession(id: id, url: sessionUrl, callbackURLScheme: callbackURLScheme, settings: initialSettings) + let session = WebAuthenticationSession(plugin: plugin, id: id, url: sessionUrl, callbackURLScheme: callbackURLScheme, settings: initialSettings) session.prepare() WebAuthenticationSessionManager.sessions[id] = session result(true) @@ -63,13 +63,13 @@ public class WebAuthenticationSessionManager: ChannelDelegate { public override func dispose() { super.dispose() - WebAuthenticationSessionManager.registrar = nil let sessions = WebAuthenticationSessionManager.sessions.values sessions.forEach { (session: WebAuthenticationSession?) in session?.cancel() session?.dispose() } WebAuthenticationSessionManager.sessions.removeAll() + plugin = nil } deinit {