completed ChannelDelegate iOS implementation

This commit is contained in:
Lorenzo Pichilli 2022-05-08 12:56:28 +02:00
parent 66add9f8ac
commit 373e970e80
43 changed files with 2272 additions and 1602 deletions

View File

@ -104,6 +104,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
pullToRefreshLayout.prepare(); pullToRefreshLayout.prepare();
webView = findViewById(R.id.webView); webView = findViewById(R.id.webView);
webView.id = id;
webView.windowId = windowId; webView.windowId = windowId;
webView.inAppBrowserDelegate = this; webView.inAppBrowserDelegate = this;
webView.plugin = manager.plugin; webView.plugin = manager.plugin;

View File

@ -1112,7 +1112,10 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
public void onLoadResourceCustomScheme(String url, @NonNull LoadResourceCustomSchemeCallback callback) { public void onLoadResourceCustomScheme(String url, @NonNull LoadResourceCustomSchemeCallback callback) {
MethodChannel channel = getChannel(); MethodChannel channel = getChannel();
if (channel == null) return; if (channel == null) {
callback.defaultBehaviour(null);
return;
}
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("url", url); obj.put("url", url);
channel.invokeMethod("onLoadResourceCustomScheme", obj, callback); channel.invokeMethod("onLoadResourceCustomScheme", obj, callback);
@ -1146,7 +1149,10 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
public void shouldInterceptRequest(WebResourceRequestExt request, @NonNull ShouldInterceptRequestCallback callback) { public void shouldInterceptRequest(WebResourceRequestExt request, @NonNull ShouldInterceptRequestCallback callback) {
MethodChannel channel = getChannel(); MethodChannel channel = getChannel();
if (channel == null) return; if (channel == null) {
callback.defaultBehaviour(null);
return;
}
channel.invokeMethod("shouldInterceptRequest", request.toMap(), callback); channel.invokeMethod("shouldInterceptRequest", request.toMap(), callback);
} }

View File

@ -7,7 +7,7 @@
import Foundation import Foundation
class CredentialDatabase: ChannelDelegate { public class CredentialDatabase: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database" static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var credentialStore: URLCredentialStorage? static var credentialStore: URLCredentialStorage?
@ -193,4 +193,8 @@ class CredentialDatabase: ChannelDelegate {
CredentialDatabase.registrar = nil CredentialDatabase.registrar = nil
CredentialDatabase.credentialStore = nil CredentialDatabase.credentialStore = nil
} }
deinit {
dispose()
}
} }

View File

@ -61,4 +61,8 @@ public class HeadlessInAppWebViewManager: ChannelDelegate {
} }
HeadlessInAppWebViewManager.webViews.removeAll() HeadlessInAppWebViewManager.webViews.removeAll()
} }
deinit {
dispose()
}
} }

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
public class HeadlessWebViewChannelDelegate : ChannelDelegate { public class HeadlessWebViewChannelDelegate : ChannelDelegate {
private var headlessWebView: HeadlessInAppWebView? private weak var headlessWebView: HeadlessInAppWebView?
public init(headlessWebView: HeadlessInAppWebView, channel: FlutterMethodChannel) { public init(headlessWebView: HeadlessInAppWebView, channel: FlutterMethodChannel) {
super.init(channel: channel) super.init(channel: channel)
@ -56,4 +56,8 @@ public class HeadlessWebViewChannelDelegate : ChannelDelegate {
super.dispose() super.dispose()
headlessWebView = nil headlessWebView = nil
} }
deinit {
dispose()
}
} }

View File

@ -21,4 +21,8 @@ public class InAppBrowserChannelDelegate : ChannelDelegate {
let arguments: [String: Any?] = [:] let arguments: [String: Any?] = [:]
channel?.invokeMethod("onExit", arguments: arguments) channel?.invokeMethod("onExit", arguments: arguments)
} }
deinit {
dispose()
}
} }

View File

@ -138,4 +138,8 @@ public class InAppBrowserManager: ChannelDelegate {
super.dispose() super.dispose()
InAppBrowserManager.registrar = nil InAppBrowserManager.registrar = nil
} }
deinit {
dispose()
}
} }

View File

