使用 PDFKit 在 Swift (iOS/macOS) 中生成 PDF 报告
创建 PDF 文档是移动和桌面应用程序中的常见任务之一。在 Apple 平台(iOS、macOS、watchOS、tvOS)上,使用内置框架 PDFKit 来实现。它允许以编程方式生成、显示和编辑 PDF 文件。在本文中,我们将介绍如何使用 Swift 创建完整的 PDF 报告:包含文本、表格、图像和可自定义的页面。
什么是 PDFKit?
PDFKit 是 Apple 的一个框架,包含在标准 iOS/macOS SDK 中。它提供了用于处理 PDF 的类:
PDFDocument— 整个文档的表示。PDFPage— 单个页面。PDFView— 在屏幕上显示 PDF。UIPrintPageRenderer(用于 iOS)— 通过 Core Graphics 绘制生成页面。
生成报告时,最常使用 UIPrintPageRenderer 或直接在 PDF 上下文中通过 Core Graphics 绘制。第二种方法提供了更大的灵活性,但需要更多代码。
项目准备
打开 Xcode,为 iOS 或 macOS 创建一个新项目。确保已导入 PDFKit 模块:
import PDFKitimport UIKit // 用于 iOS对于 macOS,需要 import Cocoa 以及相应的 NSView 操作。
方法 1:通过 UIPrintPageRenderer 生成 PDF(iOS)
如果您想使用 HTML 标记或复杂布局,这种方法很方便。UIPrintPageRenderer 允许通过 UIPrintFormatter 渲染页面。
func generatePDFUsingRenderer() -> Data? { let renderer = UIPrintPageRenderer() // 设置 A4 页面大小 let pageSize = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // 以点为单位 renderer.setValue(pageSize, forKey: "paperRect") renderer.setValue(pageSize, forKey: "printableRect") // 创建包含报告的 HTML 字符串 let htmlString = """ <h1>销售报告</h1> <p>日期:2025-03-17</p> <table border="1"> <tr><th>商品</th><th>数量</th><th>价格</th></tr> <tr><td>笔记本电脑</td><td>5</td><td>50000</td></tr> <tr><td>鼠标</td><td>20</td><td>1500</td></tr> </table> """ let formatter = UIMarkupTextPrintFormatter(markupText: htmlString) renderer.addPrintFormatter(formatter, startingAtPageAt: 0) // 渲染为 PDF let pdfData = NSMutableData() UIGraphicsBeginPDFContextToData(pdfData, .zero, nil) for pageIndex in 0..<renderer.numberOfPages { UIGraphicsBeginPDFPage() renderer.drawPage(at: pageIndex, in: UIGraphicsGetCurrentContext()!) } UIGraphicsEndPDFContext() return pdfData as Data}调用函数并保存结果:
if let pdfData = generatePDFUsingRenderer() { let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let fileURL = paths[0].appendingPathComponent("report.pdf") try? pdfData.write(to: fileURL) print("PDF 已保存:\\(fileURL)")}方法 2:通过 Core Graphics 绘制(iOS/macOS)
这种方法更底层,但可以完全控制每个元素。适用于 macOS,因为 UIPrintPageRenderer 不可用。
func generatePDFWithCoreGraphics() -> Data? { let pdfData = NSMutableData() let pageRect = CGRect(x: 0, y: 0, width: 612, height: 792) // US Letter guard let consumer = CGDataConsumer(data: pdfData), let pdfContext = CGContext(consumer: consu