Swift中使用UIPrintInteractionController从文件选择器打印PDF空白问题
解决UIDocumentPicker选择PDF后打印空白的问题
使用UIDocumentPickerViewController选择PDF文件,通过UIPrintInteractionController执行打印操作时,打印界面可正常弹出,但预览和实际打印结果均为空白页面。
用户原代码
文档选择器代码
struct DocumentPicker: UIViewControllerRepresentable { @Binding var filePath: URL? func makeCoordinator() -> DocumentPicker.Coordinator { return DocumentPicker.Coordinator(parent1: self) } func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPicker>) -> UIDocumentPickerViewController { let picker = UIDocumentPickerViewController(documentTypes: [String(kUTTypePDF)], in: .open) picker.allowsMultipleSelection = false picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: DocumentPicker.UIViewControllerType, context: UIViewControllerRepresentableContext<DocumentPicker>) { } class Coordinator: NSObject, UIDocumentPickerDelegate { var parent: DocumentPicker init(parent1: DocumentPicker){ parent = parent1 } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { Print(fPath: urls.first!) } } }
打印功能代码
func Print(fPath: URL){ let printInfo = UIPrintInfo(dictionary: nil) printInfo.jobName = fPath.lastPathComponent printInfo.outputType = .general let printController = UIPrintInteractionController.shared printController.printInfo = printInfo printController.showsNumberOfCopies = false printController.printingItem = fPath print(fPath.absoluteString) printController.present(animated: true, completionHandler: nil) }
问题原因
UIDocumentPicker返回的URL是安全范围URL(security-scoped URL),系统对这类URL的访问有严格限制,直接将其赋值给printingItem无法让UIPrintInteractionController获取到文件内容,因此出现空白预览。
解决方案
需要先获取安全范围URL的访问权限,再读取PDF文件的Data内容,将Data作为打印项传入打印控制器。
修改后的完整代码
文档选择器(修改Coordinator回调)
struct DocumentPicker: UIViewControllerRepresentable { @Binding var filePath: URL? func makeCoordinator() -> DocumentPicker.Coordinator { return DocumentPicker.Coordinator(parent1: self) } func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPicker>) -> UIDocumentPickerViewController { let picker = UIDocumentPickerViewController(documentTypes: [String(kUTTypePDF)], in: .open) picker.allowsMultipleSelection = false picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: DocumentPicker.UIViewControllerType, context: UIViewControllerRepresentableContext<DocumentPicker>) { } class Coordinator: NSObject, UIDocumentPickerDelegate { var parent: DocumentPicker init(parent1: DocumentPicker){ parent = parent1 } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { guard let fileURL = urls.first else { return } // 获取安全范围访问权限 guard fileURL.startAccessingSecurityScopedResource() else { print("无法获取文件访问权限") return } // 执行打印 printPDF(from: fileURL) // 用完后释放权限 fileURL.stopAccessingSecurityScopedResource() } } }
打印功能(改为读取Data)
func printPDF(from fileURL: URL) { do { let pdfData = try Data(contentsOf: fileURL) let printInfo = UIPrintInfo(dictionary: nil) printInfo.jobName = fileURL.lastPathComponent printInfo.outputType = .general let printController = UIPrintInteractionController.shared printController.printInfo = printInfo printController.showsNumberOfCopies = false // 传入PDF Data作为打印项 printController.printingItem = pdfData printController.present(animated: true) { _, success, error in if let error = error { print("打印出错:\(error.localizedDescription)") } else if success { print("打印成功") } } } catch { print("读取PDF文件失败:\(error.localizedDescription)") } }
注意事项
- 必须成对调用
startAccessingSecurityScopedResource()和stopAccessingSecurityScopedResource(),避免权限泄漏。 - 使用Data作为打印项可以绕开安全范围URL的访问限制,确保系统正确读取PDF内容。
内容的提问来源于stack exchange,提问作者Kuthar
相关产品推荐
相关产品推荐

