首页 > 解决方案 > Swift:如何激活和取消隐藏任何应用程序的窗口?

问题描述

我看到NSRunningApplicationInstance.activate()方法的非常奇怪的行为。

假设我找到了名为“Finder”的应用程序。目前这个应用是:

Not active和/或hidden

我有非常简单的代码:

let activeOptions: NSApplication.ActivationOptions = [.activateAllWindows, .activateIgnoringOtherApps]

print("1. isActive: \(app.isActive); isHidden: \(app.isHidden)")
if (!app.isActive)
{
   app.activate(options: activeOptions)
}

if ( app.isHidden )
{
   app.unhide()
}
print("2. isActive: \(app.isActive); isHidden: \(app.isHidden)")

要查找所需的应用程序,您可以使用以下代码:

let app = NSWorkspace.shared.runningApplications.filter{ $0.localizedName = "NameOfApp"}

2次运行代码结果:

  1. 活动:假;隐藏:假
  2. 活动:假;隐藏:假
  3. isActive:真;隐藏:假
  4. isActive:真;隐藏:假

如果你会尝试它......:

  1. 代码将显示应用程序的菜单: 在此处输入图像描述

  2. 但仅在第二次代码运行时!(为什么?)

  3. 不会显示应用程序窗口!(为什么?)

而且我在很多应用程序中都看到了类似的行为,而不仅仅是 Finder。

作为示例 SourceTree 应用程序。


有人可以解释逻辑以及如何在任何情况下通过某些代码显示任何已运行应用程序的窗口吗?

标签: swiftmacosmacos-catalina

解决方案


这是工作游乐场模块。该方法是使用 KVO 来获取可观察属性,以便在目标应用程序的确切期望状态发生时得到通知。希望它会有所帮助。

import Cocoa

class AppActivator: NSObject {

    private var application: NSRunningApplication!
    private let filterName: String

    init(appName: String) {
        filterName = appName
    }

    func activate() {
        guard let app = NSWorkspace.shared.runningApplications.filter ({
            return $0.localizedName == self.filterName || $0.bundleIdentifier?.contains(self.filterName) ?? false
        }).first else {
            print("Application \(self.filterName) not found")
            return
        }

        guard app.activationPolicy != .prohibited else {
            print("Application \(self.filterName) prohibits activation")
            return
        }

        self.application = app

        self.unhideAppIfNeeded()
        self.activateAppIfNeeded()
    }

    private func unhideAppIfNeeded() {
        if application.isHidden {
            application.addObserver(self, forKeyPath: "isHidden", options: .new, context: nil)
            application.unhide()
        }
    }

    private func activateAppIfNeeded() {
        if !application.isHidden && !application.isActive {
            application.addObserver(self, forKeyPath: "isActive", options: .new, context: nil)
            application.activate(options: .activateIgnoringOtherApps)
        }
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "isHidden" {
            application.removeObserver(self, forKeyPath: "isHidden")
            activateAppIfNeeded()
        } else if keyPath == "isActive" {
            application.removeObserver(self, forKeyPath: "isActive")
            print("Application \(application.localizedName) - ACTIVATED!")
        }
    }
}

let activator = AppActivator(appName: "Finder")
activator.activate()

推荐阅读