如何基于SwiftUI创建macOS Droplet应用?能否使用SPM实现?
如何用SwiftUI+SPM创建macOS Droplet应用(实现VLC多实例启动功能)
核心思路
Droplet本质是能响应文件拖放/「打开方式」请求的macOS应用,我们可以通过SwiftUI的App协议结合SPM构建可执行应用包,同时通过NSApplicationDelegate处理启动和文件打开事件,完全替代Cocoa或AppleScript方案。
1. 创建SPM可执行包
首先初始化一个SPM可执行项目:
mkdir VLCLauncherDroplet && cd VLCLauncherDroplet swift package init --type executable
2. 配置Package.swift
修改Package.swift,指定macOS平台、应用bundle配置(必须添加Info.plist键值对来支持文件关联和UI行为):
// swift-tools-version: 5.9 import PackageDescription let package = Package( name: "VLCLauncherDroplet", platforms: [ .macOS(.v13) // 适配SwiftUI 3+特性 ], products: [ .executable( name: "VLCLauncherDroplet", targets: ["VLCLauncherDroplet"] ), ], targets: [ .executableTarget( name: "VLCLauncherDroplet", dependencies: [], // 配置应用Info.plist infoPlist: [ "CFBundleName": "VLCLauncherDroplet", "CFBundleIdentifier": "com.yourdomain.VLCLauncherDroplet", "CFBundleVersion": "1.0", "CFBundleShortVersionString": "1.0", "LSUIElement": false, // 设为false才能在Dock显示,否则后台运行 "NSAppleEventsUsageDescription": "需要启动VLC并打开指定文件", // 配置支持的文件类型(这里设为所有文件,可按需修改UTI) "CFBundleDocumentTypes": [ [ "CFBundleTypeName": "All Files", "CFBundleTypeRole": "Viewer", "LSItemContentTypes": ["public.item"], "LSHandlerRank": "Alternate" ] ] ] ) ] )
3. 编写SwiftUI应用代码
替换Sources/VLCLauncherDroplet/main.swift的内容,通过NSApplicationDelegateAdaptor处理启动和文件打开事件:
import SwiftUI import AppKit // 自定义Delegate处理应用事件 class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { // 对应AppleScript的`run` handler:无文件时启动新VLC实例 let process = Process() process.executableURL = URL(filePath: "/usr/bin/open") process.arguments = ["-n", "/Applications/VLC.app"] try? process.run() process.waitUntilExit() // 启动后退出Droplet(可选,保持后台也可以) NSApplication.shared.terminate(nil) } func application(_ application: NSApplication, open urls: [URL]) { // 对应AppleScript的`open` handler:处理拖入/打开方式的文件 for url in urls { let escapedPath = url.path.replacingOccurrences(of: "'", with: "\\'") let process = Process() process.executableURL = URL(filePath: "/usr/bin/open") process.arguments = ["-na", "/Applications/VLC.app", "'\(escapedPath)'"] try? process.run() process.waitUntilExit() } // 激活VLC并退出Droplet NSWorkspace.shared.launchApplication(at: URL(filePath: "/Applications/VLC.app"), options: .activateAllWindows, configuration: [:]) NSApplication.shared.terminate(nil) } } @main struct VLCLauncherDropletApp: App { // 注入Delegate @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { // SwiftUI需要至少一个Scene,这里用空WindowGroup(不会显示窗口) WindowGroup { EmptyView() .frame(width: 0, height: 0) .hidden() } .windowStyle(.hiddenTitleBar) } }
4. 构建并部署
执行构建命令生成Release版本的应用包:
swift build -c release
构建完成后,将产物从.build/release/VLCLauncherDroplet.app移动到/Applications文件夹。
5. 配置Finder「打开方式」
在Finder中选中任意文件,右键选择「显示简介」→「打开方式」→选择VLCLauncherDroplet,点击「全部更改」即可将该Droplet设为默认打开工具(或按需选择)。
注意事项
- 如果需要限制支持的文件类型,修改
CFBundleDocumentTypes中的LSItemContentTypes(例如public.movie对应视频文件)。 - 若不需要Droplet在Dock显示,可将
LSUIElement设为true,此时应用会后台运行。 - 测试时可直接将文件拖到Dock上的Droplet图标,验证多实例启动功能。
内容的提问来源于stack exchange,提问作者marc-medley
相关产品推荐
相关产品推荐

