如何检测OS X系统中任意应用进入或退出全屏状态?
在Swift中监听macOS任意应用的全屏状态变化
我完全懂这种踩坑的感觉——macOS的全屏状态监听确实藏得有点深,尤其是用Swift开发时,Objective-C的老代码转过来经常遇到各种适配问题。下面给你一套可行的Swift实现方案,亲测能搞定任意应用的全屏进入/退出通知:
核心思路
利用NSWorkspace监听应用激活/启动/退出事件,再给目标应用的窗口注册NSWindow的全屏状态通知,这样就能精准捕获每个应用的全屏变化。相比轮询窗口信息的方案,这种基于通知的方式更高效、更优雅。
完整Swift代码实现
import Cocoa class FullScreenMonitor { // 存储所有通知监听器,避免被提前释放 private var observers = [NSObjectProtocol]() init() { setupApplicationObservers() // 给当前已激活的前台应用提前注册窗口监听 if let currentApp = NSWorkspace.shared.frontmostApplication { registerWindowNotifications(for: currentApp) } } private func setupApplicationObservers() { // 监听应用激活事件 let activateObserver = NSWorkspace.shared.notificationCenter.addObserver( forName: NSWorkspace.didActivateApplicationNotification, object: nil, queue: .main ) { [weak self] notification in guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication else { return } self?.registerWindowNotifications(for: app) } observers.append(activateObserver) // 监听应用启动事件,处理刚启动就全屏的应用 let launchObserver = NSWorkspace.shared.notificationCenter.addObserver( forName: NSWorkspace.didLaunchApplicationNotification, object: nil, queue: .main ) { [weak self] notification in guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication else { return } self?.registerWindowNotifications(for: app) } observers.append(launchObserver) // 监听应用退出事件,清理对应的监听器 let terminateObserver = NSWorkspace.shared.notificationCenter.addObserver( forName: NSWorkspace.didTerminateApplicationNotification, object: nil, queue: .main ) { [weak self] notification in guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication else { return } self?.cleanupWindowNotifications(for: app) } observers.append(terminateObserver) } private func registerWindowNotifications(for app: NSRunningApplication) { // 遍历应用的所有窗口,确保不会漏过任何一个可能全屏的窗口 guard let windows = app.windows else { return } for window in windows { addFullScreenObservers(to: window) } } private func addFullScreenObservers(to window: NSWindow) { // 先移除旧的监听器,避免重复注册 NotificationCenter.default.removeObserver( self, name: NSWindow.didEnterFullScreenNotification, object: window ) NotificationCenter.default.removeObserver( self, name: NSWindow.didExitFullScreenNotification, object: window ) // 注册进入全屏通知 let enterObserver = NotificationCenter.default.addObserver( forName: NSWindow.didEnterFullScreenNotification, object: window, queue: .main ) { notification in guard let window = notification.object as? NSWindow, let app = NSWorkspace.shared.application(forWindow: window) else { return } let appName = app.localizedName ?? "未知应用" print("✅ \(appName) 进入全屏状态") // 在这里添加你的业务逻辑,比如发送自定义通知、更新UI等 } observers.append(enterObserver) // 注册退出全屏通知 let exitObserver = NotificationCenter.default.addObserver( forName: NSWindow.didExitFullScreenNotification, object: window, queue: .main ) { notification in guard let window = notification.object as? NSWindow, let app = NSWorkspace.shared.application(forWindow: window) else { return } let appName = app.localizedName ?? "未知应用" print("❌ \(appName) 退出全屏状态") // 在这里添加你的业务逻辑 } observers.append(exitObserver) } private func cleanupWindowNotifications(for app: NSRunningApplication) { guard let windows = app.windows else { return } for window in windows { NotificationCenter.default.removeObserver( self, name: NSWindow.didEnterFullScreenNotification, object: window ) NotificationCenter.default.removeObserver( self, name: NSWindow.didExitFullScreenNotification, object: window ) } } deinit { // 销毁时移除所有监听器,避免内存泄漏 observers.forEach { NotificationCenter.default.removeObserver($0) } } }
关键配置说明
在macOS 10.14及以上系统,你的应用需要申请辅助功能权限才能获取其他应用的窗口信息。请在项目的Info.plist中添加以下键值对:
<key>NSAccessibilityUsageDescription</key> <string>需要获取应用窗口状态,以监听全屏变化</string>
用户首次启动应用时,系统会弹出权限申请弹窗,务必引导用户授权。
使用方式
在你的应用初始化代码中(比如AppDelegate的applicationDidFinishLaunching方法),创建监听器实例即可:
class AppDelegate: NSObject, NSApplicationDelegate { private var fullScreenMonitor: FullScreenMonitor? func applicationDidFinishLaunching(_ aNotification: Notification) { fullScreenMonitor = FullScreenMonitor() } }
补充说明
- 这套方案覆盖了绝大多数原生macOS应用,包括多窗口应用;
- 对于Electron等非原生框架开发的应用,部分窗口可能无法被直接捕获,此时可以结合定期扫描
CGWindowListCopyWindowInfo的方式补充监听; - 如果你之前尝试的Objective-C代码是基于轮询的,建议替换成这套通知方案,减少系统资源消耗。
内容的提问来源于stack exchange,提问作者Kristian Erik Tigersjäl
相关产品推荐
相关产品推荐

