Користувачі чекають кнопку «Завантажити PDF», а розробник стикається з обмеженнями пам'яті на пристрої, асинхронною генерацією та складною версткою багатосторінкового документа. Нещодавно до нас звернувся клієнт із задачею генерації звіту на 5 000 рядків — на Android це викликало OutOfMemoryError, довелося терміново переробляти архітектуру на серверну. Наша команда має 5+ років досвіду в реалізації систем генерації звітів для мобільних додатків — ми гарантуємо стабільну роботу навіть з великими обсягами даних. Оцінимо ваш проект і запропонуємо оптимальне за бюджетом рішення.
Без правильного підходу звіти можуть займати забагато пам'яті, видавати помилки при відкритті або відображати порожні прямокутники замість кирилиці. Ми пройшли ці граблі на десятках проектів і знаємо, як уникнути типових проблем. Як Apple рекомендує: Use UIActivityViewController to let users export files.
Як реалізувати генерацію звітів у мобільному додатку
Успішна реалізація вимагає вибору підходу, форматування даних, рендерингу та експорту в потрібний формат. Розглянемо три основні способи генерації PDF.
Три підходи до генерації PDF у мобільному додатку
Нативний рендеринг через Canvas
На 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()
HTML → PDF через WebView
Генеруємо 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 автоматично розбиває на сторінки — вирішує головну проблему довгих звітів.
Серверна генерація (рекомендовано для складних звітів)
Звіти з великим обсягом даних, складними діаграмами або корпоративним брендингом краще генерувати на сервері. Puppeteer (Node.js) рендерить HTML + Charts у PDF з точністю браузерного движка. Клієнт отримує посилання або файл по WebSocket після завершення.
Це єдиний правильний шлях, якщо у звіт потрібно включити інтерактивні графіки (Echarts, Highcharts) — на пристрої їх не відрендериш без WebView.
| Параметр | Нативний Canvas | HTML → PDF WebView | Серверна генерація |
|---|---|---|---|
| Складність реалізації | Висока | Середня | Низька (клієнт) |
| Контроль макету | Повний | Залежить від CSS | Залежить від HTML/CSS |
| Обсяг даних | До 50 сторінок | До 100 сторінок | Необмежений |
| Інтерактивні графіки | Ні | Через WebView | Так (Puppeteer) |
| Пам'ять пристрою | Висока | Середня | Низька |
| Швидкість генерації | Повільна (до 10 сек на 100 стор.) | Середня (до 5 сек) | Швидка (1–2 сек) |
| Вартість інфраструктури | Безкоштовно | Безкоштовно | Від $20/міс |
Серверна генерація в 3–5 разів швидше за нативну на пристроях з 2 ГБ ОЗП, а вартість рішення зменшується на 40% за рахунок відсутності обмежень пам'яті.
Для вибору оптимального рішення зв'яжіться з нами — ми проаналізуємо ваші дані та запропонуємо підхід.
Який формат звіту обрати?
Крім PDF, часто потрібні CSV та Excel. CSV — найлегший: дані пишуться рядками з роздільниками. Головний нюанс — кодування: Excel відкриває CSV в UTF-8 лише з BOM (\uFEFF). Інакше кирилиця перетворюється на кракозябри. Excel (xlsx) складніший: потрібна бібліотека, що підтримує формули, стилі та декілька аркушів. Для простих таблиць достатньо CSV. На практиці, CSV з 10 000 рядків генерується на пристрої за 0.5 секунди, а PDF з такою ж кількістю рядків потребує 5–7 секунд та пагінації.
| Формат | Складність реалізації | Підтримка стилів | Обсяг файлу | Універсальність |
|---|---|---|---|---|
| Висока | Так (фіксований макет) | Середній | Висока (всюди відкривається) | |
| CSV | Низька | Ні | Маленький | Середня (Excel, Numbers) |
| Excel | Середня | Так (формули, кольори) | Великий | Висока (Excel, Google Sheets) |
Що обрати: нативний рендеринг чи HTML в PDF?
Вибір залежить від складності макету та обсягу даних. Для фіксованого шаблону з невеликою кількістю сторінок підійде нативний рендеринг. Для складних таблиць і діаграм — HTML в PDF або сервер. Наш досвід показує, що 80% проектів використовують гібридний підхід: прості звіти на пристрої, складні — на сервері. Ми допоможемо підібрати оптимальне рішення під ключ.
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(...).
Проблеми з Excel: якщо використовувати бібліотеку на кшталт excel (Dart), не забувайте про стилі рядків — інакше файл не відкриється в старих версіях Excel. Рекомендуємо завжди перевіряти на реальних версіях офісних пакетів.
Для Excel-звітів використовуйте бібліотеки: на Flutter — excel (версія 4.x), на Android — Apache POI (через JNI або сервер), на iOS — SwiftExcel або xlsxwriter. Вибір залежить від складності звіту та часу розробки.
Кроки з впровадження генерації звітів
- Аналіз даних та макетів: визначте формат, обсяг і тип звітів.
- Вибір підходу: нативний, HTML→PDF або серверний.
- Розробка шаблонів з версткою та вбудовуванням шрифтів.
- Інтеграція експорту та шерингу.
- Тестування на реальних даних (порожні, великі, з кирилицею).
- Оптимізація пам'яті та продуктивності.
Що входить в роботу
- Вибір підходу під специфіку даних та макет (нативний / HTML→PDF / сервер)
- Реалізація шаблонів звітів (PDF/CSV/Excel)
- Інтеграція шерингу та збереження файлів
- Обробка edge cases: порожні дані, великі обсяги, перенесення сторінок
Строки
Один шаблон PDF-звіту з базовим форматуванням: 2–3 дні (від $300). Декілька типів звітів з діаграмами та серверною генерацією: 1–2 тижні ($800–$1500). Вартість розраховується індивідуально. Отримайте консультацію щодо вашого проекту — реалізуємо систему звітів під ключ. Замовте розробку, і ми запропонуємо оптимальне рішення з урахуванням ваших даних та бюджету.







