Реалізація генерації PDF у мобільному додатку
Генерація PDF на мобільних потрібна в конкретних сценаріях: вигрузити счёт або акт в фінансовому додатку, зберегти звіт в фітнес-трекері, експортувати заявку в CRM. Підхід залежить від складності документу: простий текст + таблиця вирішується за день, складна верстка з зображеннями та нестандартними шрифтами потребує більше часу.
iOS: PDFKit та UIGraphicsPDFRenderer
На iOS два основних підходи.
UIGraphicsPDFRenderer — малюємо PDF як Canvas. Повний контроль над розташуванням, але кожен елемент потрібно розташовувати вручну:
func generateInvoicePDF(invoice: Invoice) -> Data {
let pageRect = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4 у pt
let renderer = UIGraphicsPDFRenderer(bounds: pageRect)
return renderer.pdfData { context in
context.beginPage()
let ctx = context.cgContext
// Заголовок
let titleAttrs: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: 18, weight: .bold),
.foregroundColor: UIColor.black
]
"СЧЁТ №\(invoice.number)".draw(at: CGPoint(x: 40, y: 40), withAttributes: titleAttrs)
// Таблиця позицій
drawInvoiceTable(invoice.items, in: ctx, startY: 120, pageWidth: 595.2)
// Якщо контент не умещается — beginPage() для наступної сторінки
}
}
Рендеринг HTML → PDF. Складну верстку (таблиці, колонки, зображення) простіше описати HTML/CSS та конвертувати через WKWebView:
class HTMLToPDFConverter: NSObject, WKNavigationDelegate {
private var webView: WKWebView!
func convert(html: String, completion: @escaping (Data?) -> Void) {
webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 595, height: 842))
webView.navigationDelegate = self
webView.loadHTMLString(html, baseURL: nil)
self.completion = completion
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let config = WKPDFConfiguration()
config.rect = CGRect(origin: .zero, size: CGSize(width: 595, height: 842))
webView.createPDF(configuration: config) { result in
self.completion?(try? result.get())
}
}
}
WKWebView.createPDF (iOS 14+) — найпростіший спосіб для складної верстки. CSS @page правила керують розривами сторінок (page-break-before: always), шрифтами, відступами.
PDFKit — для маніпуляцій з існуючими PDF: додати сторінку, вставити аннотацію, слити кілька документів в один. PDFDocument, PDFPage, PDFAnnotation — простий API.
Android: PdfDocument та WebView
android.graphics.pdf.PdfDocument — нативна генерація через Canvas API, аналогічно UIGraphicsPDFRenderer:
fun generatePdf(invoice: Invoice): ByteArray {
val document = PdfDocument()
val pageInfo = PdfDocument.PageInfo.Builder(595, 842, 1).create() // A4
val page = document.startPage(pageInfo)
val canvas = page.canvas
val paint = Paint().apply {
textSize = 18f
isFakeBoldText = true
}
canvas.drawText("СЧЁТ №${invoice.number}", 40f, 60f, paint)
drawInvoiceTable(canvas, invoice.items, startY = 120f)
document.finishPage(page)
val output = ByteArrayOutputStream()
document.writeTo(output)
document.close()
return output.toByteArray()
}
WebView → PDF. WebView.createPrintDocumentAdapter + PrintManager — стандартний шлях на Android. Але це відкриває діалог друку, а не повертає ByteArray. Для програмної генерації — WebView + PrintDocumentAdapter з кастомним PrintManager через reflection чи бібліотеки.
Альтернатива — iText 7 (AGPL, платна для комерційного використання) чи Apache PDFBox (Apache 2.0). PdfBox на Android — порт з деякими обмеженнями, але для більшості задач достатній. OpenPDF (форк iText 2.x, LGPL) — хороший баланс функціональності та ліцензії.
Кирилиця та шрифти
Стандартні системні шрифти у PDF можуть не включатися коректно при відкриванні на іншому пристрої. Правильний підхід — embed шрифт у PDF. На iOS: UIFont(name:size:) з bundled TTF-файлом. На Android з iText/OpenPDF: PdfFont.createFont("assets/fonts/Roboto-Regular.ttf", PdfEncodings.IDENTITY_H, true) — true означає embed у документ.
Без embed кирилиця часто відображається як квадратики на пристроях без російських шрифтів.
Поділитися та зберегти
Після генерації — UIActivityViewController (iOS) чи FileProvider + ACTION_SEND Intent (Android). Для збереження у Files/Downloads: UIDocumentPickerViewController (iOS) чи MediaStore.Downloads URI (Android 10+).
Перегляд без зовнішнього додатку: PDFView з PDFKit (iOS), PdfRenderer (Android) — постраничний рендеринг з файлу у Bitmap.
Графіки
2–3 робочих дні для стандартних документів (счёт, акт, звіт). Складна верстка з зображеннями, таблицями та багатостарічним потоком — до 5 днів. Вартість розраховується індивідуально.







