【问题标题】:Share issue when using PDFKit to create a PDF document使用 PDFKit 创建 PDF 文档时的共享问题
【发布时间】:2019-12-31 01:00:46
【问题描述】:

我正在使用 PDFKit 创建一个 PDF 文件。

PDF 文档已正确创建,因为如果我尝试使用 PDFView 查看它,我会看到它(@IBAction func DetailButton) 可能不是……我没看到广场!

问题是我无法与 UIActivityViewController 共享它。 (@IBAction func Sh​​areButton)

我共享一个文本文件,它是文件路径。 /var/mobile/Containers/Data/Application/....../Documents/1234.pdf

另外,我如何在分享到“邮件”时发送默认电子邮件地址,在分享到“消息”时发送电话号码?

func createPDFwithPDFKit(filePath:String, share:Bool) {

    let pdfTitle = "Swift-Generated PDF"
    let pdfMetadata = [
        // The name of the application creating the PDF.
        kCGPDFContextCreator: "XXX",
        // The name of the PDF's author.
        kCGPDFContextAuthor: "xxx",
        // The title of the PDF.
        kCGPDFContextTitle: game!.name,
        // Encrypts the document with the value as the owner password. Used to enable/disable different permissions.
        kCGPDFContextOwnerPassword: "myPassword123"
    ]

    // Creates a new PDF file at the specified path.
    UIGraphicsBeginPDFContextToFile(filePath, CGRect.zero, pdfMetadata)

    // Creates a new page in the current PDF context.
    UIGraphicsBeginPDFPage()

    // Default size of the page is 612x72.
    let pageSize = UIGraphicsGetPDFContextBounds().size
    let font = UIFont.preferredFont(forTextStyle: .largeTitle)

    // Let's draw the title of the PDF on top of the page.
    let attributedPDFTitle = NSAttributedString(string: pdfTitle, attributes: [NSAttributedString.Key.font: font])
    let stringSize = attributedPDFTitle.size()
    let stringRect = CGRect(x: (pageSize.width / 2 - stringSize.width / 2), y: 20, width: stringSize.width, height: stringSize.height)
    attributedPDFTitle.draw(in: stringRect)

    // Closes the current PDF context and ends writing to the file.
    UIGraphicsEndPDFContext()

    if share {
        let vc = UIActivityViewController(activityItems: [filePath], applicationActivities: [])
        vc.excludedActivityTypes = [
            UIActivity.ActivityType.assignToContact,
            UIActivity.ActivityType.saveToCameraRoll,
            UIActivity.ActivityType.postToFlickr,
            UIActivity.ActivityType.postToVimeo,
            UIActivity.ActivityType.postToTencentWeibo,
            UIActivity.ActivityType.postToTwitter,
            UIActivity.ActivityType.postToFacebook,
            UIActivity.ActivityType.openInIBooks
        ]
        present(vc, animated: true, completion: nil)
    }
}

@IBAction func ShareButton(_ sender: UIBarButtonItem) {



    alert.addAction(UIAlertAction(title: "Exporter au format PDF", style: .default, handler: { _ in

        let fileName = "1234.pdf"
        let documentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
        let filePath = (documentsDirectory as NSString).appendingPathComponent(fileName) as String

        self.createPDFwithPDFKit(filePath:filePath, share:true)
    }))

    alert.addAction(UIAlertAction.init(title: "Annuler", style: .cancel, handler: nil))

    self.present(alert, animated: true, completion: nil)

}

@IBAction func DetailButton(_ sender: UIBarButtonItem) {
    // Create and add a PDFView to the view hierarchy.

    let documentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    let filePath = (documentsDirectory as NSString).appendingPathComponent("scores de '" + game!.name + "'.pdf") as String

    self.createPDFwithPDFKit(filePath:filePath, share:false)

    //View the PDF
    let pdfView = PDFView(frame: view.bounds)
    pdfView.autoScales = true
    pdfView.displayMode = .singlePageContinuous
    view.addSubview(pdfView)

    // Create a PDFDocument object and set it as PDFView's document to load the document in that view.
    let pdfDocument = PDFDocument(url: URL(fileURLWithPath: filePath))!
    pdfView.document = pdfDocument

}

