乐于分享
好东西不私藏

Flutter 如何优雅地实现 PDF 生成

Flutter 如何优雅地实现 PDF 生成
点击蓝字 关注我们

引言

在移动端开发中,PDF文档处理几乎是各类企业应用的标配——无论是生成发票、收据、报告还是电子合同。作为跨平台开发的首选框架,Flutter 具备插件优雅的生成。

一、选择合适的 PDF 方案

目前 Flutter 生态中 PDF 处理的核心方案是 pdf + printing 组合,两者相辅相成:

库名
功能定位
pdf
PDF 文档创建和内容生成
printing
PDF 打印、预览和分享

安装步骤:

dependencies:  pdf: ^3.11.0  printing: ^5.14.3
flutter pub get

二、核心代码实现

1. 基础PDF生成

import 'package:pdf/pdf.dart';import 'package:pdf/widgets.dart' as pw;Future<Uint8List> generatePDF() async {  final pdf = pw.Document();  pdf.addPage(pw.Page(    pageFormat: PdfPageFormat.a4,    build: (pw.Context context) {      return pw.Center(        child: pw.Text(          'Hello PDF!',          style: pw.TextStyle(fontSize20),        ),      );    },  ));  return pdf.save();}

2. PDF 打印与分享

import 'package:printing/printing.dart';// 保存到本地final file = File("example.pdf");await file.writeAsBytes(await pdf.save());// 分享PDFawait Printing.sharePdf(bytes: pdfBytes, filename'example.pdf');// 预览PDFPdfPreview(  build(format) => doc.save(),);

三、高级功能实战

1. 添加表格

pw.Table.fromTextArray(  context: context,  data: <List<String>>[    ['姓名''年龄'],    ['Alice''30'],    ['Bob''25'],  ],)

2. 插入图片

// 从本地文件加载final image = pw.MemoryImage(  File('test.webp').readAsBytesSync(),);// 从 Assets 加载final img = await rootBundle.load('assets/images/logo.jpg');final imageBytes = img.buffer.asUint8List();final image = pw.Image(pw.MemoryImage(imageBytes));

3. 自定义字体

// 加载本地字体final ttf = await fontFromAssetBundle('assets/open-sans.ttf');pw.Text(  'Dart is awesome',  style: pw.TextStyle(font: ttf, fontSize40),)// 或加载 Google 字体final font = await PdfGoogleFonts.nunitoExtraLight();

4. 插入 SVG

final svgRaw = '''<svg viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><circle cx="25" cy="25" r="20" fill="blue" /></svg>''';final svgImage = pw.SvgImage(svg: svgRaw);

四、平台权限配置(关键步骤)

Android 配置

在 android/app/src/main/AndroidManifest.xml 中添加:

<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE" />

iOS 配置

在 ios/Runner/Info.plist 中添加:

<key>UIBackgroundModes</key><array>  <string>print</string></array>

macOS 特殊配置

在 macos/Runner/Release.entitlements 中添加:

<key>com.apple.security.print</key><true/>

五、常用功能速查表

功能
方法
说明
生成 PDF
pdf.save()
返回 Uint8List
保存文件
File.writeAsBytes()
保存本地文件
分享 PDF
Printing.sharePdf()
分享到其他应用
预览 PDF
PdfPreview
 组件
实时预览
加载图片
MemoryImage
内存图片加载
多页文档
addPage()
添加多页

六、避坑指南

常见问题:

问题
解决方案
iOS 预览不显示
检查 Info.plist 配置
图片无法加载
确认文件路径和权限
内存不足
大文件分页处理
Web 端不支持
使用 Printing 的 Web 方案
字体乱码
使用本地字体文件或 Google Fonts

优化建议:

  • 使用 PdfPreview 进行热重载调试,快速预览效果
  • 图片资源尽量压缩,减少 PDF 体积
  • 复杂文档分段生成,避免单页内容过多
  • 注意不同平台的路径差异

七、完整实战案例

void createAndSharePDF() async {  final pdf = pw.Document();  // 添加标题页  pdf.addPage(pw.Page(    build: (context) => pw.Center(      child: pw.Text('PDF 示例报告', style: pw.TextStyle(fontSize24)),    ),  ));  // 添加表格页  pdf.addPage(pw.Page(    build: (context) => pw.Table.fromTextArray(      context: context,      data: [        ['项目''数量''价格'],        ['商品A''10''¥100'],        ['商品B''5''¥200'],      ],    ),  ));  // 保存并分享  final pdfBytes = await pdf.save();  await Printing.sharePdf(bytes: pdfBytes, filename'报告.pdf');}

八、应用场景推荐

场景
推荐方案
电商订单
pdf + 表格 + 签名
财务报表
多页 PDF + 图表
电子合同
pdf + 数字签名
活动签到
pdf + 图片 + 表格
培训证书
pdf + 自定义字体 + 图片

总结

Flutter 的 PDF 功能已经相当成熟,pdf + printing 组合可覆盖 95% 以上的移动端 PDF 需求。只要按规范配置权限,就能轻松实现各种文档生成功能。

参考资料
  • https://pub.dev/packages/pdf
  • https://pub.dev/packages/printing
  • https://github.com/DavBfr/dart_pdf

愿每一个做技术、做服务的人,都能被温柔以待,不负努力,不负自己,越来越好。