Реалізація генерації звітів у мобільному приложенні
Експорт звіту в мобільному приложенні — завдання, де користувач чекає кнопку «Скачати PDF», а розробник стикається з обмеженнями пам'яті на пристрої, асинхронною генерацією, складною версткою багатосторінкового документу та шерингом у потрібний формат.
PDF-генерація: три підходи
1. Нативний рендеринг через Canvas (iOS: PDFKit, Android: PdfDocument)
На iOS — UIGraphicsPDFRenderer, найконтрольованіший варіант. Рисуємо кожен елемент вручну через Core Graphics:
func generateReport(data: ReportData) -> Data {
let pageRect = CGRect(x: 0, y: 0, width: 595, height: 842) // A4 у points
let renderer = UIGraphicsPDFRenderer(bounds: pageRect)
return renderer.pdfData { context in
context.beginPage()
let ctx = context.cgContext
// Заголовок
let titleFont = UIFont.boldSystemFont(ofSize: 18)
let title = data.title as NSString
title.draw(at: CGPoint(x: 40, y: 40), withAttributes: [
.font: titleFont,
.foregroundColor: UIColor.black
])
// Таблиця даних
drawTable(ctx, rows: data.rows, startY: 80, pageWidth: pageRect.width)
// Якщо дані не поміщаються — нова сторінка
if needsNewPage {
context.beginPage()
// продовжуємо...
}
}
}
Трудомісткий, але результат — точний контроль над пиксельним виводом. Добре для фіксованого шаблону звіту.
На Android через PdfDocument:
val document = PdfDocument()
val pageInfo = PdfDocument.PageInfo.Builder(595, 842, 1).create()
val page = document.startPage(pageInfo)
val canvas = page.canvas
val paint = Paint().apply { textSize = 18f; isFakeBoldText = true }
canvas.drawText(data.title, 40f, 60f, paint)
document.finishPage(page)
val stream = ByteArrayOutputStream()
document.writeTo(stream)
document.close()
2. HTML → PDF через WebView (Flutter: printing package)
Генеруємо HTML-шаблон, конвертуємо в PDF. Простіше для складних макетів, таблиць та текстових блоків — HTML/CSS гнучкіше Canvas. На Flutter printing + pdf package:
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
Future<Uint8List> buildPdf(ReportData data) async {
final doc = pw.Document();
final font = await PdfGoogleFonts.notoSansRegular();
final boldFont = await PdfGoogleFonts.notoSansBold();
doc.addPage(
pw.MultiPage(
pageFormat: PdfPageFormat.a4,
build: (context) => [
pw.Header(text: data.title, textStyle: pw.TextStyle(font: boldFont, fontSize: 18)),
pw.SizedBox(height: 16),
pw.TableHelper.fromTextArray(
headers: data.headers,
data: data.rows,
cellStyle: pw.TextStyle(font: font, fontSize: 10),
),
],
),
);
return doc.save();
}
pw.MultiPage автоматично розбиває на сторінки — вирішує головну проблему довгих звітів.
3. Серверна генерація (рекомендовано для складних звітів)
Звіти з великим обсягом даних, складними діаграмами або корпоративним брендингом краще генерувати на сервері. Puppeteer (Node.js) рендерить HTML + Charts у PDF з точністю браузерного рушія. Клієнт отримує посилання або файл по WebSocket після завершення.
Це єдиний правильний шлях якщо в звіт треба включити інтерактивні графіки (Echarts, Highcharts) — на пристрої їх не отримаєш без WebView.
CSV-експорт
Простіше, ніж PDF, але є нюанси з кодуванням. Excel очікує UTF-8 з BOM — інакше кирилиця відображається мусором. На Flutter:
String buildCsv(List<List<dynamic>> rows) {
final buffer = StringBuffer();
buffer.write('\uFEFF'); // UTF-8 BOM для коректного відкриття в Excel
for (final row in rows) {
buffer.writeln(row.map((cell) {
final str = cell.toString();
// Екранюємо клітинки з комами та лапками
return str.contains(',') || str.contains('"')
? '"${str.replaceAll('"', '""')}"'
: str;
}).join(','));
}
return buffer.toString();
}
Шеринг сгенерованого файлу
share_plus на Flutter, UIActivityViewController на iOS, FileProvider + Intent.ACTION_SEND на Android. Збереження в галерею / Файли — через path_provider + open_filex.
На iOS потрібен NSPhotoLibraryAddUsageDescription в Info.plist для збереження в Photos, UIFileSharingEnabled для доступу до файлів через Files.app.
Типічні проблеми
Генерація PDF з таблицею з 10 000 рядків на пристрої — OutOfMemoryError на Android або memory warning на iOS. Рішення: пагінація даних, генерація постранично, для великих обсягів — сервер.
Кирилиця в PDF без вбудованого шрифту — білі прямокутники замість букв. Обов'язково вбудовувати кастомний font з підтримкою Unicode через pw.Font.ttf(...).
Що входить у роботу
- Вибір підходу під специфіку даних та макет (нативний / HTML→PDF / сервер)
- Реалізація шаблонів звітів (PDF/CSV/Excel)
- Інтеграція шерингу та збереження файлів
- Обробка edge cases: порожні дані, великі обсяги, переноси сторінок
Строки
Один шаблон PDF-звіту з базовим форматуванням: 2–3 дні. Кілька типів звітів з діаграмами та серверною генерацією: 1–2 тижні. Вартість розраховується індивідуально.