【问题讨论】:

    标签: swift share uiactivityviewcontroller pdfkit


    【解决方案1】:

    在我自己对 PDFKit 的使用中,我将 PDF 文本创建为 NSMutableAttributedString 的一个实例(就像您所做的那样),然后将其封装在 UISimpleTextPrintFormatter 的一个实例中。此对象处理文档格式,尤其是在需要分页符时。此实例用于初始化 UIPrintPageRenderer 的实例。该对象“知道”页面大小、页面内的可打印区域和打印格式化程序。调用 UIGraphicsBeginPDFContextToData 后,您可以调用这些对象以逐页呈现 PDF。

    显然这里发生了很多事情,所以我写了一个简单的应用程序来测试它。该场景有两个控件,一个系统样式的“共享”按钮(在导航栏中)和一个覆盖整个安全区域并声明为“PDFView”类型的 UIView 实例。 PDF 仅包含文本:“这是 PDF 文件中的文本。”。以下视图控制器逻辑提供了如何显示 PDF(在 viewDidLoad 方法中)以及如何完成共享(在 activityButton 操作中)的示例:

    import UIKit
    import PDFKit
    
    class PDFViewController: UIViewController {
    
        // MARK: iVars
        private var reportBuffer = NSMutableData()
    
        // MARK: outlets and actions
        @IBOutlet weak var pdfReportView: PDFView!
    
        @IBAction func activityButton(_ sender: Any)
        {
            let activityViewController =
                getActivityViewController()
            self.present( activityViewController,
                          animated: true,
                          completion: nil )
        }
    
        // MARK: - Action convenience functions
        private func getActivityViewController() -> UIActivityViewController
        {
            let manager = FileManager.default
            let path = pdfURL.path
            if manager.fileExists(atPath: path ) {
                do {
                    try manager.removeItem(at: pdfURL )
                } catch {
                    fatalError()
                }
            }
            do {
                try reportBuffer.write(to: pdfURL, options: [.atomic])
            } catch {
                fatalError()
            }
    
            let activityVC =
                UIActivityViewController( activityItems: [ pdfURL ],
                                          applicationActivities: nil)
            activityVC.completionWithItemsHandler =
                {
                    [weak self] activity, wasCompleted, returnedItems, error in
                    if manager.fileExists(atPath: path ) {
                        do {
                            try manager.removeItem(at: self!.pdfURL )
                        } catch {
                            fatalError()
                        }
                    }
                }
            activityVC.popoverPresentationController?.sourceView =
                self.pdfReportView
            activityVC.modalPresentationStyle = .popover
            return activityVC
        }
    
        // MARK: lifecycle
        override func viewDidAppear(_ animated: Bool)
        {
            super.viewDidAppear( animated )
    
            // create PDF content
            let report =
                NSMutableAttributedString(string: "This is text in a PDF file." )
    
            // create renderer
            let renderer = UIPrintPageRenderer()
            renderer.setValue( NSValue( cgRect: paperRect ),
                               forKey: "paperRect" )
            renderer.setValue( NSValue( cgRect: printableRect ),
                               forKey: "printableRect" )
            let printFormatter =
                UISimpleTextPrintFormatter( attributedText: report )
            renderer.addPrintFormatter(printFormatter,
                                       startingAtPageAt: 0)
    
            // draw the PDF into an NSMutableData buffer
            UIGraphicsBeginPDFContextToData( reportBuffer,
                                             paperRect,
                                             nil )
            let pageRange = NSMakeRange( 0, renderer.numberOfPages )
            renderer.prepare( forDrawingPages: pageRange )
            let bounds = UIGraphicsGetPDFContextBounds()
            for i in 0 ..< renderer.numberOfPages {
                UIGraphicsBeginPDFPage()
                renderer.drawPage( at: i, in: bounds )
            }
            UIGraphicsEndPDFContext()
    
            // display the PDF
            if let document =
                PDFDocument( data: reportBuffer as Data )
            {
                pdfReportView.document = document
            }
        }
    
        // MARK: - constants
    
        private struct Page
        {
            static let size =
                CGSize( width: 612.0, height: 792.0 )
            static let margins =
                UIEdgeInsets(top: 72.0,
                             left: 72.0,
                             bottom: 72.0,
                             right: 72.0)
        }
        private let printableRect =
            CGRect(x: Page.margins.left,
                   y: Page.margins.top,
                   width: Page.size.width
                    - Page.margins.left
                    - Page.margins.right,
                   height: Page.size.height
                    - Page.margins.top
                    - Page.margins.bottom)
    
        private let paperRect =
            CGRect( x: 0.0,
                    y: 0.0,
                    width: Page.size.width,
                    height: Page.size.height )
    
        private var pdfURL: URL {
            let manager = FileManager.default
            let url = manager.urls(for: .cachesDirectory,
                                   in: .userDomainMask).first!
            return url.appendingPathComponent("temporary.pdf") as URL
        }
    }
    

    旁注:我对您的代码逻辑感到有些困惑。您使用“ShareButton”来呈现警报,而警报又具有用于调用 UIActivityViewController 实例的按钮。您的业​​务需求可能决定了这种方法,但一般用户会发现这出乎意料地复杂。点击共享按钮(系统图标是一个带有向上突出箭头的正方形)通常会直接调用 UIActivityViewController 的一个实例。也就是说,没有干预警报。

    编辑:我只能让邮件和消息共享在真实设备上工作。没有一款模拟器设备在 UIActivityViewController 弹出框上提供 Mail 或 Message 选项(尽管 Message 是可用的,至少在 iPad Air 模拟器上是这样)。

    【讨论】:

    • 非常感谢,效果很好。 PS:我使用“分享按钮”向用户“分享.csv”和“分享pdf”提出警告。 pdf应该更详细的图表;不仅仅是文字。
    • 有趣!我认为 UISimpleTextPrintFormatter 不会处理图形。如果您有一个同时包含图形和文本的 UIView 实例,那么 UIViewPrintFormatter 可能是一个合适的替代品。
    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 1970-01-01
    • 2013-03-15
    • 1970-01-01
    • 2023-01-30
    • 2019-03-07
    相关资源
    最近更新 更多