如何在Cordova安卓应用中打开并展示Base64编码的PDF文件?
解决方案:Cordova Android 9+ 处理Base64文件(PDF/图片)并打开
一、修复file-opener2插件编译问题并使用
你提到的file-opener2依赖Android4工具链编译失败是旧版本的问题,当前最新版已适配高版本Android,按以下步骤操作:
- 卸载旧版本(若已安装):
cordova plugin remove cordova-plugin-file-opener2
- 安装最新稳定版:
cordova plugin add cordova-plugin-file-opener2@latest
- 若仍有编译问题,在
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>
- 修改代码,在文件写入完成后调用插件打开:
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:
- 安装必要插件:
cordova plugin add cordova-plugin-file cordova-plugin-android-permissions
- 在
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>
- 完整代码(含权限申请、写入下载目录):
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中渲染,无需处理文件存储:
- 下载PDF.js预构建包,放到项目
www目录下。 - 将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
相关产品推荐
相关产品推荐

