553 lines
23 KiB
Swift
553 lines
23 KiB
Swift
//
|
|
// 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 = arguments!["baseUrl"] as! String
|
|
webView?.loadData(data: data, mimeType: mimeType, encoding: encoding, baseUrl: baseUrl)
|
|
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 "setOptions":
|
|
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
|
let inAppBrowserOptions = InAppBrowserOptions()
|
|
let inAppBrowserOptionsMap = arguments!["options"] as! [String: Any]
|
|
let _ = inAppBrowserOptions.parse(options: inAppBrowserOptionsMap)
|
|
iabController.setOptions(newOptions: inAppBrowserOptions, newOptionsMap: inAppBrowserOptionsMap)
|
|
} else {
|
|
let inAppWebViewOptions = InAppWebViewOptions()
|
|
let inAppWebViewOptionsMap = arguments!["options"] as! [String: Any]
|
|
let _ = inAppWebViewOptions.parse(options: inAppWebViewOptionsMap)
|
|
webView?.setOptions(newOptions: inAppWebViewOptions, newOptionsMap: inAppWebViewOptionsMap)
|
|
}
|
|
result(true)
|
|
break
|
|
case "getOptions":
|
|
if let iabController = webView?.inAppBrowserDelegate as? InAppBrowserWebViewController {
|
|
result(iabController.getOptions())
|
|
} else {
|
|
result(webView?.getOptions())
|
|
}
|
|
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! Float
|
|
let animated = arguments!["iosAnimated"] as! Bool
|
|
webView?.zoomBy(zoomFactor: zoomFactor, animated: animated)
|
|
result(true)
|
|
break
|
|
case "reloadFromOrigin":
|
|
webView?.reloadFromOrigin()
|
|
result(true)
|
|
break
|
|
case "getScale":
|
|
result(webView?.getScale())
|
|
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!["iosWKPdfConfiguration"] 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
|
|
default:
|
|
result(FlutterMethodNotImplemented)
|
|
break
|
|
}
|
|
}
|
|
|
|
deinit {
|
|
print("InAppWebViewMethodHandler - dealloc")
|
|
webView = nil
|
|
}
|
|
}
|