You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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的桥接接口:

  1. 终端执行命令生成桥接文件:
sdef /System/Library/CoreServices/Finder.app | sdp -fh --basename Finder
  1. 将生成的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 16:35:24