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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 21:25:24