如何在macOS Swift应用中获取Finder当前选中的文件/文件夹详情?
解决方案:获取Finder选中的文件/文件夹
1. 用AppleScript查询当前选中项
Finder提供了AppleScript接口,可直接获取选中的文件/文件夹。在Swift中通过NSAppleScript执行脚本即可实现:
import Foundation func getFinderSelectedItems() -> [URL]? { let script = """ tell application "Finder" set selectedItems to selection set itemPaths to {} repeat with item in selectedItems set end of itemPaths to POSIX path of item end repeat return itemPaths end tell """ let appleScript = NSAppleScript(source: script) var error: NSDictionary? guard let result = appleScript?.executeAndReturnError(&error) else { print("脚本执行错误: \(error ?? [:])") return nil } guard let paths = result.arrayValue?.compactMap({ $0.stringValue }) else { return [] } return paths.map { URL(fileURLWithPath: $0) } }
调用该函数即可获取当前Finder选中项的URL数组,从中提取文件名/文件夹名即可满足显示需求。
2. 实时监听选中状态变化
Finder没有直接提供选中变化的通知接口,可通过以下两种方案实现实时监听:
方案A:定时轮询
适合轻量后台应用,设置定时器定期查询选中状态,对比前后结果触发更新:
import Foundation var lastSelectedPaths: Set<String> = [] func startFinderSelectionMonitoring() { Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in guard let currentItems = getFinderSelectedItems() else { return } let currentPaths = Set(currentItems.map { $0.path }) if currentPaths != lastSelectedPaths { lastSelectedPaths = currentPaths // 更新显示逻辑 if let firstItem = currentItems.first { print("当前选中: \(firstItem.lastPathComponent)") } else { print("无选中项") } } } }
注意:后台应用需确保定时器运行在主线程RunLoop上。
方案B:结合Workspace通知+补充轮询
通过NSWorkspace监听Finder激活、窗口变化事件,触发查询,同时搭配短周期轮询覆盖窗口内选中变化场景:
import AppKit func setupWorkspaceNotifications() { let notificationCenter = NSWorkspace.shared.notificationCenter // 监听Finder激活事件 notificationCenter.addObserver(forName: NSWorkspace.didActivateApplicationNotification, object: nil, queue: .main) { notification in guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication, app.bundleIdentifier == "com.apple.finder" else { return } updateSelectedItemDisplay() } // 监听Finder窗口内容变化 notificationCenter.addObserver(forName: NSWorkspace.didChangeFileLabelsNotification, object: nil, queue: .main) { _ in updateSelectedItemDisplay() } // 启动补充轮询 startFinderSelectionMonitoring() } func updateSelectedItemDisplay() { guard let selectedItems = getFinderSelectedItems() else { return } if let firstItem = selectedItems.first { print("显示选中项: \(firstItem.lastPathComponent)") // 替换为你的UI更新逻辑 } else { print("无选中项") } }
3. 权限配置
- 应用需要请求辅助功能权限:在
Info.plist中添加NSAccessibilityUsageDescription键,说明权限用途(例如"需要获取Finder选中的文件信息"),用户需在系统设置中授予该权限。 - 后台运行权限:在Xcode的Capabilities中开启"Background Modes",选择对应后台模式(如"App provides content to the user")。
替代方案:ScriptingBridge
若偏好类型安全的调用方式,可通过ScriptingBridge生成Finder的桥接接口:
- 终端执行命令生成桥接文件:
sdef /System/Library/CoreServices/Finder.app | sdp -fh --basename Finder
- 将生成的
Finder.h和Finder.swift加入项目,即可直接调用:
import ScriptingBridge func getFinderSelectedItemsViaScriptingBridge() -> [URL]? { guard let finder = SBApplication(bundleIdentifier: "com.apple.finder") else { return nil } guard let selection = finder.selection as? [SBObject] else { return [] } return selection.compactMap { item in guard let path = item.value(forKey: "POSIXPath") as? String else { return nil } return URL(fileURLWithPath: path) } }
内容的提问来源于stack exchange,提问作者user1880312
相关产品推荐
相关产品推荐

