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

如何在Cordova安卓应用中打开并展示Base64编码的PDF文件?

解决方案:Cordova Android 9+ 处理Base64文件(PDF/图片)并打开

一、修复file-opener2插件编译问题并使用

你提到的file-opener2依赖Android4工具链编译失败是旧版本的问题,当前最新版已适配高版本Android,按以下步骤操作:

  1. 卸载旧版本(若已安装):
cordova plugin remove cordova-plugin-file-opener2
  1. 安装最新稳定版:
cordova plugin add cordova-plugin-file-opener2@latest
  1. 若仍有编译问题,在config.xml中添加兼容配置:
<platform name="android">
    <preference name="android-targetSdkVersion" value="33" />
    <preference name="GradlePluginVersion" value="7.4.2" />
    <preference name="GradleVersion" value="7.5" />
</platform>
  1. 修改代码,在文件写入完成后调用插件打开:
var filePath = cordova.file.externalDataDirectory;
var fileName = "someFileName.pdf";
var mime = "application/pdf";
var dataBlob = /* 你的Base64转成的Blob */;

function writeFile(fileEntry, dataBlob) {
    fileEntry.createWriter(function (fileWriter) {
        fileWriter.onwriteend = function() {
            console.log("文件写入完成");
            cordova.plugins.fileOpener2.open(
                fileEntry.toURL(),
                mime,
                {
                    error: function(e) {
                        console.log("打开失败: " + e.message);
                    },
                    success: function() {
                        console.log("文件已打开");
                    }
                }
            );
        };

        fileWriter.onerror = function (e) {
            console.log("写入失败: " + e.toString());
        };

        fileWriter.write(dataBlob);
    });
}

window.resolveLocalFileSystemURL(
    filePath,
    function onResolveSuccess (dirEntry) {
        dirEntry.getFile(
            fileName,
            { create: true, exclusive: false },
            function onGetFileSuccess (file) {
                writeFile(file, dataBlob);
                // 注意:不能在这里直接调用打开,writeFile是异步操作
            },
            function getFileError(e) {
                console.log("获取文件失败: " + e.toString());
            }
        );
    },
    function resolveError(e) {
        console.log("解析路径失败: " + e.toString());
    }
);

该方案无需将文件放到公共目录,插件可直接访问应用私有目录文件,调用系统默认应用打开。

二、将文件写入公共「下载」目录并提示用户

若需将文件存到用户可见的下载目录,需处理Android存储权限与Scoped Storage:

  1. 安装必要插件:
cordova plugin add cordova-plugin-file cordova-plugin-android-permissions
  1. 在config.xml中添加权限与兼容配置:
<platform name="android">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- Android 10+ 兼容旧存储模式 -->
    <application android:requestLegacyExternalStorage="true" />
</platform>
  1. 完整代码(含权限申请、写入下载目录):
var permissions = cordova.plugins.permissions;
var downloadDir = cordova.file.externalPublicDirectory + "/Download/";
var fileName = "someFileName.pdf";
var mime = "application/pdf";
var dataBlob = /* 你的Base64转成的Blob */;

// 先申请存储权限
function checkPermissions() {
    permissions.checkPermission(permissions.WRITE_EXTERNAL_STORAGE, function(status) {
        if (status.hasPermission) {
            writeToDownloadDir();
        } else {
            permissions.requestPermission(permissions.WRITE_EXTERNAL_STORAGE, function() {
                writeToDownloadDir();
            }, function() {
                console.log("用户拒绝了存储权限");
            });
        }
    });
}

function writeToDownloadDir() {
    window.resolveLocalFileSystemURL(
        downloadDir,
        function(dirEntry) {
            dirEntry.getFile(
                fileName,
                { create: true, exclusive: false },
                function(fileEntry) {
                    writeFile(fileEntry, dataBlob);
                },
                function(e) {
                    console.log("创建文件失败: " + e.toString());
                }
            );
        },
        function(e) {
            console.log("解析下载目录失败: " + e.toString());
        }
    );
}

function writeFile(fileEntry, dataBlob) {
    fileEntry.createWriter(function(fileWriter) {
        fileWriter.onwriteend = function() {
            console.log("文件已保存到下载目录: " + fileEntry.fullPath);
            alert("文件已保存到下载目录,请打开文件管理器查看");
            // 部分设备支持直接通过系统打开
            window.open(fileEntry.toURL(), "_system");
        };

        fileWriter.onerror = function(e) {
            console.log("写入失败: " + e.toString());
        };

        fileWriter.write(dataBlob);
    });
}

// 启动流程
checkPermissions();

注意:Android 11+的Scoped Storage限制更严格,requestLegacyExternalStorage仅对Android 10有效,Android 11+需额外适配MediaStore API。

三、直接在WebView中展示PDF(无需外部应用)

对于PDF,可使用PDF.js库直接在WebView中渲染,无需处理文件存储:

  1. 下载PDF.js预构建包,放到项目www目录下。
  2. 将Base64转成ArrayBuffer并传给PDF.js:
// Base64转ArrayBuffer
function base64ToArrayBuffer(base64) {
    var binaryString = window.atob(base64);
    var bytes = new Uint8Array(binaryString.length);
    for (var i = 0; i < binaryString.length; i++) {
        bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes.buffer;
}

// 加载展示PDF
function showPdf(base64Data) {
    var arrayBuffer = base64ToArrayBuffer(base64Data);
    // 假设PDF.js的viewer.html在www/pdfjs/viewer.html
    localStorage.setItem('pdfData', JSON.stringify(arrayBuffer));
    window.open('pdfjs/viewer.html', '_blank');
}

后续在viewer.html中读取localStorage数据加载PDF即可,具体参考PDF.js官方文档。

对于图片,直接将Base64作为img的src:

<img src="data:image/png;base64,你的Base64字符串" alt="图片">

关键错误修正

你现有代码的致命问题:在onGetFileSuccess中直接调用window.open,但writeFile是异步操作,此时文件尚未写入完成,导致打开无效。必须在fileWriter.onwriteend回调中执行打开操作。

内容的提问来源于stack exchange,提问作者Cin Vhetin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 14:10:26