如何为macOS FileProvider API添加自定义动作并在代码中调用
macOS FileProvider API 自定义动作实现指南
1. 添加自定义动作到FileProvider
自定义动作需要先在File Provider扩展的Info.plist中声明,系统会根据配置在Finder右键菜单中展示对应选项。
在扩展的Info.plist中添加NSExtensionFileProviderActions数组,每个数组元素为字典形式,定义单个动作的属性:
<key>NSExtensionFileProviderActions</key> <array> <dict> <key>identifier</key> <string>com.yourcompany.archive-action</string> <key>displayName</key> <string>归档到云端</string> <key>imageName</key> <string>archive</string> <!-- 可使用系统图标名或自定义图标资源名 --> <key>supportedItemTypes</key> <array> <string>public.item</string> <!-- 支持所有文件/文件夹 --> </array> </dict> <dict> <key>identifier</key> <string>com.yourcompany.share-with-team</string> <key>displayName</key> <string>分享给团队</string> <key>imageName</key> <string>square.and.arrow.up</string> <key>supportedItemTypes</key> <array> <string>public.image</string> <string>public.text</string> </array> </dict> </array>
2. 定义与自定义动作
每个动作的核心配置项说明:
- identifier:全局唯一标识,建议使用反向域名格式
- displayName:Finder右键菜单中显示的动作名称
- imageName:动作图标,可使用SF Symbols名称(如
square.and.arrow.up)或扩展内的自定义图标资源名 - supportedItemTypes:指定动作支持的文件类型UTI(Uniform Type Identifier),如
public.image、public.folder等
若需动态控制动作可用性(比如根据文件状态、权限),在FileProviderExtension类中重写supportedActions(for item: NSFileProviderItem)方法:
override func supportedActions(for item: NSFileProviderItem) -> [NSFileProviderActionIdentifier] { var actions = super.supportedActions(for: item) // 仅对已下载完成的文件显示归档动作 if item.isDownloaded { actions.append(NSFileProviderActionIdentifier("com.yourcompany.archive-action")) } // 仅对团队文件夹内的文件显示分享动作 if item.parentItemIdentifier == teamFolderIdentifier { actions.append(NSFileProviderActionIdentifier("com.yourcompany.share-with-team")) } return actions }
3. 处理动作执行逻辑
用户在Finder中选择动作后,系统会调用FileProviderExtension的performAction(_:for:itemIdentifiers:completionHandler:)方法,在此实现具体业务逻辑:
override func performAction(_ actionIdentifier: NSFileProviderActionIdentifier, for item: NSFileProviderItem, itemIdentifiers: [NSFileProviderItemIdentifier], completionHandler: @escaping (Error?) -> Void) { switch actionIdentifier.rawValue { case "com.yourcompany.archive-action": // 实现归档逻辑:移动文件到归档目录 let archiveParentIdentifier = NSFileProviderItemIdentifier(domainIdentifier: self.domainIdentifier, rawValue: "archive-folder") let updatedItem = item.copy() as! NSFileProviderItem updatedItem.parentItemIdentifier = archiveParentIdentifier self.modifyItem(updatedItem, baseVersion: item.version) { error in completionHandler(error) } case "com.yourcompany.share-with-team": // 实现分享逻辑:调用团队API发送分享通知 Task { do { try await TeamShareAPI.shareItem(withIdentifier: item.itemIdentifier.rawValue) completionHandler(nil) } catch { completionHandler(error) } } default: // 处理未知动作 completionHandler(NSError(domain: NSFileProviderErrorDomain, code: NSFileProviderError.unsupportedAction.rawValue, userInfo: nil)) } }
4. 在代码中访问与触发动作
获取某个Item支持的动作
let item: NSFileProviderItem = // 获取目标Item guard let extension = NSFileProviderManager.default.providerExtension(for: item.itemIdentifier) else { return } extension.supportedActions(for: item) { actions, error in if let error = error { // 处理错误 return } // 遍历可用动作 for actionId in actions { print("可用动作:\(actionId.rawValue)") } }
主动触发动作执行
let item: NSFileProviderItem = // 获取目标Item let actionId = NSFileProviderActionIdentifier("com.yourcompany.archive-action") NSFileProviderManager.default.performAction(actionId, forItemWithIdentifier: item.itemIdentifier) { error in if let error = error { // 处理执行错误 } else { // 动作执行成功 } }
内容的提问来源于stack exchange,提问作者Sri
相关产品推荐
相关产品推荐

