SwiftUI中如何用.onDrop处理UTType.data并获取Outlook附件文件名
解决SwiftUI中Outlook附件拖放的问题
核心思路
Outlook拖放附件时,并非只能用UTType.data处理,优先用NSFilePromiseProvider或public.file-url能更可靠地获取文件名和完整文件数据,这两种方式是系统推荐的文件拖放处理方式。
实现步骤
1. 优先处理NSFilePromiseProvider(最可靠)
Outlook拖放附件时,拖放提供者通常会是NSFilePromiseProvider类型,直接用它可以获取原始文件名并完成文件保存:
providers.forEach { provider in if let filePromise = provider as? NSFilePromiseProvider { // 获取附件原始文件名 let originalFileName = filePromise.fileName let saveURL = container.volumeInfo.volumePath.appendingPathComponent(originalFileName) filePromise.receivePromisedFiles(atDestination: saveURL, options: nil, operationQueue: .main) { error in if let error = error { print("附件保存失败:\(error.localizedDescription)") return } // 调用你已有的文件处理逻辑 self.fileDropped(container: container, url: saveURL) } return } }
2. Fallback:通过public.file-url获取临时文件URL
如果NSFilePromiseProvider不存在,尝试加载public.file-url类型的表示,Outlook可能会把附件的临时文件URL包装在这个类型里:
providers.forEach { provider in guard provider.hasItemConformingToTypeIdentifier(UTType.fileURL.identifier) else { return } provider.loadDataRepresentation(forTypeIdentifier: UTType.fileURL.identifier) { data, error in guard let data = data, let urlString = String(data: data, encoding: .utf8), let tempURL = URL(string: urlString) else { print("无法获取文件URL:\(error?.localizedDescription ?? "未知错误")") return } let fileName = tempURL.lastPathComponent let targetURL = container.volumeInfo.volumePath.appendingPathComponent(fileName) do { // 复制临时文件到目标路径 try FileManager.default.copyItem(at: tempURL, to: targetURL) self.fileDropped(container: container, url: targetURL) } catch { print("复制文件失败:\(error.localizedDescription)") } } return }
3. 兜底处理UTType.data类型
如果上面两种方式都失效,再处理UTType.data,同时要先获取拖放项的文件名元数据:
providers.forEach { provider in guard provider.hasItemConformingToTypeIdentifier(UTType.data.identifier) else { return } // 先获取文件名属性 provider.loadItem(forTypeIdentifier: kUTTypeFileAttributes as String, options: nil) { attrs, error in guard let attributes = attrs as? [String: Any], let fileName = attributes[kUTTypeFileName as String] as? String else { print("无法获取附件文件名") return } // 加载文件数据 provider.loadDataRepresentation(forTypeIdentifier: UTType.data.identifier) { data, error in guard let fileData = data else { print("加载附件数据失败:\(error?.localizedDescription ?? "未知错误")") return } let targetPath = container.volumeInfo.volumePath.appendingPathComponent(fileName).path let isSaved = FileManager.default.createFile(atPath: targetPath, contents: fileData) if isSaved { self.fileDropped(container: container, url: URL(fileURLWithPath: targetPath)) } else { print("创建文件失败") } } } }
注意事项
- 拖放处理的顺序很重要:先尝试最可靠的
NSFilePromiseProvider,再到public.file-url,最后才是UTType.data。 - 确保你的SwiftUI视图已经正确设置了拖放接收权限,比如在
onDrop修饰符中指定支持的UT类型,包括UTType.fileURL、UTType.data等。
内容的提问来源于stack exchange,提问作者Stephan
相关产品推荐
相关产品推荐

