Реализация генерации 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 рабочих дня для стандартных документов (счёт, акт, отчёт). Сложная вёрстка с изображениями, таблицами и многостраничным flow — до 5 дней. Стоимость рассчитывается индивидуально.







