Report Generation Implementation in Mobile Apps
Report export in mobile apps is a task where users expect "Download PDF" button, but developers hit memory limits, asynchronous generation, complex multi-page document layout and sharing in needed format.
PDF Generation: Three Approaches
1. Native Rendering via Canvas (iOS: PDFKit, Android: PdfDocument)
On iOS — UIGraphicsPDFRenderer, most controlled variant. Draw each element manually via Core Graphics:
func generateReport(data: ReportData) -> Data {
let pageRect = CGRect(x: 0, y: 0, width: 595, height: 842) // A4 in points
let renderer = UIGraphicsPDFRenderer(bounds: pageRect)
return renderer.pdfData { context in
context.beginPage()
let ctx = context.cgContext
// Title
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
])
// Data table
drawTable(ctx, rows: data.rows, startY: 80, pageWidth: pageRect.width)
// If data doesn't fit — new page
if needsNewPage {
context.beginPage()
// continue...
}
}
}
Labor-intensive but result is precise pixel control. Good for fixed report template.
On Android via 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 via WebView (Flutter: printing package)
Generate HTML template, convert to PDF. Simpler for complex layouts, tables and text blocks — HTML/CSS more flexible than Canvas. On 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 automatically splits to pages — solves long report main problem.
3. Server-Side Generation (Recommended for Complex Reports)
Reports with large data volume, complex diagrams or corporate branding better generated on server. Puppeteer (Node.js) renders HTML + Charts to PDF with browser engine precision. Client gets link or file via WebSocket after completion.
This is the only right path if report must include interactive charts (Echarts, Highcharts) — can't render on device without WebView.
CSV Export
Simpler than PDF, but has encoding nuances. Excel expects UTF-8 with BOM — otherwise Cyrillic shows as garbage. On Flutter:
String buildCsv(List<List<dynamic>> rows) {
final buffer = StringBuffer();
buffer.write('\uFEFF'); // UTF-8 BOM for correct Excel opening
for (final row in rows) {
buffer.writeln(row.map((cell) {
final str = cell.toString();
// Escape cells with commas and quotes
return str.contains(',') || str.contains('"')
? '"${str.replaceAll('"', '""')}"'
: str;
}).join(','));
}
return buffer.toString();
}
Sharing Generated File
share_plus on Flutter, UIActivityViewController on iOS, FileProvider + Intent.ACTION_SEND on Android. Save to gallery / Files — via path_provider + open_filex.
On iOS need NSPhotoLibraryAddUsageDescription in Info.plist for saving to Photos, UIFileSharingEnabled for file access via Files.app.
Typical Problems
Generating PDF with table of 10,000 rows on device — OutOfMemoryError on Android or memory warning on iOS. Solution: data pagination, page-by-page generation, for large volumes — server.
Cyrillic in PDF without embedded font — white rectangles instead of letters. Must embed custom font with Unicode support via pw.Font.ttf(...).
Scope of Work
- Approach choice per data specifics and layout (native / HTML→PDF / server)
- Report template implementation (PDF/CSV/Excel)
- File sharing and saving integration
- Edge cases handling: empty data, large volumes, page breaks
Timeframe
One PDF report template with basic formatting: 2–3 days. Multiple report types with diagrams and server generation: 1–2 weeks. Cost calculated individually.







