340 lines
12 KiB
Swift
Executable File
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()
|
|
}
|
|
}
|