@ -24,7 +24,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
var tmpWindow: UIWindow? var tmpWindow: UIWindow?
var id: String = "" var id: String = ""
var windowId: Int64? var windowId: Int64?
var webView: InAppWebView! var webView: InAppWebView?
var channelDelegate: InAppBrowserChannelDelegate? var channelDelegate: InAppBrowserChannelDelegate?
var initialUrlRequest: URLRequest? var initialUrlRequest: URLRequest?
var initialFile: String? var initialFile: String?
@ -38,7 +38,6 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
var previousStatusBarStyle = -1 var previousStatusBarStyle = -1
var initialUserScripts: [[String: Any]] = [] var initialUserScripts: [[String: Any]] = []
var pullToRefreshInitialSettings: [String: Any?] = [:] var pullToRefreshInitialSettings: [String: Any?] = [:]
var methodCallDelegate: InAppWebViewMethodHandler?
public override func loadView() { public override func loadView() {
let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
@ -52,20 +51,24 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: webViewSettings) let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: webViewSettings)
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] { if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
webView = webViewTransport.webView webView = webViewTransport.webView
webView.contextMenu = contextMenu webView!.contextMenu = contextMenu
webView.channel = channel webView!.initialUserScripts = userScripts
webView.initialUserScripts = userScripts
} else { } else {
webView = InAppWebView(frame: .zero, webView = InAppWebView(id: nil,
configuration: preWebviewConfiguration, registrar: nil,
contextMenu: contextMenu, frame: .zero,
channel: channel, configuration: preWebviewConfiguration,
userScripts: userScripts) contextMenu: contextMenu,
userScripts: userScripts)
} }
webView.inAppBrowserDelegate = self
methodCallDelegate = InAppWebViewMethodHandler(webView: webView!) guard let webView = webView else {
channel.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle) return
}
webView.inAppBrowserDelegate = self
webView.id = id
webView.channelDelegate = WebViewChannelDelegate(webView: webView, channel: channel)
let pullToRefreshSettings = PullToRefreshSettings() let pullToRefreshSettings = PullToRefreshSettings()
let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings) let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
@ -87,38 +90,41 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
public override func viewDidLoad() { public override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
webView.translatesAutoresizingMaskIntoConstraints = false webView?.translatesAutoresizingMaskIntoConstraints = false
progressBar.translatesAutoresizingMaskIntoConstraints = false progressBar.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 9.0, *) { if #available(iOS 9.0, *) {
webView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0.0).isActive = true webView?.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0.0).isActive = true
webView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0.0).isActive = true webView?.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0.0).isActive = true
webView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true webView?.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true
webView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true webView?.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true
progressBar.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0.0).isActive = true progressBar.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0.0).isActive = true
progressBar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true progressBar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true
progressBar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true progressBar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true
} else { } else {
view.addConstraints([ if let webView = webView {
NSLayoutConstraint(item: webView!, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0), view.addConstraints([
NSLayoutConstraint(item: webView!, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0), NSLayoutConstraint(item: webView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: webView!, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0), NSLayoutConstraint(item: webView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0),
NSLayoutConstraint(item: webView!, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1, constant: 0) NSLayoutConstraint(item: webView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0),
]) NSLayoutConstraint(item: webView, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1, constant: 0)
])
view.addConstraints([ }
NSLayoutConstraint(item: progressBar!, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0), if let progressBar = progressBar {
NSLayoutConstraint(item: progressBar!, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0), view.addConstraints([
NSLayoutConstraint(item: progressBar!, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1, constant: 0) NSLayoutConstraint(item: progressBar, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
]) NSLayoutConstraint(item: progressBar, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0),
NSLayoutConstraint(item: progressBar, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1, constant: 0)
])
}
} }
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] { if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
webView.load(webViewTransport.request) webView?.load(webViewTransport.request)
} else { } else {
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
if let contentBlockers = webView.settings?.contentBlockers, contentBlockers.count > 0 { if let contentBlockers = webView?.settings?.contentBlockers, contentBlockers.count > 0 {
do { do {
let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: []) let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: [])
let blockRules = String(data: jsonData, encoding: String.Encoding.utf8) let blockRules = String(data: jsonData, encoding: String.Encoding.utf8)
@ -165,27 +171,22 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
allowingReadAccessToURL = nil allowingReadAccessToURL = nil
} }
} }
webView.loadData(data: initialData, mimeType: initialMimeType!, encoding: initialEncoding!, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL) webView?.loadData(data: initialData, mimeType: initialMimeType!, encoding: initialEncoding!, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL)
} }
else if let initialUrlRequest = initialUrlRequest { else if let initialUrlRequest = initialUrlRequest {
var allowingReadAccessToURL: URL? = nil var allowingReadAccessToURL: URL? = nil
if let allowingReadAccessTo = webView.settings?.allowingReadAccessTo, let url = initialUrlRequest.url, url.scheme == "file" { if let allowingReadAccessTo = webView?.settings?.allowingReadAccessTo, let url = initialUrlRequest.url, url.scheme == "file" {
allowingReadAccessToURL = URL(string: allowingReadAccessTo) allowingReadAccessToURL = URL(string: allowingReadAccessTo)
if allowingReadAccessToURL?.scheme != "file" { if allowingReadAccessToURL?.scheme != "file" {
allowingReadAccessToURL = nil allowingReadAccessToURL = nil
} }
} }
webView.loadUrl(urlRequest: initialUrlRequest, allowingReadAccessTo: allowingReadAccessToURL) webView?.loadUrl(urlRequest: initialUrlRequest, allowingReadAccessTo: allowingReadAccessToURL)
} }
channelDelegate?.onBrowserCreated() channelDelegate?.onBrowserCreated()
} }
deinit {
debugPrint("InAppBrowserWebViewController - dealloc")
dispose()
}
public override func viewDidDisappear(_ animated: Bool) { public override func viewDidDisappear(_ animated: Bool) {
dispose() dispose()
super.viewDidDisappear(animated) super.viewDidDisappear(animated)
@ -203,8 +204,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
} }
public func prepareWebView() { public func prepareWebView() {
webView.settings = webViewSettings webView?.settings = webViewSettings
webView.prepare() webView?.prepare()
searchBar = UISearchBar() searchBar = UISearchBar()
searchBar.keyboardType = .URL searchBar.keyboardType = .URL
@ -305,8 +306,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
} }
public func didStartNavigation(url: URL?) { public func didStartNavigation(url: URL?) {
forwardButton.isEnabled = webView.canGoForward forwardButton.isEnabled = webView?.canGoForward ?? false
backButton.isEnabled = webView.canGoBack backButton.isEnabled = webView?.canGoBack ?? false
progressBar.setProgress(0.0, animated: false) progressBar.setProgress(0.0, animated: false)
guard let url = url else { guard let url = url else {
return return
@ -315,8 +316,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
} }
public func didUpdateVisitedHistory(url: URL?) { public func didUpdateVisitedHistory(url: URL?) {
forwardButton.isEnabled = webView.canGoForward forwardButton.isEnabled = webView?.canGoForward ?? false
backButton.isEnabled = webView.canGoBack backButton.isEnabled = webView?.canGoBack ?? false
guard let url = url else { guard let url = url else {
return return
} }
@ -324,8 +325,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
} }
public func didFinishNavigation(url: URL?) { public func didFinishNavigation(url: URL?) {
forwardButton.isEnabled = webView.canGoForward forwardButton.isEnabled = webView?.canGoForward ?? false
backButton.isEnabled = webView.canGoBack backButton.isEnabled = webView?.canGoBack ?? false
progressBar.setProgress(0.0, animated: false) progressBar.setProgress(0.0, animated: false)
guard let url = url else { guard let url = url else {
return return
@ -334,8 +335,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
} }
public func didFailNavigation(url: URL?, error: Error) { public func didFailNavigation(url: URL?, error: Error) {
forwardButton.isEnabled = webView.canGoForward forwardButton.isEnabled = webView?.canGoForward ?? false
backButton.isEnabled = webView.canGoBack backButton.isEnabled = webView?.canGoBack ?? false
progressBar.setProgress(0.0, animated: false) progressBar.setProgress(0.0, animated: false)
} }
@ -350,7 +351,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
return return
} }
let request = URLRequest(url: url) let request = URLRequest(url: url)
webView.load(request) webView?.load(request)
} }
public func show(completion: (() -> Void)? = nil) { public func show(completion: (() -> Void)? = nil) {
@ -381,12 +382,12 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
} }
@objc public func reload() { @objc public func reload() {
webView.reload() webView?.reload()
didUpdateVisitedHistory(url: webView.url) didUpdateVisitedHistory(url: webView?.url)
} }
@objc public func share() { @objc public func share() {
let vc = UIActivityViewController(activityItems: [webView.url?.absoluteString ?? ""], applicationActivities: []) let vc = UIActivityViewController(activityItems: [webView?.url?.absoluteString ?? ""], applicationActivities: [])
present(vc, animated: true, completion: nil) present(vc, animated: true, completion: nil)
} }
@ -413,26 +414,25 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
} }
@objc public func goBack() { @objc public func goBack() {
if webView.canGoBack { if let webView = webView, webView.canGoBack {
webView.goBack() webView.goBack()
} }
} }
@objc public func goForward() { @objc public func goForward() {
if webView.canGoForward { if let webView = webView, webView.canGoForward {
webView.goForward() webView.goForward()
} }
} }
@objc public func goBackOrForward(steps: Int) { @objc public func goBackOrForward(steps: Int) {
webView.goBackOrForward(steps: steps) webView?.goBackOrForward(steps: steps)
} }
public func setSettings(newSettings: InAppBrowserSettings, newSettingsMap: [String: Any]) { public func setSettings(newSettings: InAppBrowserSettings, newSettingsMap: [String: Any]) {
let newInAppWebViewSettings = InAppWebViewSettings()
let newInAppWebViewOptions = InAppWebViewSettings() let _ = newInAppWebViewSettings.parse(settings: newSettingsMap)
let _ = newInAppWebViewOptions.parse(settings: newSettingsMap) webView?.setSettings(newSettings: newInAppWebViewSettings, newSettingsMap: newSettingsMap)
self.webView.setSettings(newSettings: newInAppWebViewOptions, newSettingsMap: newSettingsMap)
if newSettingsMap["hidden"] != nil, browserSettings?.hidden != newSettings.hidden { if newSettingsMap["hidden"] != nil, browserSettings?.hidden != newSettings.hidden {
if newSettings.hidden { if newSettings.hidden {
@ -537,12 +537,12 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
progressBar.isHidden = newSettings.hideProgressBar progressBar.isHidden = newSettings.hideProgressBar
} }
self.browserSettings = newSettings browserSettings = newSettings
self.webViewSettings = newInAppWebViewOptions webViewSettings = newInAppWebViewSettings
} }
public func getSettings() -> [String: Any?]? { public func getSettings() -> [String: Any?]? {
let webViewSettingsMap = self.webView.getSettings() let webViewSettingsMap = webView?.getSettings()
if (self.browserSettings == nil || webViewSettingsMap == nil) { if (self.browserSettings == nil || webViewSettingsMap == nil) {
return nil return nil
} }
@ -568,7 +568,10 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
backButton.target = nil backButton.target = nil
reloadButton.target = nil reloadButton.target = nil
shareButton.target = nil shareButton.target = nil
methodCallDelegate?.webView = nil }
methodCallDelegate = nil
deinit {
debugPrint("InAppBrowserWebViewController - dealloc")
dispose()
} }
} }

View File

@ -7,7 +7,7 @@
import Foundation import Foundation
class ContextMenuSettings: ISettings<NSObject> { public class ContextMenuSettings: ISettings<NSObject> {
var hideDefaultSystemContextMenuItems = false; var hideDefaultSystemContextMenuItems = false;

View File

@ -10,37 +10,37 @@ import Foundation
import WebKit import WebKit
@available(iOS 11.0, *) @available(iOS 11.0, *)
class CustomSchemeHandler : NSObject, WKURLSchemeHandler { public class CustomSchemeHandler : NSObject, WKURLSchemeHandler {
var schemeHandlers: [Int:WKURLSchemeTask] = [:] var schemeHandlers: [Int:WKURLSchemeTask] = [:]
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { public func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
schemeHandlers[urlSchemeTask.hash] = urlSchemeTask schemeHandlers[urlSchemeTask.hash] = urlSchemeTask
let inAppWebView = webView as! InAppWebView let inAppWebView = webView as! InAppWebView
if let url = urlSchemeTask.request.url { if let url = urlSchemeTask.request.url {
inAppWebView.onLoadResourceCustomScheme(url: url.absoluteString, result: {(result) -> Void in let callback = WebViewChannelDelegate.LoadResourceCustomSchemeCallback()
if result is FlutterError { callback.nonNullSuccess = { (response: CustomSchemeResponse) in
print((result as! FlutterError).message ?? "") if (self.schemeHandlers[urlSchemeTask.hash] != nil) {
let urlResponse = URLResponse(url: url, mimeType: response.contentType, expectedContentLength: -1, textEncodingName: response.contentEncoding)
urlSchemeTask.didReceive(urlResponse)
urlSchemeTask.didReceive(response.data)
urlSchemeTask.didFinish()
self.schemeHandlers.removeValue(forKey: urlSchemeTask.hash)
} }
else if (result as? NSObject) == FlutterMethodNotImplemented {} return false
else { }
let json: [String: Any] callback.error = { (code: String, message: String?, details: Any?) in
if let r = result { print(code + ", " + (message ?? ""))
json = r as! [String: Any] }
let urlResponse = URLResponse(url: url, mimeType: (json["contentType"] as! String), expectedContentLength: -1, textEncodingName: (json["contentEncoding"] as! String))
let data = json["data"] as! FlutterStandardTypedData if let channelDelegate = inAppWebView.channelDelegate {
if (self.schemeHandlers[urlSchemeTask.hash] != nil) { channelDelegate.onLoadResourceCustomScheme(url: url, callback: callback)
urlSchemeTask.didReceive(urlResponse) } else {
urlSchemeTask.didReceive(data.data) callback.defaultBehaviour(nil)
urlSchemeTask.didFinish() }
self.schemeHandlers.removeValue(forKey: urlSchemeTask.hash)
}
}
}
})
} }
} }
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) { public func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
schemeHandlers.removeValue(forKey: urlSchemeTask.hash) schemeHandlers.removeValue(forKey: urlSchemeTask.hash)
} }
} }

