如何实现从QuickLook直接将编辑后的PDF保存至应用?
实现QuickLook风格文件编辑与本地保存方案(无第三方库)
核心思路
系统自带的QLPreviewController本身不直接提供编辑后的保存回调,但可以通过代理监听 dismissal 事件,结合NSFileCoordinator安全获取编辑后的文件内容,再同步到自己应用的沙盒目录。以下是具体实现步骤:
1. 配置QLPreviewController并监听编辑完成事件
初始化QLPreviewController,设置数据源和代理,重点实现previewControllerDidDismiss:方法——用户点击Done按钮后会触发这个回调,此时可检查当前预览文件是否有编辑变化:
class PreviewViewController: QLPreviewController, QLPreviewControllerDataSource, QLPreviewControllerDelegate { var targetFileURL: URL? override func viewDidLoad() { super.viewDidLoad() dataSource = self delegate = self } func numberOfPreviewItems(in controller: QLPreviewController) -> Int { return targetFileURL != nil ? 1 : 0 } func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { return targetFileURL! as QLPreviewItem } func previewControllerDidDismiss(_ controller: QLPreviewController) { guard let fileURL = targetFileURL else { return } saveEditedFileToAppSandbox(fileURL: fileURL) } }
2. 用NSFileCoordinator安全读取编辑后的文件
编辑的文件可能来自外部存储(比如Files应用、iCloud),直接访问URL会有权限问题,必须用NSFileCoordinator协调读写操作,将文件复制到应用的Documents目录:
private func saveEditedFileToAppSandbox(fileURL: URL) { let fileCoordinator = NSFileCoordinator(filePresenter: nil) fileCoordinator.coordinateReadingItem(at: fileURL, options: .withoutChanges, error: nil) { readURL in guard let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return } let destURL = documentsDir.appendingPathComponent(fileURL.lastPathComponent) do { if FileManager.default.fileExists(atPath: destURL.path) { try FileManager.default.removeItem(at: destURL) } try FileManager.default.copyItem(at: readURL, to: destURL) print("文件已保存到本地:\(destURL)") } catch { print("保存失败:\(error.localizedDescription)") } } }
3. 持久化外部文件访问权限
如果编辑的是外部文件(比如通过UIDocumentPickerViewController选择的文件),需要保存URL的bookmark数据,确保下次启动应用仍能访问:
// 选择文件时保存bookmark func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { guard let fileURL = urls.first else { return } do { let bookmarkData = try fileURL.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil) UserDefaults.standard.set(bookmarkData, forKey: "LastEditedFileBookmark") } catch { print("保存bookmark失败:\(error.localizedDescription)") } let previewVC = PreviewViewController() previewVC.targetFileURL = fileURL present(previewVC, animated: true) } // 恢复URL func restoreLastEditedFileURL() -> URL? { guard let bookmarkData = UserDefaults.standard.data(forKey: "LastEditedFileBookmark") else { return nil } var isStale = false do { let url = try URL(resolvingBookmarkData: bookmarkData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale) if isStale { let newBookmarkData = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil) UserDefaults.standard.set(newBookmarkData, forKey: "LastEditedFileBookmark") } return url } catch { print("恢复URL失败:\(error.localizedDescription)") return nil } }
4. 配置Info.plist支持文件类型
确保应用能识别并编辑目标文件类型,在Info.plist中添加UTImportedTypeDeclarations,比如支持PDF编辑:
<key>UTImportedTypeDeclarations</key> <array> <dict> <key>UTTypeIdentifier</key> <string>com.adobe.pdf</string> <key>UTTypeDescription</key> <string>PDF Document</string> <key>UTTypeConformsTo</key> <array> <string>public.data</string> <string>public.item</string> </array> <key>UTTypeTagSpecification</key> <dict> <key>public.filename-extension</key> <array> <string>pdf</string> </array> </dict> </dict> </array>
内容的提问来源于stack exchange,提问作者t12
相关产品推荐
相关产品推荐

