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

340 lines
12 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 plugin: InAppWebViewFlutterPlugin?
var windowId: Int64?
var webView: InAppWebView?
var channelDelegate: InAppBrowserChannelDelegate?
var initialUrlRequest: URLRequest?
var initialFile: String?
var browserSettings: InAppBrowserSettings?
var webViewSettings: InAppWebViewSettings?
var initialData: String?
var initialMimeType: String?
var initialEncoding: String?
var initialBaseUrl: String?
var initialUserScripts: [[String: Any]] = []
var isHidden = false
public override func loadView() {
guard let plugin = plugin, let registrar = plugin.registrar else {
return
}
let channel = FlutterMethodChannel(name: InAppBrowserWebViewController.METHOD_CHANNEL_NAME_PREFIX + id, binaryMessenger: registrar.messenger)
channelDelegate = InAppBrowserChannelDelegate(channel: channel)
var userScripts: [UserScript] = []
for initialUserScript in initialUserScripts {
userScripts.append(UserScript.fromMap(map: initialUserScript, windowId: windowId)!)
}
let preWebviewConfiguration = InAppWebView.preWKWebViewConfiguration(settings: webViewSettings)
if let wId = windowId, let webViewTransport = plugin.inAppWebViewManager?.windowWebViews[wId] {
webView = webViewTransport.webView
webView!.initialUserScripts = userScripts
} else {
webView = InAppWebView(id: nil,
plugin: nil,
frame: .zero,
configuration: preWebviewConfiguration,
userScripts: userScripts)
}
guard let webView = webView else {
return
}
webView.inAppBrowserDelegate = self
webView.id = id
webView.plugin = plugin
webView.channelDelegate = WebViewChannelDelegate(webView: webView, channel: channel)
let findInteractionController = FindInteractionController(
plugin: plugin,
id: id, webView: webView, settings: nil)
webView.findInteractionController = findInteractionController
findInteractionController.prepare()
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 {
channelDelegate?.onBrowserCreated()
webView?.runWindowBeforeCreatedCallbacks()
} 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: .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
}
if let browserSettings = browserSettings,
let toolbarTopFixedTitle = browserSettings.toolbarTopFixedTitle {
window?.title = toolbarTopFixedTitle
} else {
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)
}
@objc public func onMenuItemClicked(sender: Any?) {
var identifier: String?
if let sender = sender as? NSMenuItem {
identifier = sender.identifier?.rawValue
}
if identifier == nil, let sender = sender as? NSButton {
identifier = sender.identifier?.rawValue
}
if let identifier = identifier, let window = window {
let menuItem = window.menuItems.first { item in
return item.id == Int64(identifier)
}
if let menuItem = menuItem {
channelDelegate?.onMenuItemClicked(menuItem: menuItem)
}
}
}
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() {
isHidden = true
window?.hide()
}
public func show() {
isHidden = false
window?.show()
}
public func close() {
window?.close()
}
public func dispose() {
channelDelegate?.onExit()
channelDelegate?.dispose()
channelDelegate = nil
webView?.dispose()
webView?.removeFromSuperview()
webView = nil
window = nil
plugin = nil
}
deinit {
debugPrint("InAppBrowserWebViewController - dealloc")
dispose()
}
}