View File

@ -8,24 +8,13 @@
import Foundation import Foundation
import WebKit import WebKit
public class FlutterWebViewController: NSObject, FlutterPlatformView { public class FlutterWebViewController: NSObject, FlutterPlatformView, Disposable {
private weak var registrar: FlutterPluginRegistrar?
var webView: InAppWebView?
var viewId: Any = 0
var channel: FlutterMethodChannel?
var myView: UIView? var myView: UIView?
var methodCallDelegate: InAppWebViewMethodHandler?
init(registrar: FlutterPluginRegistrar, withFrame frame: CGRect, viewIdentifier viewId: Any, params: NSDictionary) { init(registrar: FlutterPluginRegistrar, withFrame frame: CGRect, viewIdentifier viewId: Any, params: NSDictionary) {
super.init() super.init()
self.registrar = registrar
self.viewId = viewId
channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_" + String(describing: viewId),
binaryMessenger: registrar.messenger())
myView = UIView(frame: frame) myView = UIView(frame: frame)
myView!.clipsToBounds = true myView!.clipsToBounds = true
@ -46,23 +35,26 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
let _ = settings.parse(settings: initialSettings) let _ = settings.parse(settings: initialSettings)
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: settings) let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: settings)
var webView: InAppWebView?
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] { if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
webView = webViewTransport.webView webView = webViewTransport.webView
webView!.id = viewId
let channel = FlutterMethodChannel(name: InAppWebView.METHOD_CHANNEL_NAME_PREFIX + String(describing: viewId),
binaryMessenger: registrar.messenger())
webView!.channelDelegate = WebViewChannelDelegate(webView: webView!, channel: channel)
webView!.frame = myView!.bounds webView!.frame = myView!.bounds
webView!.contextMenu = contextMenu webView!.contextMenu = contextMenu
webView!.channel = channel!
webView!.initialUserScripts = userScripts webView!.initialUserScripts = userScripts
} else { } else {
webView = InAppWebView(frame: myView!.bounds, webView = InAppWebView(id: viewId,
registrar: registrar,
frame: myView!.bounds,
configuration: preWebviewConfiguration, configuration: preWebviewConfiguration,
contextMenu: contextMenu, contextMenu: contextMenu,
channel: channel!,
userScripts: userScripts) userScripts: userScripts)
} }
methodCallDelegate = InAppWebViewMethodHandler(webView: webView!)
channel!.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle)
let pullToRefreshSettings = PullToRefreshSettings() let pullToRefreshSettings = PullToRefreshSettings()
let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings) let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
let pullToRefreshControl = PullToRefreshControl(registrar: registrar, id: viewId, settings: pullToRefreshSettings) let pullToRefreshControl = PullToRefreshControl(registrar: registrar, id: viewId, settings: pullToRefreshSettings)
@ -80,11 +72,26 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
webView!.windowCreated = true webView!.windowCreated = true
} }
public func webView() -> InAppWebView? {
for subview in myView?.subviews ?? []
{
if let item = subview as? InAppWebView
{
return item
}
}
return nil
}
public func view() -> UIView { public func view() -> UIView {
return myView! return myView!
} }
public func makeInitialLoad(params: NSDictionary) { public func makeInitialLoad(params: NSDictionary) {
guard let webView = webView() else {
return
}
let windowId = params["windowId"] as? Int64 let windowId = params["windowId"] as? Int64
let initialUrlRequest = params["initialUrlRequest"] as? [String: Any?] let initialUrlRequest = params["initialUrlRequest"] as? [String: Any?]
let initialFile = params["initialFile"] as? String let initialFile = params["initialFile"] as? String
@ -92,8 +99,8 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
if windowId == nil { if windowId == nil {
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
self.webView!.configuration.userContentController.removeAllContentRuleLists() webView.configuration.userContentController.removeAllContentRuleLists()
if let contentBlockers = webView!.settings?.contentBlockers, contentBlockers.count > 0 { if let contentBlockers = webView.settings?.contentBlockers, contentBlockers.count > 0 {
do { do {
let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: []) let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: [])
let blockRules = String(data: jsonData, encoding: String.Encoding.utf8) let blockRules = String(data: jsonData, encoding: String.Encoding.utf8)
@ -106,7 +113,7 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
return return
} }
let configuration = self.webView!.configuration let configuration = webView.configuration
configuration.userContentController.add(contentRuleList!) configuration.userContentController.add(contentRuleList!)
self.load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData) self.load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData)
@ -120,14 +127,18 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData) load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData)
} }
else if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] { else if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
webView!.load(webViewTransport.request) webView.load(webViewTransport.request)
} }
} }
func load(initialUrlRequest: [String:Any?]?, initialFile: String?, initialData: [String: String]?) { func load(initialUrlRequest: [String:Any?]?, initialFile: String?, initialData: [String: String]?) {
guard let webView = webView() else {
return
}
if let initialFile = initialFile { if let initialFile = initialFile {
do { do {
try webView?.loadFile(assetFilePath: initialFile) try webView.loadFile(assetFilePath: initialFile)
} }
catch let error as NSError { catch let error as NSError {
dump(error) dump(error)
@ -139,34 +150,31 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
let encoding = initialData["encoding"]! let encoding = initialData["encoding"]!
let baseUrl = URL(string: initialData["baseUrl"]!)! let baseUrl = URL(string: initialData["baseUrl"]!)!
var allowingReadAccessToURL: URL? = nil var allowingReadAccessToURL: URL? = nil
if let allowingReadAccessTo = webView?.settings?.allowingReadAccessTo, baseUrl.scheme == "file" { if let allowingReadAccessTo = webView.settings?.allowingReadAccessTo, baseUrl.scheme == "file" {
allowingReadAccessToURL = URL(string: allowingReadAccessTo) allowingReadAccessToURL = URL(string: allowingReadAccessTo)
if allowingReadAccessToURL?.scheme != "file" { if allowingReadAccessToURL?.scheme != "file" {
allowingReadAccessToURL = nil allowingReadAccessToURL = nil
} }
} }
webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL) webView.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL)
} }
else if let initialUrlRequest = initialUrlRequest { else if let initialUrlRequest = initialUrlRequest {
let urlRequest = URLRequest.init(fromPluginMap: initialUrlRequest) let urlRequest = URLRequest.init(fromPluginMap: initialUrlRequest)
var allowingReadAccessToURL: URL? = nil var allowingReadAccessToURL: URL? = nil
if let allowingReadAccessTo = webView?.settings?.allowingReadAccessTo, let url = urlRequest.url, url.scheme == "file" { if let allowingReadAccessTo = webView.settings?.allowingReadAccessTo, let url = urlRequest.url, url.scheme == "file" {
allowingReadAccessToURL = URL(string: allowingReadAccessTo) allowingReadAccessToURL = URL(string: allowingReadAccessTo)
if allowingReadAccessToURL?.scheme != "file" { if allowingReadAccessToURL?.scheme != "file" {
allowingReadAccessToURL = nil allowingReadAccessToURL = nil
} }
} }
webView?.loadUrl(urlRequest: urlRequest, allowingReadAccessTo: allowingReadAccessToURL) webView.loadUrl(urlRequest: urlRequest, allowingReadAccessTo: allowingReadAccessToURL)
} }
} }
func dispose() { public func dispose() {
channel?.setMethodCallHandler(nil) if let webView = webView() {
channel = nil webView.dispose()
methodCallDelegate?.dispose() }
methodCallDelegate = nil
webView?.dispose()
webView = nil
myView = nil myView = nil
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
//
// WebMessageChannel.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 10/03/21.
//
import Foundation
public class WebMessageChannel : FlutterMethodCallDelegate {
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_channel_"
var id: String
var channelDelegate: WebMessageChannelChannelDelegate?
weak var webView: InAppWebView?
var ports: [WebMessagePort] = []
public init(id: String) {
self.id = id
super.init()
let channel = FlutterMethodChannel(name: WebMessageChannel.METHOD_CHANNEL_NAME_PREFIX + id,
binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
self.channelDelegate = WebMessageChannelChannelDelegate(webMessageChannel: self, channel: channel)
self.ports = [
WebMessagePort(name: "port1", webMessageChannel: self),
WebMessagePort(name: "port2", webMessageChannel: self)
]
}
public func initJsInstance(webView: InAppWebView, completionHandler: ((WebMessageChannel) -> Void)? = nil) {
self.webView = webView
if let webView = self.webView {
webView.evaluateJavascript(source: """
(function() {
\(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(id)"] = new MessageChannel();
})();
""") { (_) in
completionHandler?(self)
}
} else {
completionHandler?(self)
}
}
public func toMap() -> [String:Any?] {
return [
"id": id
]
}
public func dispose() {
channelDelegate?.dispose()
channelDelegate = nil
for port in ports {
port.dispose()
}
ports.removeAll()
webView?.evaluateJavascript(source: """
(function() {
var webMessageChannel = \(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(id)"];
if (webMessageChannel != null) {
webMessageChannel.port1.close();
webMessageChannel.port2.close();
delete \(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(id)"];
}
})();
""")
webView = nil
}
deinit {
debugPrint("WebMessageChannel - dealloc")
dispose()
}
}

View File

@ -1,43 +1,18 @@
// //
// WebMessageChannel.swift // WebMessageChannelChannelDelegate.swift
// flutter_inappwebview // flutter_inappwebview
// //
// Created by Lorenzo Pichilli on 10/03/21. // Created by Lorenzo Pichilli on 07/05/22.
// //
import Foundation import Foundation
public class WebMessageChannel : FlutterMethodCallDelegate { public class WebMessageChannelChannelDelegate : ChannelDelegate {
var id: String private weak var webMessageChannel: WebMessageChannel?
var channel: FlutterMethodChannel?
var webView: InAppWebView?
var ports: [WebMessagePort] = []
public init(id: String) { public init(webMessageChannel: WebMessageChannel, channel: FlutterMethodChannel) {
self.id = id super.init(channel: channel)
super.init() self.webMessageChannel = webMessageChannel
self.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_web_message_channel_" + id,
binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
self.channel?.setMethodCallHandler(self.handle)
self.ports = [
WebMessagePort(name: "port1", webMessageChannel: self),
WebMessagePort(name: "port2", webMessageChannel: self)
]
}
public func initJsInstance(webView: InAppWebView, completionHandler: ((WebMessageChannel) -> Void)? = nil) {
self.webView = webView
if let webView = self.webView {
webView.evaluateJavascript(source: """
(function() {
\(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(id)"] = new MessageChannel();
})();
""") { (_) in
completionHandler?(self)
}
} else {
completionHandler?(self)
}
} }
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
@ -45,7 +20,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
switch call.method { switch call.method {
case "setWebMessageCallback": case "setWebMessageCallback":
if let _ = webView, ports.count > 0 { if let _ = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 {
let index = arguments!["index"] as! Int let index = arguments!["index"] as! Int
let port = ports[index] let port = ports[index]
do { do {
@ -57,11 +32,11 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
} }
} else { } else {
result(true) result(true)
} }
break break
case "postMessage": case "postMessage":
if let webView = webView, ports.count > 0 { if let webView = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 {
let index = arguments!["index"] as! Int let index = arguments!["index"] as! Int
let port = ports[index] let port = ports[index]
let message = arguments!["message"] as! [String: Any?] let message = arguments!["message"] as! [String: Any?]
@ -90,7 +65,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
} }
break break
case "close": case "close":
if let _ = webView, ports.count > 0 { if let _ = webMessageChannel?.webView, let ports = webMessageChannel?.ports, ports.count > 0 {
let index = arguments!["index"] as! Int let index = arguments!["index"] as! Int
let port = ports[index] let port = ports[index]
do { do {
@ -118,34 +93,12 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
channel?.invokeMethod("onMessage", arguments: arguments) channel?.invokeMethod("onMessage", arguments: arguments)
} }
public func toMap () -> [String:Any?] { public override func dispose() {
return [ super.dispose()
"id": id webMessageChannel = nil
]
}
public func dispose() {
channel?.setMethodCallHandler(nil)
channel = nil
for port in ports {
port.dispose()
}
ports.removeAll()
webView?.evaluateJavascript(source: """
(function() {
var webMessageChannel = \(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(id)"];
if (webMessageChannel != null) {
webMessageChannel.port1.close();
webMessageChannel.port2.close();
delete \(WEB_MESSAGE_CHANNELS_VARIABLE_NAME)["\(id)"];
}
})();
""")
webView = nil
} }
deinit { deinit {
debugPrint("WebMessageChannel - dealloc")
dispose() dispose()
} }
} }

View File

@ -9,19 +9,19 @@ import Foundation
import WebKit import WebKit
public class WebMessageListener : FlutterMethodCallDelegate { public class WebMessageListener : FlutterMethodCallDelegate {
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_listener_"
var jsObjectName: String var jsObjectName: String
var allowedOriginRules: Set<String> var allowedOriginRules: Set<String>
var channel: FlutterMethodChannel? var channelDelegate: WebMessageListenerChannelDelegate?
var webView: InAppWebView? weak var webView: InAppWebView?
public init(jsObjectName: String, allowedOriginRules: Set<String>) { public init(jsObjectName: String, allowedOriginRules: Set<String>) {
self.jsObjectName = jsObjectName self.jsObjectName = jsObjectName
self.allowedOriginRules = allowedOriginRules self.allowedOriginRules = allowedOriginRules
super.init() super.init()
self.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappwebview_web_message_listener_" + self.jsObjectName, let channel = FlutterMethodChannel(name: WebMessageListener.METHOD_CHANNEL_NAME_PREFIX + self.jsObjectName,
binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger()) binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger())
self.channel?.setMethodCallHandler(self.handle) self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel)
} }
public func assertOriginRulesValid() throws { public func assertOriginRulesValid() throws {
@ -122,41 +122,6 @@ public class WebMessageListener : FlutterMethodCallDelegate {
) )
} }
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "postMessage":
if let webView = webView {
let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'")
let messageEscaped = (arguments!["message"] as! String).replacingOccurrences(of: "\'", with: "\\'")
let source = """
(function() {
var webMessageListener = window['\(jsObjectNameEscaped)'];
if (webMessageListener != null) {
var event = {data: '\(messageEscaped)'};
if (webMessageListener.onmessage != null) {
webMessageListener.onmessage(event);
}
for (var listener of webMessageListener.listeners) {
listener(event);
}
}
})();
"""
webView.evaluateJavascript(source: source) { (_) in
result(true)
}
} else {
result(true)
}
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func isOriginAllowed(scheme: String?, host: String?, port: Int?) -> Bool { public func isOriginAllowed(scheme: String?, host: String?, port: Int?) -> Bool {
for allowedOriginRule in allowedOriginRules { for allowedOriginRule in allowedOriginRules {
if allowedOriginRule == "*" { if allowedOriginRule == "*" {
@ -204,19 +169,10 @@ public class WebMessageListener : FlutterMethodCallDelegate {
} }
return false return false
} }
public func onPostMessage(message: String?, sourceOrigin: URL?, isMainFrame: Bool) {
let arguments: [String:Any?] = [
"message": message,
"sourceOrigin": sourceOrigin?.absoluteString,
"isMainFrame": isMainFrame
]
channel?.invokeMethod("onPostMessage", arguments: arguments)
}
public func dispose() { public func dispose() {
channel?.setMethodCallHandler(nil) channelDelegate?.dispose()
channel = nil channelDelegate = nil
webView = nil webView = nil
} }

View File

@ -0,0 +1,71 @@
//
// WebMessageListenerChannelDelegate.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 07/05/22.
//
import Foundation
public class WebMessageListenerChannelDelegate : ChannelDelegate {
private weak var webMessageListener: WebMessageListener?
public init(webMessageListener: WebMessageListener, channel: FlutterMethodChannel) {
super.init(channel: channel)
self.webMessageListener = webMessageListener
}
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "postMessage":
if let webView = webMessageListener?.webView, let jsObjectName = webMessageListener?.jsObjectName {
let jsObjectNameEscaped = jsObjectName.replacingOccurrences(of: "\'", with: "\\'")
let messageEscaped = (arguments!["message"] as! String).replacingOccurrences(of: "\'", with: "\\'")
let source = """
(function() {
var webMessageListener = window['\(jsObjectNameEscaped)'];
if (webMessageListener != null) {
var event = {data: '\(messageEscaped)'};
if (webMessageListener.onmessage != null) {
webMessageListener.onmessage(event);
}
for (var listener of webMessageListener.listeners) {
listener(event);
}
}
})();
"""
webView.evaluateJavascript(source: source) { (_) in
result(true)
}
} else {
result(true)
}
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func onPostMessage(message: String?, sourceOrigin: URL?, isMainFrame: Bool) {
let arguments: [String:Any?] = [
"message": message,
"sourceOrigin": sourceOrigin?.absoluteString,
"isMainFrame": isMainFrame
]
channel?.invokeMethod("onPostMessage", arguments: arguments)
}
public override func dispose() {
super.dispose()
webMessageListener = nil
}
deinit {
dispose()
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,654 +0,0 @@
//
// WebViewMethodHandler.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 01/02/21.
//
import Foundation
import WebKit
public class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
var webView: InAppWebView?
init(webView: InAppWebView) {
super.init()
self.webView = webView
}
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
let arguments = call.arguments as? NSDictionary
switch call.method {
case "getUrl":
result(webView?.url?.absoluteString)
break
case "getTitle":
result(webView?.title)
break
case "getProgress":
result( (webView != nil) ? Int(webView!.estimatedProgress * 100) : nil )
break
case "loadUrl":
let urlRequest = arguments!["urlRequest"] as! [String:Any?]
let allowingReadAccessTo = arguments!["allowingReadAccessTo"] as? String
var allowingReadAccessToURL: URL? = nil
if let allowingReadAccessTo = allowingReadAccessTo {
allowingReadAccessToURL = URL(string: allowingReadAccessTo)
}
webView?.loadUrl(urlRequest: URLRequest.init(fromPluginMap: urlRequest), allowingReadAccessTo: allowingReadAccessToURL)
result(true)
break
case "postUrl":
if let webView = webView {
let url = arguments!["url"] as! String
let postData = arguments!["postData"] as! FlutterStandardTypedData
webView.postUrl(url: URL(string: url)!, postData: postData.data)
}
result(true)
break
case "loadData":
let data = arguments!["data"] as! String
let mimeType = arguments!["mimeType"] as! String
let encoding = arguments!["encoding"] as! String
let baseUrl = URL(string: arguments!["baseUrl"] as! String)!
let allowingReadAccessTo = arguments!["allowingReadAccessTo"] as? String
var allowingReadAccessToURL: URL? = nil
if let allowingReadAccessTo = allowingReadAccessTo {
allowingReadAccessToURL = URL(string: allowingReadAccessTo)
}
webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl, allowingReadAccessTo: allowingReadAccessToURL)
result(true)
break
case "loadFile":
let assetFilePath = arguments!["assetFilePath"] as! String
do {
try webView?.loadFile(assetFilePath: assetFilePath)
}
catch let error as NSError {
result(FlutterError(code: "InAppWebViewMethodHandler", message: error.domain, details: nil))
return
}
result(true)
break
case "evaluateJavascript":
if let webView = webView {
let source = arguments!["source"] as! String
let contentWorldMap = arguments!["contentWorld"] as? [String:Any?]
if #available(iOS 14.0, *), let contentWorldMap = contentWorldMap {
let contentWorld = WKContentWorld.fromMap(map: contentWorldMap, windowId: webView.windowId)!
webView.evaluateJavascript(source: source, contentWorld: contentWorld) { (value) in
result(value)
}
} else {
webView.evaluateJavascript(source: source) { (value) in
result(value)
}
}
}
else {
result(nil)
}
break
case "injectJavascriptFileFromUrl":
let urlFile = arguments!["urlFile"] as! String
let scriptHtmlTagAttributes = arguments!["scriptHtmlTagAttributes"] as? [String:Any?]
webView?.injectJavascriptFileFromUrl(urlFile: urlFile, scriptHtmlTagAttributes: scriptHtmlTagAttributes)
result(true)
break
case "injectCSSCode":
let source = arguments!["source"] as! String
webView?.injectCSSCode(source: source)
result(true)
break
case "injectCSSFileFromUrl":
let urlFile = arguments!["urlFile"] as! String
let cssLinkHtmlTagAttributes = arguments!["cssLinkHtmlTagAttributes"] as? [String:Any?]
webView?.injectCSSFileFromUrl(urlFile: urlFile, cssLinkHtmlTagAttributes: cssLinkHtmlTagAttributes)
result(true)
break
case "reload":
webView?.reload()
result(true)
break
case "goBack":
webView?.goBack()
result(true)
break
case "canGoBack":
result(webView?.canGoBack ?? false)
break
case "goForward":
webView?.goForward()
result(true)
break
case "canGoForward":
result(webView?.canGoForward ?? false)
break
case "goBackOrForward":
let steps = arguments!["steps"] as! Int
webView?.goBackOrForward(steps: steps)
result(true)
break
case "canGoBackOrForward":
let steps = arguments!["steps"] as! Int
result(webView?.canGoBackOrForward(steps: steps) ?? false)
break
case "stopLoading":
webView?.stopLoading()
result(true)
break
case "isLoading":
result(webView?.isLoading ?? false)
break
case "takeScreenshot":
if let webView = webView, #available(iOS 11.0, *) {
let screenshotConfiguration = arguments!["screenshotConfiguration"] as? [String: Any?]
webView.takeScreenshot(with: screenshotConfiguration, completionHandler: { (screenshot) -> Void in
result(screenshot)
})
}
else {
result(nil)
}
break
case "setSettings":
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
let inAppBrowserSettings = InAppBrowserSettings()
let inAppBrowserSettingsMap = arguments!["settings"] as! [String: Any]
let _ = inAppBrowserSettings.parse(settings: inAppBrowserSettingsMap)
iabController.setSettings(newSettings: inAppBrowserSettings, newSettingsMap: inAppBrowserSettingsMap)
} else {
let inAppWebViewSettings = InAppWebViewSettings()
let inAppWebViewSettingsMap = arguments!["settings"] as! [String: Any]
let _ = inAppWebViewSettings.parse(settings: inAppWebViewSettingsMap)
webView?.setSettings(newSettings: inAppWebViewSettings, newSettingsMap: inAppWebViewSettingsMap)
}
result(true)
break
case "getSettings":
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
result(iabController.getSettings())
} else {
result(webView?.getSettings())
}
break
case "close":
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
iabController.close {
result(true)
}
} else {
result(FlutterMethodNotImplemented)
}
break
case "show":
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
iabController.show {
result(true)
}
} else {
result(FlutterMethodNotImplemented)
}
break
case "hide":
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
iabController.hide {
result(true)
}
} else {
result(FlutterMethodNotImplemented)
}
break
case "getCopyBackForwardList":
result(webView?.getCopyBackForwardList())
break
case "findAllAsync":
if let webView = webView {
let find = arguments!["find"] as! String
webView.findAllAsync(find: find, completionHandler: {(value, error) in
if error != nil {
result(FlutterError(code: "InAppWebViewMethodHandler", message: error?.localizedDescription, details: nil))
return
}
result(true)
})
} else {
result(false)
}
break
case "findNext":
if let webView = webView {
let forward = arguments!["forward"] as! Bool
webView.findNext(forward: forward, completionHandler: {(value, error) in
if error != nil {
result(FlutterError(code: "InAppWebViewMethodHandler", message: error?.localizedDescription, details: nil))
return
}
result(true)
})
} else {
result(false)
}
break
case "clearMatches":
if let webView = webView {
webView.clearMatches(completionHandler: {(value, error) in
if error != nil {
result(FlutterError(code: "InAppWebViewMethodHandler", message: error?.localizedDescription, details: nil))
return
}
result(true)
})
} else {
result(false)
}
break
case "clearCache":
webView?.clearCache()
result(true)
break
case "scrollTo":
let x = arguments!["x"] as! Int
let y = arguments!["y"] as! Int
let animated = arguments!["animated"] as! Bool
webView?.scrollTo(x: x, y: y, animated: animated)
result(true)
break
case "scrollBy":
let x = arguments!["x"] as! Int
let y = arguments!["y"] as! Int
let animated = arguments!["animated"] as! Bool
webView?.scrollBy(x: x, y: y, animated: animated)
result(true)
break
case "pauseTimers":
webView?.pauseTimers()
result(true)
break
case "resumeTimers":
webView?.resumeTimers()
result(true)
break
case "printCurrentPage":
if let webView = webView {
webView.printCurrentPage(printCompletionHandler: {(completed, error) in
if !completed, let err = error {
print(err.localizedDescription)
result(false)
return
}
result(true)
})
} else {
result(false)
}
break
case "getContentHeight":
result(webView?.getContentHeight())
break
case "zoomBy":
let zoomFactor = (arguments!["zoomFactor"] as! NSNumber).floatValue
let animated = arguments!["animated"] as! Bool
webView?.zoomBy(zoomFactor: zoomFactor, animated: animated)
result(true)
break
case "reloadFromOrigin":
webView?.reloadFromOrigin()
result(true)
break
case "getOriginalUrl":
result(webView?.getOriginalUrl()?.absoluteString)
break
case "getZoomScale":
result(webView?.getZoomScale())
break
case "hasOnlySecureContent":
result(webView?.hasOnlySecureContent ?? false)
break
case "getSelectedText":
if let webView = webView {
webView.getSelectedText { (value, error) in
if let err = error {
print(err.localizedDescription)
result("")
return
}
result(value)
}
}
else {
result(nil)
}
break
case "getHitTestResult":
if let webView = webView {
webView.getHitTestResult { (hitTestResult) in
result(hitTestResult.toMap())
}
}
else {
result(nil)
}
break
case "clearFocus":
webView?.clearFocus()
result(true)
break
case "setContextMenu":
if let webView = webView {
let contextMenu = arguments!["contextMenu"] as? [String: Any]
webView.contextMenu = contextMenu
result(true)
} else {
result(false)
}
break
case "requestFocusNodeHref":
if let webView = webView {
webView.requestFocusNodeHref { (value, error) in
if let err = error {
print(err.localizedDescription)
result(nil)
return
}
result(value)
}
} else {
result(nil)
}
break
case "requestImageRef":
if let webView = webView {
webView.requestImageRef { (value, error) in
if let err = error {
print(err.localizedDescription)
result(nil)
return
}
result(value)
}
} else {
result(nil)
}
break
case "getScrollX":
if let webView = webView {
result(Int(webView.scrollView.contentOffset.x))
} else {
result(nil)
}
break
case "getScrollY":
if let webView = webView {
result(Int(webView.scrollView.contentOffset.y))
} else {
result(nil)
}
break
case "getCertificate":
result(webView?.getCertificate()?.toMap())
break
case "addUserScript":
if let webView = webView {
let userScriptMap = arguments!["userScript"] as! [String: Any?]
let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView.windowId)!
webView.configuration.userContentController.addUserOnlyScript(userScript)
webView.configuration.userContentController.sync(scriptMessageHandler: webView)
}
result(true)
break
case "removeUserScript":
let index = arguments!["index"] as! Int
let userScriptMap = arguments!["userScript"] as! [String: Any?]
let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView?.windowId)!
webView?.configuration.userContentController.removeUserOnlyScript(at: index, injectionTime: userScript.injectionTime)
result(true)
break
case "removeUserScriptsByGroupName":
let groupName = arguments!["groupName"] as! String
webView?.configuration.userContentController.removeUserOnlyScripts(with: groupName)
result(true)
break
case "removeAllUserScripts":
webView?.configuration.userContentController.removeAllUserOnlyScripts()
result(true)
break
case "callAsyncJavaScript":
if let webView = webView, #available(iOS 10.3, *) {
if #available(iOS 14.0, *) {
let functionBody = arguments!["functionBody"] as! String
let functionArguments = arguments!["arguments"] as! [String:Any]
var contentWorld = WKContentWorld.page
if let contentWorldMap = arguments!["contentWorld"] as? [String:Any?] {
contentWorld = WKContentWorld.fromMap(map: contentWorldMap, windowId: webView.windowId)!
}
webView.callAsyncJavaScript(functionBody: functionBody, arguments: functionArguments, contentWorld: contentWorld) { (value) in
result(value)
}
} else {
let functionBody = arguments!["functionBody"] as! String
let functionArguments = arguments!["arguments"] as! [String:Any]
webView.callAsyncJavaScript(functionBody: functionBody, arguments: functionArguments) { (value) in
result(value)
}
}
}
else {
result(nil)
}
break
case "createPdf":
if let webView = webView, #available(iOS 14.0, *) {
let configuration = arguments!["pdfConfiguration"] as? [String: Any?]
webView.createPdf(configuration: configuration, completionHandler: { (pdf) -> Void in
result(pdf)
})
}
else {
result(nil)
}
break
case "createWebArchiveData":
if let webView = webView, #available(iOS 14.0, *) {
webView.createWebArchiveData(dataCompletionHandler: { (webArchiveData) -> Void in
result(webArchiveData)
})
}
else {
result(nil)
}
break
case "saveWebArchive":
if let webView = webView, #available(iOS 14.0, *) {
let filePath = arguments!["filePath"] as! String
let autoname = arguments!["autoname"] as! Bool
webView.saveWebArchive(filePath: filePath, autoname: autoname, completionHandler: { (path) -> Void in
result(path)
})
}
else {
result(nil)
}
break
case "isSecureContext":
if let webView = webView {
webView.isSecureContext(completionHandler: { (isSecureContext) in
result(isSecureContext)
})
}
else {
result(false)
}
break
case "createWebMessageChannel":
if let webView = webView {
let _ = webView.createWebMessageChannel { (webMessageChannel) in
result(webMessageChannel.toMap())
}
} else {
result(nil)
}
break
case "postWebMessage":
if let webView = webView {
let message = arguments!["message"] as! [String: Any?]
let targetOrigin = arguments!["targetOrigin"] as! String
var ports: [WebMessagePort] = []
let portsMap = message["ports"] as? [[String: Any?]]
if let portsMap = portsMap {
for portMap in portsMap {
let webMessageChannelId = portMap["webMessageChannelId"] as! String
let index = portMap["index"] as! Int
if let webMessageChannel = webView.webMessageChannels[webMessageChannelId] {
ports.append(webMessageChannel.ports[index])
}
}
}
let webMessage = WebMessage(data: message["data"] as? String, ports: ports)
do {
try webView.postWebMessage(message: webMessage, targetOrigin: targetOrigin) { (_) in
result(true)
}
} catch let error as NSError {
result(FlutterError(code: "InAppWebViewMethodHandler", message: error.domain, details: nil))
}
} else {
result(false)
}
break
case "addWebMessageListener":
if let webView = webView {
let webMessageListenerMap = arguments!["webMessageListener"] as! [String: Any?]
let webMessageListener = WebMessageListener.fromMap(map: webMessageListenerMap)!
do {
try webView.addWebMessageListener(webMessageListener: webMessageListener)
result(false)
} catch let error as NSError {
result(FlutterError(code: "InAppWebViewMethodHandler", message: error.domain, details: nil))
}
} else {
result(false)
}
break
case "canScrollVertically":
if let webView = webView {
result(webView.canScrollVertically())
} else {
result(false)
}
break
case "canScrollHorizontally":
if let webView = webView {
result(webView.canScrollHorizontally())
} else {
result(false)
}
break
case "pauseAllMediaPlayback":
if let webView = webView, #available(iOS 15.0, *) {
webView.pauseAllMediaPlayback(completionHandler: { () -> Void in
result(true)
})
} else {
result(false)
}
break
case "setAllMediaPlaybackSuspended":
if let webView = webView, #available(iOS 15.0, *) {
let suspended = arguments!["suspended"] as! Bool
webView.setAllMediaPlaybackSuspended(suspended, completionHandler: { () -> Void in
result(true)
})
} else {
result(false)
}
break
case "closeAllMediaPresentations":
if let webView = self.webView, #available(iOS 14.5, *) {
// closeAllMediaPresentations with completionHandler v15.0 makes the app crash
// with error EXC_BAD_ACCESS, so use closeAllMediaPresentations v14.5
webView.closeAllMediaPresentations()
result(true)
} else {
result(false)
}
break
case "requestMediaPlaybackState":
if let webView = webView, #available(iOS 15.0, *) {
webView.requestMediaPlaybackState(completionHandler: { (state) -> Void in
result(state.rawValue)
})
} else {
result(nil)
}
break
case "getMetaThemeColor":
if let webView = webView, #available(iOS 15.0, *) {
result(webView.themeColor?.hexString)
} else {
result(nil)
}
break
case "isInFullscreen":
// if let webView = webView, #available(iOS 15.0, *) {
// result(webView.fullscreenState == .inFullscreen)
// }
if let webView = webView {
result(webView.inFullscreen)
}
else {
result(false)
}
break
case "getCameraCaptureState":
if let webView = webView, #available(iOS 15.0, *) {
result(webView.cameraCaptureState.rawValue)
} else {
result(nil)
}
break
case "setCameraCaptureState":
if let webView = webView, #available(iOS 15.0, *) {
let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none
webView.setCameraCaptureState(state) {
result(true)
}
} else {
result(false)
}
break
case "getMicrophoneCaptureState":
if let webView = webView, #available(iOS 15.0, *) {
result(webView.microphoneCaptureState.rawValue)
} else {
result(nil)
}
break
case "setMicrophoneCaptureState":
if let webView = webView, #available(iOS 15.0, *) {
let state = WKMediaCaptureState.init(rawValue: arguments!["state"] as! Int) ?? WKMediaCaptureState.none
webView.setMicrophoneCaptureState(state) {
result(true)
}
} else {
result(false)
}
break
default:
result(FlutterMethodNotImplemented)
break
}
}
public func dispose() {
webView = nil
}
deinit {
debugPrint("InAppWebViewMethodHandler - dealloc")
dispose()
}
}

