Working with PDFs in SwiftUI: Best Packages and Implementation
Working with PDFs in SwiftUI can be enhanced using third-party packages. In this guide, we'll explore popular PDF packages and how to implement them in your SwiftUI applications.
1. Adding PDFKit Integration
While PDFKit is built into iOS, we can create a SwiftUI wrapper for better integration:
PDFKitView.swift
import SwiftUI
import PDFKit
struct PDFKitView: UIViewRepresentable {
let pdfDocument: PDFDocument
func makeUIView(context: Context) -> PDFView {
let pdfView = PDFView()
pdfView.document = pdfDocument
pdfView.autoScales = true
return pdfView
}
func updateUIView(_ uiView: PDFView, context: Context) {
uiView.document = pdfDocument
}
}
// Usage Example
struct PDFViewer: View {
let pdfDoc = PDFDocument(url: Bundle.main.url(
forResource: "sample",
withExtension: "pdf"
)!)!
var body: some View {
PDFKitView(pdfDocument: pdfDoc)
}
}
2. Using PSPDFKit
PSPDFKit is a powerful commercial PDF library. First, add the package to your project:
Package.swift
let package = Package(
dependencies: [
.package(
url: "https://github.com/PSPDFKit/PSPDFKit-SP.git",
from: "12.0.0"
)
]
)
Then implement the viewer:
PSPDFKitView.swift
import SwiftUI
import PSPDFKit
struct PSPDFKitView: UIViewControllerRepresentable {
let document: Document
func makeUIViewController(context: Context) -> PDFViewController {
let pdfController = PDFViewController(document: document)
pdfController.pageMode = .single
return pdfController
}
func updateUIViewController(
_ uiViewController: PDFViewController,
context: Context
) {
// Update if needed
}
}
3. Using PDFGenerator
For PDF generation, we can use the PDFGenerator package. Add it to your project:
Package.swift
.package(
url: "https://github.com/sgr-ksmt/PDFGenerator.git",
from: "3.0.0"
)
Implementation example:
PDFGenerator.swift
import SwiftUI
import PDFGenerator
class PDFCreator {
static func generatePDF(from view: some View) -> URL? {
// Create a hosting controller for the SwiftUI view
let hostingController = UIHostingController(rootView: view)
hostingController.view.frame = CGRect(x: 0, y: 0, width: 595, height: 842) // A4 size
// Generate PDF
let pdfData = try? PDFGenerator.generate(hostingController.view)
// Save to temporary file
let tempURL = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension("pdf")
try? pdfData?.write(to: tempURL)
return tempURL
}
}
// Usage Example
struct PDFContent: View {
var body: some View {
VStack(spacing: 20) {
Text("PDF Content")
.font(.largeTitle)
Image("sample-image")
.resizable()
.scaledToFit()
.frame(height: 200)
Text("Description text here...")
.padding()
}
}
}
struct ContentView: View {
var body: some View {
Button("Generate PDF") {
if let pdfURL = PDFCreator.generatePDF(from: PDFContent()) {
// Share or display the PDF
let activityVC = UIActivityViewController(
activityItems: [pdfURL],
applicationActivities: nil
)
// Present the share sheet
UIApplication.shared.windows.first?.rootViewController?
.present(activityVC, animated: true)
}
}
}
}
4. Handling PDF Forms
For interactive PDF forms, we can create a custom implementation:
PDFFormHandler.swift
import PDFKit
class PDFFormHandler {
let pdfDocument: PDFDocument
init(pdfDocument: PDFDocument) {
self.pdfDocument = pdfDocument
}
func fillForm(with data: [String: String]) {
for i in 0..<self.pdfDocument.pageCount {
guard let page = self.pdfDocument.page(at: i) else { continue }
for annotation in page.annotations {
guard let field = annotation as? PDFAnnotation,
let fieldName = field.fieldName,
let value = data[fieldName] else { continue }
field.widgetStringValue = value
}
}
}
func saveForm() -> Data? {
return self.pdfDocument.dataRepresentation()
}
}
Best Practices
- Always handle PDF loading errors gracefully
- Consider memory usage when dealing with large PDFs
- Implement proper caching for frequently accessed PDFs
- Use appropriate compression for generated PDFs
- Consider accessibility features for PDF viewing
Common Issues and Solutions
- Memory issues with large PDFs: Implement page loading on demand
- PDF rendering performance: Use appropriate zoom levels and caching
- Form field handling: Properly validate input before saving
- PDF generation errors: Implement proper error handling and logging
These implementations provide a solid foundation for working with PDFs in your SwiftUI applications. Choose the approach that best fits your specific requirements and performance needs.