iosWebViewFix/macos/Classes/InAppBrowser/InAppBrowserWebViewControll...

303 lines
11 KiB
Swift
Executable File

//
// InAppBrowserWebViewController.swift
// flutter_inappwebview
//
// Created by Lorenzo on 17/09/18.
//
import FlutterMacOS
import AppKit
import WebKit
import Foundation
public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelegate, Disposable {
static var METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappbrowser_";
var progressBar: NSProgressIndicator!
var window: InAppBrowserWindow?
var id: String = ""
var windowId: Int64?
var webView: InAppWebView?
var channelDelegate: InAppBrowserChannelDelegate?
var initialUrlRequest: URLRequest?
var initialFile: String?
var contextMenu: [String: Any]?
var browserSettings: InAppBrowserSettings?
var webViewSettings: InAppWebViewSettings?
var initialData: String?
var initialMimeType: String?
var initialEncoding: String?
var initialBaseUrl: String?
var initialUserScripts: [[String: Any]] = []
public override func loadView() {
let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: SwiftFlutterPlugin.instance!.registrar!.messenger)
channelDelegate = InAppBrowserChannelDelegate(channel: channel)
var userScripts: [UserScript] = []
for intialUserScript in initialUserScripts {
userScripts.append(UserScript.fromMap(map: intialUserScript, windowId: windowId)!)
}
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: webViewSettings)
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
webView = webViewTransport.webView
webView!.contextMenu = contextMenu
webView!.initialUserScripts = userScripts
} else {
webView = InAppWebView(id: nil,
registrar: nil,
frame: .zero,
configuration: preWebviewConfiguration,
contextMenu: contextMenu,
userScripts: userScripts)
}
guard let webView = webView else {
return
}
webView.inAppBrowserDelegate = self
webView.id = id
webView.channelDelegate = WebViewChannelDelegate(webView: webView, channel: channel)
prepareWebView()
webView.windowCreated = true
progressBar = NSProgressIndicator()
progressBar.style = .bar
progressBar.isIndeterminate = false
progressBar.startAnimation(self)
view = NSView(frame: NSApplication.shared.mainWindow?.frame ?? .zero)
view.addSubview(webView)
view.addSubview(progressBar, positioned: .above, relativeTo: webView)
}
public override func viewDidLoad() {
super.viewDidLoad()
webView?.translatesAutoresizingMaskIntoConstraints = false
progressBar.translatesAutoresizingMaskIntoConstraints = false
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: -6.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
if let wId = windowId, let webViewTransport = InAppWebView.windowWebViews[wId] {
webView?.load(webViewTransport.request)
channelDelegate?.onBrowserCreated()
} else {
if #available(macOS 10.13, *) {
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)
WKContentRuleListStore.default().compileContentRuleList(
forIdentifier: "ContentBlockingRules",
encodedContentRuleList: blockRules) { (contentRuleList, error) in
if let error = error {
print(error.localizedDescription)
return
}
let configuration = self.webView!.configuration
configuration.userContentController.add(contentRuleList!)
self.initLoad()
}
return
} catch {
print(error.localizedDescription)
}
}
}
initLoad()
}
}
public override func viewDidAppear() {
super.viewDidAppear()
window = view.window as? InAppBrowserWindow
}
public func initLoad() {
if let initialFile = initialFile {
do {
try webView?.loadFile(assetFilePath: initialFile)
}
catch let error as NSError {
dump(error)
}
}
else if let initialData = initialData {
let baseUrl = URL(string: initialBaseUrl ?? "about:blank")!
var allowingReadAccessToURL: URL? = nil
if let allowingReadAccessTo = webView?.settings?.allowingReadAccessTo, baseUrl.scheme == "file" {
allowingReadAccessToURL = URL(string: allowingReadAccessTo)
if allowingReadAccessToURL?.scheme != "file" {
allowingReadAccessToURL = nil
}
}
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" {
allowingReadAccessToURL = URL(string: allowingReadAccessTo)
if allowingReadAccessToURL?.scheme != "file" {
allowingReadAccessToURL = nil
}
}
webView?.loadUrl(urlRequest: initialUrlRequest, allowingReadAccessTo: allowingReadAccessToURL)
}
channelDelegate?.onBrowserCreated()
}
public func prepareWebView() {
webView?.settings = webViewSettings
webView?.prepare()
if let browserSettings = browserSettings {
if browserSettings.hideProgressBar {
progressBar.isHidden = true
}
}
}
public func didChangeTitle(title: String?) {
guard let title = title else {
return
}
window?.title = title
window?.update()
}
public func didStartNavigation(url: URL?) {
window?.forwardButton?.isEnabled = webView?.canGoForward ?? false
window?.backButton?.isEnabled = webView?.canGoBack ?? false
progressBar.doubleValue = 0.0
progressBar.isHidden = false
guard let url = url else {
return
}
window?.searchBar?.stringValue = url.absoluteString
}
public func didUpdateVisitedHistory(url: URL?) {
window?.forwardButton?.isEnabled = webView?.canGoForward ?? false
window?.backButton?.isEnabled = webView?.canGoBack ?? false
guard let url = url else {
return
}
window?.searchBar?.stringValue = url.absoluteString
}
public func didFinishNavigation(url: URL?) {
window?.forwardButton?.isEnabled = webView?.canGoForward ?? false
window?.backButton?.isEnabled = webView?.canGoBack ?? false
progressBar.doubleValue = 0.0
progressBar.isHidden = true
guard let url = url else {
return
}
window?.searchBar?.stringValue = url.absoluteString
}
public func didFailNavigation(url: URL?, error: Error) {
window?.forwardButton?.isEnabled = webView?.canGoForward ?? false
window?.backButton?.isEnabled = webView?.canGoBack ?? false
progressBar.doubleValue = 0.0
progressBar.isHidden = true
}
public func didChangeProgress(progress: Double) {
progressBar.isHidden = false
progressBar.doubleValue = progress * 100
if progress == 100.0 {
progressBar.isHidden = true
}
}
@objc public func reload() {
webView?.reload()
didUpdateVisitedHistory(url: webView?.url)
}
@objc public func goBack() {
if let webView = webView, webView.canGoBack {
webView.goBack()
}
}
@objc public func goForward() {
if let webView = webView, webView.canGoForward {
webView.goForward()
}
}
@objc public func goBackOrForward(steps: Int) {
webView?.goBackOrForward(steps: steps)
}
public func setSettings(newSettings: InAppBrowserSettings, newSettingsMap: [String: Any]) {
window?.setSettings(newSettings: newSettings, newSettingsMap: newSettingsMap)
let newInAppWebViewSettings = InAppWebViewSettings()
let _ = newInAppWebViewSettings.parse(settings: newSettingsMap)
webView?.setSettings(newSettings: newInAppWebViewSettings, newSettingsMap: newSettingsMap)
if newSettingsMap["hideProgressBar"] != nil, browserSettings?.hideProgressBar != newSettings.hideProgressBar {
progressBar.isHidden = newSettings.hideProgressBar
}
browserSettings = newSettings
webViewSettings = newInAppWebViewSettings
}
public func getSettings() -> [String: Any?]? {
let webViewSettingsMap = webView?.getSettings()
if (self.browserSettings == nil || webViewSettingsMap == nil) {
return nil
}
var settingsMap = self.browserSettings!.getRealSettings(obj: self)
settingsMap.merge(webViewSettingsMap!, uniquingKeysWith: { (current, _) in current })
return settingsMap
}
public func hide() {
window?.hide()
}
public func show() {
window?.show()
}
public func close() {
window?.close()
}
public func dispose() {
channelDelegate?.onExit()
channelDelegate?.dispose()
channelDelegate = nil
webView?.dispose()
webView = nil
window = nil
}
deinit {
debugPrint("InAppBrowserWebViewController - dealloc")
dispose()
}
}