View File

@ -8,7 +8,7 @@
import Foundation import Foundation
import WebKit import WebKit
class InAppWebViewStatic: ChannelDelegate { public class InAppWebViewStatic: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static" static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var webViewForUserAgent: WKWebView? static var webViewForUserAgent: WKWebView?
@ -73,4 +73,8 @@ class InAppWebViewStatic: ChannelDelegate {
InAppWebViewStatic.webViewForUserAgent = nil InAppWebViewStatic.webViewForUserAgent = nil
InAppWebViewStatic.defaultUserAgent = nil InAppWebViewStatic.defaultUserAgent = nil
} }
deinit {
dispose()
}
} }

View File

@ -9,7 +9,7 @@ import Foundation
import WebKit import WebKit
@available(iOS 11.0, *) @available(iOS 11.0, *)
class MyCookieManager: ChannelDelegate { public class MyCookieManager: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager" static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var httpCookieStore: WKHTTPCookieStore? static var httpCookieStore: WKHTTPCookieStore?
@ -295,4 +295,8 @@ class MyCookieManager: ChannelDelegate {
MyCookieManager.registrar = nil MyCookieManager.registrar = nil
MyCookieManager.httpCookieStore = nil MyCookieManager.httpCookieStore = nil
} }
deinit {
dispose()
}
} }

