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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 10:06:24