为何使用AppleScript复制多文件后无法粘贴至第三方应用?如何实现与Finder一致的粘贴效果?
I’ve run into this exact issue before—when you only write NSURL objects to the pasteboard, many third-party apps fail to recognize the content because they rely on the older (but still widely used) file path string format that Finder includes alongside URLs. Let’s fix your AppleScript first, then cover the Swift equivalent.
The Root Cause
Finder doesn’t just put file URLs on the pasteboard when you copy files. It adds multiple data types to support both modern and legacy apps:
public.file-url: The array of NSURL objects (what your original code uses)NSFilenamesPboardType: An array of POSIX file paths as strings (many third-party apps depend on this)
Your current code only writes NSURL objects, which is why Finder works (it handles both types) but other apps don’t.
Fixed AppleScript Code
Here’s the updated script that matches Finder’s behavior perfectly:
#!/usr/bin/osascript use framework "Appkit" use scripting additions use Finder : application "Finder" property this : a reference to current application property NSFileManager : a reference to NSFileManager of this property NSMutableArray : a reference to NSMutableArray of this property NSPasteboard : a reference to NSPasteboard of this property NSString : a reference to NSString of this property NSURL : a reference to NSURL of this property pb : missing value on run input if input's class = script then set input to ¬ Finder's selection as alias list init() clearClipboard() addToClipboard(input) end run to init() set pb to NSPasteboard's generalPasteboard() end init to clearClipboard() if pb = missing value then init() pb's clearContents() end clearClipboard to addToClipboard(fs) local fs set fURLs to NSMutableArray's array() set fPaths to NSMutableArray's array() set FileManager to NSFileManager's defaultManager() repeat with f in fs -- Get standardized POSIX path directly from the alias set fPOSIX to POSIX path of f set fp to (NSString's stringWithString:fPOSIX)'s stringByStandardizingPath() if (FileManager's fileExistsAtPath:fp) then -- Add URL for modern apps (fURLs's addObject:(NSURL's fileURLWithPath:fp)) -- Add POSIX path string for legacy/third-party apps (fPaths's addObject:fp) end if end repeat if pb = missing value then init() -- Explicitly declare supported pasteboard types pb's clearContents() pb's declareTypes:[current application's NSFilenamesPboardType, current application's NSPasteboardTypeFileURL] owner:(missing value) -- Write both data types to match Finder's behavior pb's setPropertyList:fPaths forType:(current application's NSFilenamesPboardType) pb's writeObjects:fURLs end addToClipboard
Key Changes Explained
- Added
fPathsarray: Stores standardized POSIX paths as strings to support the legacyNSFilenamesPboardType - Explicit type declaration: Tells the pasteboard exactly what data types we’re providing, which helps apps recognize the content immediately
- Dual data writing: We first add the string paths (for older apps) then the URL objects (for modern ones)—this mirrors how Finder populates the pasteboard
- Simplified path handling: Removed the
do shell script "realpath"call sincePOSIX path of aliascombined withstringByStandardizingPath()is more reliable in AppleScript
Swift Equivalent
If you prefer a Swift solution, the logic is identical—you just need to populate both data types on NSPasteboard:
import AppKit func copyFilesToPasteboard(urls: [URL]) { let pasteboard = NSPasteboard.general pasteboard.clearContents() // Convert URLs to POSIX path strings for legacy support let filePaths = urls.map { $0.path } // Declare all supported pasteboard types let supportedTypes: [NSPasteboard.PasteboardType] = [.fileURL, NSFilenamesPboardType] guard pasteboard.declareTypes(supportedTypes, owner: nil) else { return } // Write both data types to the pasteboard pasteboard.setPropertyList(filePaths, forType: NSFilenamesPboardType) pasteboard.writeObjects(urls as [NSPasteboardWriting]) } // Example usage: // let targetFiles = [URL(fileURLWithPath: "/Users/you/Documents/File1.txt"), URL(fileURLWithPath: "/Users/you/Documents/File2.jpg")] // copyFilesToPasteboard(urls: targetFiles)
This Swift code will behave exactly like Finder’s copy operation, ensuring third-party apps recognize and accept the pasted files without issues.
内容的提问来源于stack exchange,提问作者Zheng Xiaodong