View File

@ -9,7 +9,7 @@ import Foundation
import WebKit import WebKit
@available(iOS 9.0, *) @available(iOS 9.0, *)
class MyWebStorageManager: ChannelDelegate { public class MyWebStorageManager: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager" static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
static var websiteDataStore: WKWebsiteDataStore? static var websiteDataStore: WKWebsiteDataStore?
@ -105,4 +105,8 @@ class MyWebStorageManager: ChannelDelegate {
MyWebStorageManager.registrar = nil MyWebStorageManager.registrar = nil
MyWebStorageManager.websiteDataStore = nil MyWebStorageManager.websiteDataStore = nil
} }
deinit {
dispose()
}
} }

View File

@ -7,7 +7,7 @@
import Foundation import Foundation
class PlatformUtil: ChannelDelegate { public class PlatformUtil: ChannelDelegate {
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil" static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil"
static var registrar: FlutterPluginRegistrar? static var registrar: FlutterPluginRegistrar?
@ -59,4 +59,8 @@ class PlatformUtil: ChannelDelegate {
super.dispose() super.dispose()
PlatformUtil.registrar = nil PlatformUtil.registrar = nil
} }
deinit {
dispose()
}
} }

View File

@ -8,9 +8,9 @@
import Foundation import Foundation
public class PullToRefreshChannelDelegate : ChannelDelegate { public class PullToRefreshChannelDelegate : ChannelDelegate {
private var pullToRefreshControl: PullToRefreshControl? private weak var pullToRefreshControl: PullToRefreshControl?
public init(pullToRefreshControl: PullToRefreshControl , channel: FlutterMethodChannel) { public init(pullToRefreshControl: PullToRefreshControl, channel: FlutterMethodChannel) {
super.init(channel: channel) super.init(channel: channel)
self.pullToRefreshControl = pullToRefreshControl self.pullToRefreshControl = pullToRefreshControl
} }
@ -87,4 +87,8 @@ public class PullToRefreshChannelDelegate : ChannelDelegate {
super.dispose() super.dispose()
pullToRefreshControl = nil pullToRefreshControl = nil
} }
deinit {
dispose()
}
} }

