You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 05:35:42