为何pdfMake.createPdf(docDefinition).download()在浏览器可用,Ionic6/React安卓端无效?
Ionic6/React中pdfMake在Android端无法下载PDF的解决方案
问题原因
桌面浏览器中pdfMake.createPdf(docDefinition).download()依赖原生浏览器下载API,但Android的WebView(Capacitor默认使用)不支持直接通过该方式触发下载,导致无响应。
解决方案
借助Capacitor的文件系统和分享插件,手动处理PDF的生成、保存与分享:
1. 安装必要插件
npm install @capacitor/filesystem @capacitor/share npx cap sync
2. 修改PDF生成逻辑
替换原有的download()调用,改为生成Base64格式的PDF数据,再通过Capacitor插件保存或分享:
import pdfMake from 'pdfmake/build/pdfmake'; import pdfFonts from 'pdfmake/build/vfs_fonts'; import { Filesystem, Directory, Encoding } from '@capacitor/filesystem'; import { Share } from '@capacitor/share'; pdfMake.vfs = pdfFonts.pdfMake.vfs; // 文档定义(保留原有内容) const docDefinition = { pageOrientation:'landscape', content: [ {image:"logo", width: 100, height: 100, alignment: "center", margin:[0,-20,0,5]}, {text: 'Institución Educativa Fiscal "Miguel de Santiago"', style:"header"}, {text: `Rector/a: ${rector}`, style:"header"}, {text: `Secretario/a: ${secretario}`, style:"header", margin:[0,0,0,20]}, {text: `Asignatura: ${secretario}`, style:"info"}, {text: `Especialidad: ${secretario}`, style:"info"}, {text: `Curso: ${secretario}`, style:"info",margin:[0,0,0,10]}, {text: `Paralelo: ${secretario}`, style:"info",bold:true, alignment:"center"}, { table: { widths: [150, 'auto', 'auto','auto', 'auto', 'auto','auto', 'auto', 'auto','auto','auto','auto','auto'], headerRows: 2, body: [ [{text: 'Estudiante', style: 'header', rowSpan:2, margin:[0,16]},{text: 'Quimestre 1', style: 'header', colSpan: 4, fillColor: "#a01d27", color:"white"}, {},{},{}, {text: 'Quimestre 2', colSpan:4,style: 'header', fillColor: "#a01d27", color:"white"}, {},{},{},{text:'Periodo 2023-2024', style:'header',colSpan:4},{},{},{}], [{}, {text: 'Parcial 1', style: 'subheader'},{text: 'Parcial 2', style: 'subheader'},{text: 'Parcial 3', style: 'subheader'},{text: 'Final Q1', style: 'subheader'},{text: 'Parcial 1', style: 'subheader'},{text: 'Parcial 2', style: 'subheader'},{text: 'Parcial 3', style: 'subheader'}, {text: 'Final Q1', style: 'subheader'}, {text: 'Supletorio', style: 'subheader',margin:[0,6,0,0]},{text: 'Remedial', style: 'subheader',margin:[0,6,0,0]},{text: 'Gracia', style: 'subheader',margin:[0,6,0,0]},{text: 'Final', style: 'subheader',margin:[0,6,0,0]}] ] } } ], styles: { header:{ fontSize:15, alignment: "center", verticalAlignment:"middle" }, subheader:{ fontSize:13, alignment:"center", fillColor:"#d5d5d4" }, info:{ fontSize: 14, alignment:'left' }, tableHeader:{ bold: true, fontSize: 13, color: 'black' } }, images:{ logo:{ url:"https://cdn-icons-png.flaticon.com/512/2231/2231696.png" } } }; // 生成并处理PDF的异步函数 const generateAndHandlePdf = async () => { try { const pdfDoc = pdfMake.createPdf(docDefinition); // 获取PDF的Base64数据 pdfDoc.getBase64(async (base64Data) => { // 保存PDF到设备的文档目录 const savedFile = await Filesystem.writeFile({ path: 'calificaciones.pdf', data: base64Data, directory: Directory.Documents, encoding: Encoding.Base64 }); // 触发分享功能,让用户选择打开/保存方式 await Share.share({ title: 'Calificaciones', text: 'Archivo de calificaciones generado', url: savedFile.uri }); alert('PDF已保存至文档目录'); }); } catch (error) { console.error('PDF生成/保存失败:', error); alert('生成PDF时出错'); } }; // 执行PDF生成 generateAndHandlePdf();
3. 优化图片加载(可选)
移动端加载远程图片可能遇到CORS问题,建议将图片转换为Base64嵌入文档:
// 获取图片Base64的工具函数 const getImageBase64 = async (url: string) => { const response = await fetch(url); const blob = await response.blob(); return new Promise<string>((resolve) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result?.toString().split(',')[1] || ''); reader.readAsDataURL(blob); }); }; // 初始化PDF生成流程 const initPdf = async () => { const logoBase64 = await getImageBase64('https://cdn-icons-png.flaticon.com/512/2231/2231696.png'); // 更新文档定义中的图片 const updatedDocDefinition = { ...docDefinition, images:{ logo:{ dataUri: `data:image/png;base64,${logoBase64}` } } }; // 调用生成函数 const pdfDoc = pdfMake.createPdf(updatedDocDefinition); // 后续保存/分享逻辑同前 }; initPdf();
4. 旧版Android权限配置
若需兼容Android 9及以下版本,需在android/app/src/main/AndroidManifest.xml中添加存储权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
内容的提问来源于stack exchange,提问作者Ariel Calderon
相关产品推荐
相关产品推荐