View File

@ -94,4 +94,8 @@ public class ChromeSafariBrowserManager: ChannelDelegate {
} }
ChromeSafariBrowserManager.browsers.removeAll() ChromeSafariBrowserManager.browsers.removeAll()
} }
deinit {
dispose()
}
} }

View File

@ -8,8 +8,7 @@
import Foundation import Foundation
public class SafariViewControllerChannelDelegate : ChannelDelegate { public class SafariViewControllerChannelDelegate : ChannelDelegate {
private weak var safariViewController: SafariViewController?
private var safariViewController: SafariViewController?
public init(safariViewController: SafariViewController, channel: FlutterMethodChannel) { public init(safariViewController: SafariViewController, channel: FlutterMethodChannel) {
super.init(channel: channel) super.init(channel: channel)
@ -60,4 +59,8 @@ public class SafariViewControllerChannelDelegate : ChannelDelegate {
super.dispose() super.dispose()
safariViewController = nil safariViewController = nil
} }
deinit {
dispose()
}
} }

View File

@ -0,0 +1,32 @@
//
// BaseCallbackResult.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 06/05/22.
//
import Foundation
public class BaseCallbackResult<T> : CallbackResult<T> {
override init() {
super.init()
self.success = { [weak self] (obj: Any?) in
let result: T? = self?.decodeResult(obj)
var shouldRunDefaultBehaviour = false
if let result = result {
shouldRunDefaultBehaviour = self?.nonNullSuccess(result) ?? shouldRunDefaultBehaviour
} else {
shouldRunDefaultBehaviour = self?.nullSuccess() ?? shouldRunDefaultBehaviour
}
if shouldRunDefaultBehaviour {
self?.defaultBehaviour(result)
}
}
self.notImplemented = { [weak self] in
self?.defaultBehaviour(nil)
}
}
}

View File

@ -0,0 +1,18 @@
//
// CallbackResult.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 06/05/22.
//
import Foundation
public class CallbackResult<T> : MethodChannelResult {
public var notImplemented: () -> Void = {}
public var success: (Any?) -> Void = {_ in }
public var error: (String, String?, Any?) -> Void = {_,_,_ in }
public var nonNullSuccess: (T) -> Bool = {_ in true}
public var nullSuccess: () -> Bool = {true}
public var defaultBehaviour: (T?) -> Void = {_ in }
public var decodeResult: (Any?) -> T? = {_ in nil}
}

View File

@ -7,7 +7,7 @@
import Foundation import Foundation
class ClientCertChallenge: NSObject { public class ClientCertChallenge: NSObject {
var protectionSpace: URLProtectionSpace! var protectionSpace: URLProtectionSpace!
public init(fromChallenge: URLAuthenticationChallenge) { public init(fromChallenge: URLAuthenticationChallenge) {

View File

@ -0,0 +1,33 @@
//
// ClientCertResponse.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 07/05/22.
//
import Foundation
public class ClientCertResponse : NSObject {
var certificatePath: String
var certificatePassword: String?
var keyStoreType: String?
var action: Int?
public init(certificatePath: String, certificatePassword: String? = nil, keyStoreType: String? = nil, action: Int? = nil) {
self.certificatePath = certificatePath
self.certificatePassword = certificatePassword
self.keyStoreType = keyStoreType
self.action = action
}
public static func fromMap(map: [String:Any?]?) -> ClientCertResponse? {
guard let map = map else {
return nil
}
let certificatePath = map["certificatePath"] as! String
let certificatePassword = map["certificatePassword"] as? String
let keyStoreType = map["keyStoreType"] as? String
let action = map["action"] as? Int
return ClientCertResponse(certificatePath: certificatePath, certificatePassword: certificatePassword, keyStoreType: keyStoreType, action: action)
}
}

View File

@ -0,0 +1,31 @@
//
// CreateWindowAction.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 07/05/22.
//
import Foundation
import WebKit
public class CreateWindowAction : NSObject {
var navigationAction: WKNavigationAction
var windowId: Int64
var windowFeatures: WKWindowFeatures
var isDialog: Bool?
public init(navigationAction: WKNavigationAction, windowId: Int64, windowFeatures: WKWindowFeatures, isDialog: Bool? = nil) {
self.navigationAction = navigationAction
self.windowId = windowId
self.windowFeatures = windowFeatures
self.isDialog = isDialog
}
public func toMap () -> [String:Any?] {
var map = navigationAction.toMap()
map["windowId"] = windowId
map["windowFeatures"] = windowFeatures.toMap()
map["isDialog"] = isDialog
return map
}
}

View File

@ -0,0 +1,30 @@
//
// CustomSchemeResponse.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 07/05/22.
//
import Foundation
public class CustomSchemeResponse : NSObject {
var data: Data
var contentType: String
var contentEncoding: String
public init(data: Data, contentType: String, contentEncoding: String) {
self.data = data
self.contentType = contentType
self.contentEncoding = contentEncoding
}
public static func fromMap(map: [String:Any?]?) -> CustomSchemeResponse? {
guard let map = map else {
return nil
}
let data = map["data"] as! FlutterStandardTypedData
let contentType = map["contentType"] as! String
let contentEncoding = map["contentEncoding"] as! String
return CustomSchemeResponse(data: data.data, contentType: contentType, contentEncoding: contentEncoding)
}
}

View File

@ -0,0 +1,26 @@
//
// FlutterMethodChannel.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 06/05/22.
//
import Foundation
import Flutter
extension FlutterMethodChannel {
public func invokeMethod(_ method: String, arguments: Any, callback: MethodChannelResult) {
invokeMethod(method, arguments: arguments) {(result) -> Void in
if result is FlutterError {
let error = result as! FlutterError
callback.error(error.code, error.message, error.details)
}
else if (result as? NSObject) == FlutterMethodNotImplemented {
callback.notImplemented()
}
else {
callback.success(result)
}
}
}
}

View File

@ -0,0 +1,33 @@
//
// HttpAuthResponse.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 07/05/22.
//
import Foundation
public class HttpAuthResponse : NSObject {
var username: String
var password: String
var permanentPersistence: Bool
var action: Int?
public init(username: String, password: String, permanentPersistence: Bool, action: Int? = nil) {
self.username = username
self.password = password
self.permanentPersistence = permanentPersistence
self.action = action
}
public static func fromMap(map: [String:Any?]?) -> HttpAuthResponse? {
guard let map = map else {
return nil
}
let username = map["username"] as! String
let password = map["password"] as! String
let permanentPersistence = map["permanentPersistence"] as! Bool
let action = map["action"] as? Int
return HttpAuthResponse(username: username, password: password, permanentPersistence: permanentPersistence, action: action)
}
}

View File

@ -7,7 +7,7 @@
import Foundation import Foundation
class HttpAuthenticationChallenge: NSObject { public class HttpAuthenticationChallenge: NSObject {
var protectionSpace: URLProtectionSpace! var protectionSpace: URLProtectionSpace!
var previousFailureCount: Int = 0 var previousFailureCount: Int = 0
var failureResponse: URLResponse? var failureResponse: URLResponse?

View File

@ -0,0 +1,33 @@
//
// JsAlertResponse.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 06/05/22.
//
import Foundation
public class JsAlertResponse: NSObject {
var message: String
var confirmButtonTitle: String
var handledByClient: Bool
var action: Int?
public init(message: String, confirmButtonTitle: String, handledByClient: Bool, action: Int? = nil) {
self.message = message
self.confirmButtonTitle = confirmButtonTitle
self.handledByClient = handledByClient
self.action = action
}
public static func fromMap(map: [String:Any?]?) -> JsAlertResponse? {
guard let map = map else {
return nil
}
let message = map["message"] as! String
let confirmButtonTitle = map["confirmButtonTitle"] as! String
let handledByClient = map["handledByClient"] as! Bool
let action = map["action"] as? Int
return JsAlertResponse(message: message, confirmButtonTitle: confirmButtonTitle, handledByClient: handledByClient, action: action)
}
}

View File

@ -0,0 +1,36 @@
//
// JsConfirmResponse.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 07/05/22.
//
import Foundation
public class JsConfirmResponse: NSObject {
var message: String
var confirmButtonTitle: String
var cancelButtonTitle: String
var handledByClient: Bool
var action: Int?
public init(message: String, confirmButtonTitle: String, cancelButtonTitle: String, handledByClient: Bool, action: Int? = nil) {
self.message = message
self.confirmButtonTitle = confirmButtonTitle
self.cancelButtonTitle = cancelButtonTitle
self.handledByClient = handledByClient
self.action = action
}
public static func fromMap(map: [String:Any?]?) -> JsConfirmResponse? {
guard let map = map else {
return nil
}
let message = map["message"] as! String
let confirmButtonTitle = map["confirmButtonTitle"] as! String
let cancelButtonTitle = map["cancelButtonTitle"] as! String
let handledByClient = map["handledByClient"] as! Bool
let action = map["action"] as? Int
return JsConfirmResponse(message: message, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle, handledByClient: handledByClient, action: action)
}
}

View File

@ -0,0 +1,43 @@
//
// JsPromptResponse.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 07/05/22.
//
import Foundation
public class JsPromptResponse: NSObject {
var message: String
var defaultValue: String
var confirmButtonTitle: String
var cancelButtonTitle: String
var handledByClient: Bool
var value: String?
var action: Int?
public init(message: String, defaultValue: String, confirmButtonTitle: String, cancelButtonTitle: String, handledByClient: Bool, value: String? = nil, action: Int? = nil) {
self.message = message
self.defaultValue = defaultValue
self.confirmButtonTitle = confirmButtonTitle
self.cancelButtonTitle = cancelButtonTitle
self.handledByClient = handledByClient
self.value = value
self.action = action
}
public static func fromMap(map: [String:Any?]?) -> JsPromptResponse? {
guard let map = map else {
return nil
}
let message = map["message"] as! String
let defaultValue = map["defaultValue"] as! String
let confirmButtonTitle = map["confirmButtonTitle"] as! String
let cancelButtonTitle = map["cancelButtonTitle"] as! String
let handledByClient = map["handledByClient"] as! Bool
let value = map["value"] as? String
let action = map["action"] as? Int
return JsPromptResponse(message: message, defaultValue: defaultValue, confirmButtonTitle: confirmButtonTitle, cancelButtonTitle: cancelButtonTitle,
handledByClient: handledByClient, value: value, action: action)
}
}

View File

@ -0,0 +1,14 @@
//
// MethodChannelResult.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 06/05/22.
//
import Foundation
public protocol MethodChannelResult {
var success: (_ obj: Any?) -> Void { get set }
var error: (_ code: String, _ message: String?, _ details: Any?) -> Void { get set }
var notImplemented: () -> Void { get set }
}

View File

@ -0,0 +1,27 @@
//
// PermissionResponse.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 07/05/22.
//
import Foundation
public class PermissionResponse : NSObject {
var resources: [String]
var action: Int?
public init(resources: [String], action: Int? = nil) {
self.resources = resources
self.action = action
}
public static func fromMap(map: [String:Any?]?) -> PermissionResponse? {
guard let map = map else {
return nil
}
let resources = map["resources"] as! [String]
let action = map["action"] as? Int
return PermissionResponse(resources: resources, action: action)
}
}

View File

@ -0,0 +1,24 @@
//
// ServerTrustAuthResponse.swift
// flutter_inappwebview
//
// Created by Lorenzo Pichilli on 07/05/22.
//
import Foundation
public class ServerTrustAuthResponse : NSObject {
var action: Int?
public init(action: Int? = nil) {
self.action = action
}
public static func fromMap(map: [String:Any?]?) -> ServerTrustAuthResponse? {
guard let map = map else {
return nil
}
let action = map["action"] as? Int
return ServerTrustAuthResponse(action: action)
}
}

View File

@ -7,7 +7,7 @@
import Foundation import Foundation
class ServerTrustChallenge: NSObject { public class ServerTrustChallenge: NSObject {
var protectionSpace: URLProtectionSpace! var protectionSpace: URLProtectionSpace!
public init(fromChallenge: URLAuthenticationChallenge) { public init(fromChallenge: URLAuthenticationChallenge) {

View File

@ -213,7 +213,7 @@ public class Util {
} else { } else {
// normalize grouped zeros :: // normalize grouped zeros ::
var zeros: [String] = [] var zeros: [String] = []
for j in ipv6.count...8 { for _ in ipv6.count...8 {
zeros.append("0000") zeros.append("0000")
} }
fullIPv6[i] = zeros.joined(separator: ":") fullIPv6[i] = zeros.joined(separator: ":")

View File

@ -8,6 +8,6 @@
import Foundation import Foundation
import WebKit import WebKit
class WKProcessPoolManager { public class WKProcessPoolManager {
static let sharedProcessPool = WKProcessPool() static let sharedProcessPool = WKProcessPool()
} }