completed ChannelDelegate iOS implementation
This commit is contained in:
parent
66add9f8ac
commit
373e970e80
|
@ -104,6 +104,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
|
|||
pullToRefreshLayout.prepare();
|
||||
|
||||
webView = findViewById(R.id.webView);
|
||||
webView.id = id;
|
||||
webView.windowId = windowId;
|
||||
webView.inAppBrowserDelegate = this;
|
||||
webView.plugin = manager.plugin;
|
||||
|
|
|
@ -1112,7 +1112,10 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
|||
|
||||
public void onLoadResourceCustomScheme(String url, @NonNull LoadResourceCustomSchemeCallback callback) {
|
||||
MethodChannel channel = getChannel();
|
||||
if (channel == null) return;
|
||||
if (channel == null) {
|
||||
callback.defaultBehaviour(null);
|
||||
return;
|
||||
}
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("url", url);
|
||||
channel.invokeMethod("onLoadResourceCustomScheme", obj, callback);
|
||||
|
@ -1146,7 +1149,10 @@ public class WebViewChannelDelegate extends ChannelDelegateImpl {
|
|||
|
||||
public void shouldInterceptRequest(WebResourceRequestExt request, @NonNull ShouldInterceptRequestCallback callback) {
|
||||
MethodChannel channel = getChannel();
|
||||
if (channel == null) return;
|
||||
if (channel == null) {
|
||||
callback.defaultBehaviour(null);
|
||||
return;
|
||||
}
|
||||
channel.invokeMethod("shouldInterceptRequest", request.toMap(), callback);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class CredentialDatabase: ChannelDelegate {
|
||||
public class CredentialDatabase: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_credential_database"
|
||||
static var registrar: FlutterPluginRegistrar?
|
||||
static var credentialStore: URLCredentialStorage?
|
||||
|
@ -193,4 +193,8 @@ class CredentialDatabase: ChannelDelegate {
|
|||
CredentialDatabase.registrar = nil
|
||||
CredentialDatabase.credentialStore = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,4 +61,8 @@ public class HeadlessInAppWebViewManager: ChannelDelegate {
|
|||
}
|
||||
HeadlessInAppWebViewManager.webViews.removeAll()
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
public class HeadlessWebViewChannelDelegate : ChannelDelegate {
|
||||
private var headlessWebView: HeadlessInAppWebView?
|
||||
private weak var headlessWebView: HeadlessInAppWebView?
|
||||
|
||||
public init(headlessWebView: HeadlessInAppWebView, channel: FlutterMethodChannel) {
|
||||
super.init(channel: channel)
|
||||
|
@ -56,4 +56,8 @@ public class HeadlessWebViewChannelDelegate : ChannelDelegate {
|
|||
super.dispose()
|
||||
headlessWebView = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,4 +21,8 @@ public class InAppBrowserChannelDelegate : ChannelDelegate {
|
|||
let arguments: [String: Any?] = [:]
|
||||
channel?.invokeMethod("onExit", arguments: arguments)
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,4 +138,8 @@ public class InAppBrowserManager: ChannelDelegate {
|
|||
super.dispose()
|
||||
InAppBrowserManager.registrar = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
var tmpWindow: UIWindow?
|
||||
var id: String = ""
|
||||
var windowId: Int64?
|
||||
var webView: InAppWebView!
|
||||
var webView: InAppWebView?
|
||||
var channelDelegate: InAppBrowserChannelDelegate?
|
||||
var initialUrlRequest: URLRequest?
|
||||
var initialFile: String?
|
||||
|
@ -38,7 +38,6 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
var previousStatusBarStyle = -1
|
||||
var initialUserScripts: [[String: Any]] = []
|
||||
var pullToRefreshInitialSettings: [String: Any?] = [:]
|
||||
var methodCallDelegate: InAppWebViewMethodHandler?
|
||||
|
||||
public override func loadView() {
|
||||
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)
|
||||
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
webView = webViewTransport.webView
|
||||
webView.contextMenu = contextMenu
|
||||
webView.channel = channel
|
||||
webView.initialUserScripts = userScripts
|
||||
webView!.contextMenu = contextMenu
|
||||
webView!.initialUserScripts = userScripts
|
||||
} else {
|
||||
webView = InAppWebView(frame: .zero,
|
||||
configuration: preWebviewConfiguration,
|
||||
contextMenu: contextMenu,
|
||||
channel: channel,
|
||||
userScripts: userScripts)
|
||||
webView = InAppWebView(id: nil,
|
||||
registrar: nil,
|
||||
frame: .zero,
|
||||
configuration: preWebviewConfiguration,
|
||||
contextMenu: contextMenu,
|
||||
userScripts: userScripts)
|
||||
}
|
||||
webView.inAppBrowserDelegate = self
|
||||
|
||||
methodCallDelegate = InAppWebViewMethodHandler(webView: webView!)
|
||||
channel.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle)
|
||||
guard let webView = webView else {
|
||||
return
|
||||
}
|
||||
|
||||
webView.inAppBrowserDelegate = self
|
||||
webView.id = id
|
||||
webView.channelDelegate = WebViewChannelDelegate(webView: webView, channel: channel)
|
||||
|
||||
let pullToRefreshSettings = PullToRefreshSettings()
|
||||
let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
|
||||
|
@ -87,38 +90,41 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
public override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
webView.translatesAutoresizingMaskIntoConstraints = false
|
||||
webView?.translatesAutoresizingMaskIntoConstraints = false
|
||||
progressBar.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
if #available(iOS 9.0, *) {
|
||||
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.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true
|
||||
webView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, 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?.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, 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.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0.0).isActive = true
|
||||
progressBar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0.0).isActive = true
|
||||
} else {
|
||||
view.addConstraints([
|
||||
NSLayoutConstraint(item: webView!, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
|
||||
NSLayoutConstraint(item: webView!, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, 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),
|
||||
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 webView = webView {
|
||||
view.addConstraints([
|
||||
NSLayoutConstraint(item: webView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
|
||||
NSLayoutConstraint(item: webView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, 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)
|
||||
])
|
||||
}
|
||||
if let progressBar = progressBar {
|
||||
view.addConstraints([
|
||||
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] {
|
||||
webView.load(webViewTransport.request)
|
||||
webView?.load(webViewTransport.request)
|
||||
} else {
|
||||
if #available(iOS 11.0, *) {
|
||||
if let contentBlockers = webView.settings?.contentBlockers, contentBlockers.count > 0 {
|
||||
if let contentBlockers = webView?.settings?.contentBlockers, contentBlockers.count > 0 {
|
||||
do {
|
||||
let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: [])
|
||||
let blockRules = String(data: jsonData, encoding: String.Encoding.utf8)
|
||||
|
@ -165,27 +171,22 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
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 {
|
||||
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)
|
||||
if allowingReadAccessToURL?.scheme != "file" {
|
||||
allowingReadAccessToURL = nil
|
||||
}
|
||||
}
|
||||
webView.loadUrl(urlRequest: initialUrlRequest, allowingReadAccessTo: allowingReadAccessToURL)
|
||||
webView?.loadUrl(urlRequest: initialUrlRequest, allowingReadAccessTo: allowingReadAccessToURL)
|
||||
}
|
||||
|
||||
channelDelegate?.onBrowserCreated()
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("InAppBrowserWebViewController - dealloc")
|
||||
dispose()
|
||||
}
|
||||
|
||||
public override func viewDidDisappear(_ animated: Bool) {
|
||||
dispose()
|
||||
super.viewDidDisappear(animated)
|
||||
|
@ -203,8 +204,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
}
|
||||
|
||||
public func prepareWebView() {
|
||||
webView.settings = webViewSettings
|
||||
webView.prepare()
|
||||
webView?.settings = webViewSettings
|
||||
webView?.prepare()
|
||||
|
||||
searchBar = UISearchBar()
|
||||
searchBar.keyboardType = .URL
|
||||
|
@ -305,8 +306,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
}
|
||||
|
||||
public func didStartNavigation(url: URL?) {
|
||||
forwardButton.isEnabled = webView.canGoForward
|
||||
backButton.isEnabled = webView.canGoBack
|
||||
forwardButton.isEnabled = webView?.canGoForward ?? false
|
||||
backButton.isEnabled = webView?.canGoBack ?? false
|
||||
progressBar.setProgress(0.0, animated: false)
|
||||
guard let url = url else {
|
||||
return
|
||||
|
@ -315,8 +316,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
}
|
||||
|
||||
public func didUpdateVisitedHistory(url: URL?) {
|
||||
forwardButton.isEnabled = webView.canGoForward
|
||||
backButton.isEnabled = webView.canGoBack
|
||||
forwardButton.isEnabled = webView?.canGoForward ?? false
|
||||
backButton.isEnabled = webView?.canGoBack ?? false
|
||||
guard let url = url else {
|
||||
return
|
||||
}
|
||||
|
@ -324,8 +325,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
}
|
||||
|
||||
public func didFinishNavigation(url: URL?) {
|
||||
forwardButton.isEnabled = webView.canGoForward
|
||||
backButton.isEnabled = webView.canGoBack
|
||||
forwardButton.isEnabled = webView?.canGoForward ?? false
|
||||
backButton.isEnabled = webView?.canGoBack ?? false
|
||||
progressBar.setProgress(0.0, animated: false)
|
||||
guard let url = url else {
|
||||
return
|
||||
|
@ -334,8 +335,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
}
|
||||
|
||||
public func didFailNavigation(url: URL?, error: Error) {
|
||||
forwardButton.isEnabled = webView.canGoForward
|
||||
backButton.isEnabled = webView.canGoBack
|
||||
forwardButton.isEnabled = webView?.canGoForward ?? false
|
||||
backButton.isEnabled = webView?.canGoBack ?? false
|
||||
progressBar.setProgress(0.0, animated: false)
|
||||
}
|
||||
|
||||
|
@ -350,7 +351,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
return
|
||||
}
|
||||
let request = URLRequest(url: url)
|
||||
webView.load(request)
|
||||
webView?.load(request)
|
||||
}
|
||||
|
||||
public func show(completion: (() -> Void)? = nil) {
|
||||
|
@ -381,12 +382,12 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
}
|
||||
|
||||
@objc public func reload() {
|
||||
webView.reload()
|
||||
didUpdateVisitedHistory(url: webView.url)
|
||||
webView?.reload()
|
||||
didUpdateVisitedHistory(url: webView?.url)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
|
@ -413,26 +414,25 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
}
|
||||
|
||||
@objc public func goBack() {
|
||||
if webView.canGoBack {
|
||||
if let webView = webView, webView.canGoBack {
|
||||
webView.goBack()
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func goForward() {
|
||||
if webView.canGoForward {
|
||||
if let webView = webView, webView.canGoForward {
|
||||
webView.goForward()
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func goBackOrForward(steps: Int) {
|
||||
webView.goBackOrForward(steps: steps)
|
||||
webView?.goBackOrForward(steps: steps)
|
||||
}
|
||||
|
||||
public func setSettings(newSettings: InAppBrowserSettings, newSettingsMap: [String: Any]) {
|
||||
|
||||
let newInAppWebViewOptions = InAppWebViewSettings()
|
||||
let _ = newInAppWebViewOptions.parse(settings: newSettingsMap)
|
||||
self.webView.setSettings(newSettings: newInAppWebViewOptions, newSettingsMap: newSettingsMap)
|
||||
let newInAppWebViewSettings = InAppWebViewSettings()
|
||||
let _ = newInAppWebViewSettings.parse(settings: newSettingsMap)
|
||||
webView?.setSettings(newSettings: newInAppWebViewSettings, newSettingsMap: newSettingsMap)
|
||||
|
||||
if newSettingsMap["hidden"] != nil, browserSettings?.hidden != newSettings.hidden {
|
||||
if newSettings.hidden {
|
||||
|
@ -537,12 +537,12 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
progressBar.isHidden = newSettings.hideProgressBar
|
||||
}
|
||||
|
||||
self.browserSettings = newSettings
|
||||
self.webViewSettings = newInAppWebViewOptions
|
||||
browserSettings = newSettings
|
||||
webViewSettings = newInAppWebViewSettings
|
||||
}
|
||||
|
||||
public func getSettings() -> [String: Any?]? {
|
||||
let webViewSettingsMap = self.webView.getSettings()
|
||||
let webViewSettingsMap = webView?.getSettings()
|
||||
if (self.browserSettings == nil || webViewSettingsMap == nil) {
|
||||
return nil
|
||||
}
|
||||
|
@ -568,7 +568,10 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
|
|||
backButton.target = nil
|
||||
reloadButton.target = nil
|
||||
shareButton.target = nil
|
||||
methodCallDelegate?.webView = nil
|
||||
methodCallDelegate = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("InAppBrowserWebViewController - dealloc")
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class ContextMenuSettings: ISettings<NSObject> {
|
||||
public class ContextMenuSettings: ISettings<NSObject> {
|
||||
|
||||
var hideDefaultSystemContextMenuItems = false;
|
||||
|
||||
|
|
|
@ -10,37 +10,37 @@ import Foundation
|
|||
import WebKit
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
class CustomSchemeHandler : NSObject, WKURLSchemeHandler {
|
||||
public class CustomSchemeHandler : NSObject, WKURLSchemeHandler {
|
||||
var schemeHandlers: [Int:WKURLSchemeTask] = [:]
|
||||
|
||||
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
|
||||
public func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
|
||||
schemeHandlers[urlSchemeTask.hash] = urlSchemeTask
|
||||
let inAppWebView = webView as! InAppWebView
|
||||
if let url = urlSchemeTask.request.url {
|
||||
inAppWebView.onLoadResourceCustomScheme(url: url.absoluteString, result: {(result) -> Void in
|
||||
if result is FlutterError {
|
||||
print((result as! FlutterError).message ?? "")
|
||||
let callback = WebViewChannelDelegate.LoadResourceCustomSchemeCallback()
|
||||
callback.nonNullSuccess = { (response: CustomSchemeResponse) in
|
||||
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 {}
|
||||
else {
|
||||
let json: [String: Any]
|
||||
if let r = result {
|
||||
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 (self.schemeHandlers[urlSchemeTask.hash] != nil) {
|
||||
urlSchemeTask.didReceive(urlResponse)
|
||||
urlSchemeTask.didReceive(data.data)
|
||||
urlSchemeTask.didFinish()
|
||||
self.schemeHandlers.removeValue(forKey: urlSchemeTask.hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
callback.error = { (code: String, message: String?, details: Any?) in
|
||||
print(code + ", " + (message ?? ""))
|
||||
}
|
||||
|
||||
if let channelDelegate = inAppWebView.channelDelegate {
|
||||
channelDelegate.onLoadResourceCustomScheme(url: url, callback: callback)
|
||||
} else {
|
||||
callback.defaultBehaviour(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
|
||||
public func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
|
||||
schemeHandlers.removeValue(forKey: urlSchemeTask.hash)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,24 +8,13 @@
|
|||
import Foundation
|
||||
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 methodCallDelegate: InAppWebViewMethodHandler?
|
||||
|
||||
init(registrar: FlutterPluginRegistrar, withFrame frame: CGRect, viewIdentifier viewId: Any, params: NSDictionary) {
|
||||
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!.clipsToBounds = true
|
||||
|
||||
|
@ -46,23 +35,26 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
|
|||
let _ = settings.parse(settings: initialSettings)
|
||||
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: settings)
|
||||
|
||||
var webView: InAppWebView?
|
||||
|
||||
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
|
||||
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!.contextMenu = contextMenu
|
||||
webView!.channel = channel!
|
||||
webView!.initialUserScripts = userScripts
|
||||
} else {
|
||||
webView = InAppWebView(frame: myView!.bounds,
|
||||
webView = InAppWebView(id: viewId,
|
||||
registrar: registrar,
|
||||
frame: myView!.bounds,
|
||||
configuration: preWebviewConfiguration,
|
||||
contextMenu: contextMenu,
|
||||
channel: channel!,
|
||||
userScripts: userScripts)
|
||||
}
|
||||
|
||||
methodCallDelegate = InAppWebViewMethodHandler(webView: webView!)
|
||||
channel!.setMethodCallHandler(LeakAvoider(delegate: methodCallDelegate!).handle)
|
||||
|
||||
let pullToRefreshSettings = PullToRefreshSettings()
|
||||
let _ = pullToRefreshSettings.parse(settings: pullToRefreshInitialSettings)
|
||||
let pullToRefreshControl = PullToRefreshControl(registrar: registrar, id: viewId, settings: pullToRefreshSettings)
|
||||
|
@ -80,11 +72,26 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
|
|||
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 {
|
||||
return myView!
|
||||
}
|
||||
|
||||
public func makeInitialLoad(params: NSDictionary) {
|
||||
guard let webView = webView() else {
|
||||
return
|
||||
}
|
||||
|
||||
let windowId = params["windowId"] as? Int64
|
||||
let initialUrlRequest = params["initialUrlRequest"] as? [String: Any?]
|
||||
let initialFile = params["initialFile"] as? String
|
||||
|
@ -92,8 +99,8 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
|
|||
|
||||
if windowId == nil {
|
||||
if #available(iOS 11.0, *) {
|
||||
self.webView!.configuration.userContentController.removeAllContentRuleLists()
|
||||
if let contentBlockers = webView!.settings?.contentBlockers, contentBlockers.count > 0 {
|
||||
webView.configuration.userContentController.removeAllContentRuleLists()
|
||||
if let contentBlockers = webView.settings?.contentBlockers, contentBlockers.count > 0 {
|
||||
do {
|
||||
let jsonData = try JSONSerialization.data(withJSONObject: contentBlockers, options: [])
|
||||
let blockRules = String(data: jsonData, encoding: String.Encoding.utf8)
|
||||
|
@ -106,7 +113,7 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
|
|||
return
|
||||
}
|
||||
|
||||
let configuration = self.webView!.configuration
|
||||
let configuration = webView.configuration
|
||||
configuration.userContentController.add(contentRuleList!)
|
||||
|
||||
self.load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData)
|
||||
|
@ -120,14 +127,18 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
|
|||
load(initialUrlRequest: initialUrlRequest, initialFile: initialFile, initialData: initialData)
|
||||
}
|
||||
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]?) {
|
||||
guard let webView = webView() else {
|
||||
return
|
||||
}
|
||||
|
||||
if let initialFile = initialFile {
|
||||
do {
|
||||
try webView?.loadFile(assetFilePath: initialFile)
|
||||
try webView.loadFile(assetFilePath: initialFile)
|
||||
}
|
||||
catch let error as NSError {
|
||||
dump(error)
|
||||
|
@ -139,34 +150,31 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
|
|||
let encoding = initialData["encoding"]!
|
||||
let baseUrl = URL(string: initialData["baseUrl"]!)!
|
||||
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)
|
||||
if allowingReadAccessToURL?.scheme != "file" {
|
||||
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 {
|
||||
let urlRequest = URLRequest.init(fromPluginMap: initialUrlRequest)
|
||||
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)
|
||||
if allowingReadAccessToURL?.scheme != "file" {
|
||||
allowingReadAccessToURL = nil
|
||||
}
|
||||
}
|
||||
webView?.loadUrl(urlRequest: urlRequest, allowingReadAccessTo: allowingReadAccessToURL)
|
||||
webView.loadUrl(urlRequest: urlRequest, allowingReadAccessTo: allowingReadAccessToURL)
|
||||
}
|
||||
}
|
||||
|
||||
func dispose() {
|
||||
channel?.setMethodCallHandler(nil)
|
||||
channel = nil
|
||||
methodCallDelegate?.dispose()
|
||||
methodCallDelegate = nil
|
||||
webView?.dispose()
|
||||
webView = nil
|
||||
public func dispose() {
|
||||
if let webView = webView() {
|
||||
webView.dispose()
|
||||
}
|
||||
myView = nil
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -1,43 +1,18 @@
|
|||
//
|
||||
// WebMessageChannel.swift
|
||||
// WebMessageChannelChannelDelegate.swift
|
||||
// flutter_inappwebview
|
||||
//
|
||||
// Created by Lorenzo Pichilli on 10/03/21.
|
||||
// Created by Lorenzo Pichilli on 07/05/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class WebMessageChannel : FlutterMethodCallDelegate {
|
||||
var id: String
|
||||
var channel: FlutterMethodChannel?
|
||||
var webView: InAppWebView?
|
||||
var ports: [WebMessagePort] = []
|
||||
public class WebMessageChannelChannelDelegate : ChannelDelegate {
|
||||
private weak var webMessageChannel: WebMessageChannel?
|
||||
|
||||
public init(id: String) {
|
||||
self.id = id
|
||||
super.init()
|
||||
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 init(webMessageChannel: WebMessageChannel, channel: FlutterMethodChannel) {
|
||||
super.init(channel: channel)
|
||||
self.webMessageChannel = webMessageChannel
|
||||
}
|
||||
|
||||
public override func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
|
@ -45,7 +20,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
|
|||
|
||||
switch call.method {
|
||||
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 port = ports[index]
|
||||
do {
|
||||
|
@ -57,11 +32,11 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
|
|||
}
|
||||
|
||||
} else {
|
||||
result(true)
|
||||
result(true)
|
||||
}
|
||||
break
|
||||
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 port = ports[index]
|
||||
let message = arguments!["message"] as! [String: Any?]
|
||||
|
@ -90,7 +65,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
|
|||
}
|
||||
break
|
||||
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 port = ports[index]
|
||||
do {
|
||||
|
@ -118,34 +93,12 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
|
|||
channel?.invokeMethod("onMessage", arguments: arguments)
|
||||
}
|
||||
|
||||
public func toMap () -> [String:Any?] {
|
||||
return [
|
||||
"id": id
|
||||
]
|
||||
}
|
||||
|
||||
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
|
||||
public override func dispose() {
|
||||
super.dispose()
|
||||
webMessageChannel = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("WebMessageChannel - dealloc")
|
||||
dispose()
|
||||
}
|
||||
}
|
|
@ -9,19 +9,19 @@ import Foundation
|
|||
import WebKit
|
||||
|
||||
public class WebMessageListener : FlutterMethodCallDelegate {
|
||||
|
||||
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_web_message_listener_"
|
||||
var jsObjectName: String
|
||||
var allowedOriginRules: Set<String>
|
||||
var channel: FlutterMethodChannel?
|
||||
var webView: InAppWebView?
|
||||
var channelDelegate: WebMessageListenerChannelDelegate?
|
||||
weak var webView: InAppWebView?
|
||||
|
||||
public init(jsObjectName: String, allowedOriginRules: Set<String>) {
|
||||
self.jsObjectName = jsObjectName
|
||||
self.allowedOriginRules = allowedOriginRules
|
||||
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())
|
||||
self.channel?.setMethodCallHandler(self.handle)
|
||||
self.channelDelegate = WebMessageListenerChannelDelegate(webMessageListener: self, channel: channel)
|
||||
}
|
||||
|
||||
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 {
|
||||
for allowedOriginRule in allowedOriginRules {
|
||||
if allowedOriginRule == "*" {
|
||||
|
@ -204,19 +169,10 @@ public class WebMessageListener : FlutterMethodCallDelegate {
|
|||
}
|
||||
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() {
|
||||
channel?.setMethodCallHandler(nil)
|
||||
channel = nil
|
||||
channelDelegate?.dispose()
|
||||
channelDelegate = nil
|
||||
webView = nil
|
||||
}
|
||||
|
|
@ -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
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
import Foundation
|
||||
import WebKit
|
||||
|
||||
class InAppWebViewStatic: ChannelDelegate {
|
||||
public class InAppWebViewStatic: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_static"
|
||||
static var registrar: FlutterPluginRegistrar?
|
||||
static var webViewForUserAgent: WKWebView?
|
||||
|
@ -73,4 +73,8 @@ class InAppWebViewStatic: ChannelDelegate {
|
|||
InAppWebViewStatic.webViewForUserAgent = nil
|
||||
InAppWebViewStatic.defaultUserAgent = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import Foundation
|
|||
import WebKit
|
||||
|
||||
@available(iOS 11.0, *)
|
||||
class MyCookieManager: ChannelDelegate {
|
||||
public class MyCookieManager: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_cookiemanager"
|
||||
static var registrar: FlutterPluginRegistrar?
|
||||
static var httpCookieStore: WKHTTPCookieStore?
|
||||
|
@ -295,4 +295,8 @@ class MyCookieManager: ChannelDelegate {
|
|||
MyCookieManager.registrar = nil
|
||||
MyCookieManager.httpCookieStore = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import Foundation
|
|||
import WebKit
|
||||
|
||||
@available(iOS 9.0, *)
|
||||
class MyWebStorageManager: ChannelDelegate {
|
||||
public class MyWebStorageManager: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_webstoragemanager"
|
||||
static var registrar: FlutterPluginRegistrar?
|
||||
static var websiteDataStore: WKWebsiteDataStore?
|
||||
|
@ -105,4 +105,8 @@ class MyWebStorageManager: ChannelDelegate {
|
|||
MyWebStorageManager.registrar = nil
|
||||
MyWebStorageManager.websiteDataStore = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class PlatformUtil: ChannelDelegate {
|
||||
public class PlatformUtil: ChannelDelegate {
|
||||
static let METHOD_CHANNEL_NAME = "com.pichillilorenzo/flutter_inappwebview_platformutil"
|
||||
static var registrar: FlutterPluginRegistrar?
|
||||
|
||||
|
@ -59,4 +59,8 @@ class PlatformUtil: ChannelDelegate {
|
|||
super.dispose()
|
||||
PlatformUtil.registrar = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
import Foundation
|
||||
|
||||
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)
|
||||
self.pullToRefreshControl = pullToRefreshControl
|
||||
}
|
||||
|
@ -87,4 +87,8 @@ public class PullToRefreshChannelDelegate : ChannelDelegate {
|
|||
super.dispose()
|
||||
pullToRefreshControl = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,4 +94,8 @@ public class ChromeSafariBrowserManager: ChannelDelegate {
|
|||
}
|
||||
ChromeSafariBrowserManager.browsers.removeAll()
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
public class SafariViewControllerChannelDelegate : ChannelDelegate {
|
||||
|
||||
private var safariViewController: SafariViewController?
|
||||
private weak var safariViewController: SafariViewController?
|
||||
|
||||
public init(safariViewController: SafariViewController, channel: FlutterMethodChannel) {
|
||||
super.init(channel: channel)
|
||||
|
@ -60,4 +59,8 @@ public class SafariViewControllerChannelDelegate : ChannelDelegate {
|
|||
super.dispose()
|
||||
safariViewController = nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class ClientCertChallenge: NSObject {
|
||||
public class ClientCertChallenge: NSObject {
|
||||
var protectionSpace: URLProtectionSpace!
|
||||
|
||||
public init(fromChallenge: URLAuthenticationChallenge) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class HttpAuthenticationChallenge: NSObject {
|
||||
public class HttpAuthenticationChallenge: NSObject {
|
||||
var protectionSpace: URLProtectionSpace!
|
||||
var previousFailureCount: Int = 0
|
||||
var failureResponse: URLResponse?
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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 }
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class ServerTrustChallenge: NSObject {
|
||||
public class ServerTrustChallenge: NSObject {
|
||||
var protectionSpace: URLProtectionSpace!
|
||||
|
||||
public init(fromChallenge: URLAuthenticationChallenge) {
|
||||
|
|
|
@ -213,7 +213,7 @@ public class Util {
|
|||
} else {
|
||||
// normalize grouped zeros ::
|
||||
var zeros: [String] = []
|
||||
for j in ipv6.count...8 {
|
||||
for _ in ipv6.count...8 {
|
||||
zeros.append("0000")
|
||||
}
|
||||
fullIPv6[i] = zeros.joined(separator: ":")
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
import Foundation
|
||||
import WebKit
|
||||
|
||||
class WKProcessPoolManager {
|
||||
public class WKProcessPoolManager {
|
||||
static let sharedProcessPool = WKProcessPool()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue