当前位置: 首页> 科技> 数码 > uniapp + 安卓APP + H5 + 微信小程序实现PDF文件的预览和下载

uniapp + 安卓APP + H5 + 微信小程序实现PDF文件的预览和下载

时间:2025/7/10 10:14:34来源:https://blog.csdn.net/m0_46487331/article/details/141164341 浏览次数:0次

文章目录

  • uniapp + 安卓APP + H5 + 微信小程序实现PDF文件的预览和下载
    • 1、用到的技术及插件
    • 2、简述操作:
      • 下载
      • 预览
    • 3、上代码:(主要是写后端,前端不大熟,我感觉写的还凑活,不对的请指正嘻嘻)
    • 4、注意的问题
    • 5、后续补充代码(下载进度,loading封装)
      • 1、loading的封装(手机APP中使用uni的loading会导致闪烁,所以分开写)
      • 2、下载进度

uniapp + 安卓APP + H5 + 微信小程序实现PDF文件的预览和下载

1、用到的技术及插件

uniapp、pdf.js(4.0.379,我的node是v16.15.0,这个版本正好)、微信小程序api

2、简述操作:

下载

安卓APP:点击“下载”后获取手机授权,可下载到手机“文件app”的最外层可访问目录下“file://storage/emulated/0/com.custom/”H5:安卓:点击“下载”后,基本上所有的浏览器均可弹窗下载苹果:(推荐使用Safari浏览器,其他浏览器每个效果都不一样)点击“下载”后预览PDF文件,点击页面中间的“分享”按钮,选择“保存到文件”微信小程序:安卓:点击“下载”后预览PDF文件,点击右上角“...”三个点,选择“保存到手机”苹果:点击“下载”后预览PDF文件,点击右上角“...”三个点,选择用“其他应用打开”,再点击“保存到文件”

预览

安卓APP:点击“预览”后通过pdf.js实现预览H5:点击“预览”后通过pdf.js实现预览微信小程序:点击“预览”后通过小程序内实现预览

3、上代码:(主要是写后端,前端不大熟,我感觉写的还凑活,不对的请指正嘻嘻)

提示:主要是通过一个接口获取服务器端文件的路径

1、在项目static目录下新建一个pdf目录,将pdf.js解压后两个目录个一个文件复制到该目录下
2、新建一个预览页面

<template><view><web-view :src = "url"></web-view></view>
</template><script>export default {data() {return {url : '',viewerUrl:'/static/pdf/web/viewer.html?file=',//刚解压的文件地址,用来渲染PDF的html}	},onLoad(options) {this.url = this.viewerUrl + options.url//将插件地址与接收的文件地址拼接起来},}
</script>

以下为业务代码

// APP下载------------------------------------START----------------------------------------------------
handlePdfDownload(approvalId, attachmentName) {uni.showLoading({title: '下载中...'});let data = {approvalId: approvalId,downloadType: '1'}let _this = thisthis.$api.requestPost('/api', data, true).then(res => {if (res.code && res.code != 200) {uni.hideLoading();uni.showToast({title: res.msg,icon: 'none',duration: 3000});return;}let fileUrl = `${url_config}filePath${res.data}`;//条件编译,若为h5端则直接赋值文件地址// #ifdef H5this.download4H5(fileUrl, attachmentName)// #endif//条件编译,若为App端,则需要将本地文件系统URL转换为平台绝对路径// #ifdef APP-PLUSthis.download4App(fileUrl, attachmentName)// #endif// #ifdef MP-WEIXINthis.download4WX(fileUrl, attachmentName)// #endif})
},async createDir(path) {try {// 申请本地存储读写权限return new Promise((resolve, reject) => {plus.android.requestPermissions(['android.permission.WRITE_EXTERNAL_STORAGE','android.permission.READ_EXTERNAL_STORAGE','android.permission.INTERNET','android.permission.ACCESS_WIFI_STATE'], function (e) {if (e.deniedAlways.length > 0) { //权限被永久拒绝reject(new Error('权限被永久拒绝'));}if (e.deniedPresent.length > 0) {//权限被临时拒绝reject(new Error('权限被临时拒绝'));}if (e.granted.length > 0) { //权限被允许//调用依赖获取读写手机储存权限的代码// _this.exportFile()const File = plus.android.importClass('java.io.File');let file = new File(path);if (!file.exists()) {          // 文件夹不存在即创建if (file.mkdirs()) {resolve(true);             // 成功创建文件夹} else {reject(new Error('未能创建文件夹'));//resolve(false);            // 未能创建文件夹}} else {resolve(true);              // 文件夹已存在}}}, function (e) {});});} catch (error) {console.error('权限请求失败:', error);return false; // 返回 false 表示权限请求失败}},async download4App(fileUrl, attachmentName) {try {// 获取文件夹路径const path = '/storage/emulated/0/com.custom';// 确保文件夹存在const createDirResult = await this.createDir(path);// 检查文件夹是否创建成功if (createDirResult) {// 处理文件名let lastPointIndex = attachmentName.lastIndexOf('.');let fileType = attachmentName.substring(lastPointIndex + 1);let endFileName = attachmentName.substring(0, lastPointIndex) + '_' + new Date().getTime() + '.pdf';// 开始文件下载let task = plus.downloader.createDownload(fileUrl, {filename: 'file://storage/emulated/0/com.custom/' + endFileName}, function (d, status) {if (status === 200) {uni.hideLoading();uni.showToast({icon: 'none',title: '成功下载到【手机文件->"com.custom"目录->' + endFileName + '】',duration: 3000});// d.filename是文件在保存在本地的相对路径,使用下面的API可转为平台绝对路径let fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename);console.log(fileSaveUrl);// plus.runtime.openFile(d.filename)//选择软件打开文件} else {uni.hideLoading();uni.showToast({icon: 'none',title: '下载失败',});plus.downloader.clear();}});uni.showLoading({title: '下载中...'});task.start();} else {uni.hideLoading();uni.showToast({title: '权限请求失败',icon: 'none',});console.error('权限请求失败');}} catch (error) {uni.hideLoading();uni.showToast({title: error.message,icon: 'none',});console.error('下载过程中发生错误:', error);}},download4H5(fileUrl, attachmentName) {uni.downloadFile({//需要预览的文件地址url: fileUrl,header: {"Access-Control-Expose-Headers": 'Content-Disposition'},success: (res) => {if (res.statusCode === 200) {uni.hideLoading();//下载成功,得到文件临时地址console.log('下载成功', res.tempFilePath);let newUrl = res.tempFilePath// 创建一个临时的 <a> 元素用于下载const link = document.createElement('a');link.href = newUrl;link.setAttribute('download', attachmentName);document.body.appendChild(link);link.click();document.body.removeChild(link);URL.revokeObjectURL(link.href);} else {uni.hideLoading();uni.showToast({title: '下载失败',icon: 'none',})}},fail() {uni.hideLoading();uni.showToast({title: '下载异常',icon: 'none',})}});},download4WX(fileUrl, attachmentName) {wx.downloadFile({url: fileUrl,success(res) {// 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容if (res.statusCode === 200) {uni.hideLoading();wx.openDocument({filePath: res.tempFilePath,showMenu: true, //关键点success: function (res) {console.log('打开文档成功')},fail: function (err) {uni.showToast({title: '文档打开失败',icon: 'none',duration: 3000});}})} else {uni.hideLoading();uni.showToast({title: '文档下载失败',icon: 'none',});}},fail() {uni.hideLoading();uni.showToast({title: '下载异常',icon: 'none',})}})},// APP下载------------------------------------END----------------------------------------------------// APP预览------------------------------------START----------------------------------------------------handlePdfOpen(approvalId) {uni.showLoading({title: '正在打开文档...'});let data = {approvalId: approvalId,downloadType: '0'}this.$api.requestPost('/api', data, true).then(res => {// uni.hideLoading();if (res.code && res.code != 200) {uni.hideLoading();uni.showToast({title: res.msg,icon: 'none',duration: 3000});return;}this.previewPdf(`${url_config}filePath${res.data}`)})},previewPdf(fileUrl) {//uniapp官方的下载apiuni.downloadFile({//需要预览的文件地址url: fileUrl,header: {"Access-Control-Expose-Headers": 'Content-Disposition'},success: (res) => {if (res.statusCode === 200) {//下载成功,得到文件临时地址console.log('下载成功', res.tempFilePath);uni.hideLoading();//条件编译,若为h5端则直接赋值文件地址// #ifdef H5let newUrl = res.tempFilePath// uni.hideLoading();//这里新建一个vue页面,跳转并预览pdf文档uni.navigateTo({url: "/pages/pdfView?url=" + newUrl,})// #endif//条件编译,若为App端,则需要将本地文件系统URL转换为平台绝对路径	// #ifdef APP-PLUSlet newUrl = plus.io.convertLocalFileSystemURL(res.tempFilePath)// uni.hideLoading();//这里新建一个vue页面,跳转并预览pdf文档uni.navigateTo({url: "/pages/pdfView?url=" + newUrl,})// #endif// #ifdef MP-WEIXINlet newUrl = res.tempFilePath// 微信小程序中使用 wx.openDocumentwx.openDocument({filePath: newUrl, // 文件路径fileType: 'pdf', // 文件类型success: function (res) {console.log('文档打开成功');},fail: function (err) {uni.showToast({title: '文档打开失败',icon: 'none',duration: 3000});}});// #endif		} else {uni.hideLoading();uni.showToast({title: '下载失败',icon: 'none',})}},fail() {uni.hideLoading();uni.showToast({title: '下载异常',icon: 'none',})}});},// APP预览------------------------------------END----------------------------------------------------

4、注意的问题

1、H5预览出现“Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of”

nginx中加入如下配置

include mime.types;
types 
{application/javascript mjs;
}

2、pdf.js出现跨域问题

可以将 view.js 的以下代码注释掉

 if (origin !== viewerOrigin && protocol !== 'blob:') {  throw new Error('file origin does not match viewer\'s');  }

3、pdf.js隐藏不需要的按钮

可以加上如下样式

style="visibility:hidden"

5、后续补充代码(下载进度,loading封装)

1、loading的封装(手机APP中使用uni的loading会导致闪烁,所以分开写)


data() {return {loading : null}	
},methods: {closeLoading(){this.loading = null// #ifdef APP-PLUSplus.nativeUI.closeWaiting();// #endif// #ifdef H5 || MP-WEIXINuni.hideLoading();// #endif},showLoading(title){// #ifdef H5 || MP-WEIXINuni.showLoading({title: title,mask: true});// #endif// #ifdef APP-PLUSif(this.loading){this.loading.setTitle(title)}else{this.loading = plus.nativeUI.showWaiting(title);}// #endif},showToast(title,duration){if(!duration){duration = 1500}uni.showToast({title: title,icon: 'none',duration: duration});},
}

2、下载进度

1、H5 || 微信小程序

uni.downloadFile 增加一个返回参数,以下代码:
const downloadTask = uni.downloadFile(......)downloadTask.onProgressUpdate((res) => {this.showLoading('已下载 ' + res.progress + ' %')
});

2、安卓APP

let task = plus.downloader.createDownload(..............)
task.start();
let pre_percent = 0
task.addEventListener('statechanged', function (task, status) {switch (task.state) {case 1:  // 开始console.log('开始下载');break;case 2:  // 已连接到服务器console.log('已连接到服务器');break;case 3:  // 正在下载let percent = parseInt(parseFloat(task.downloadedSize) / parseFloat(task.totalSize) * 100)if (percent > pre_percent) {_this.showLoading('已下载 ' + percent + ' %' + " ")pre_percent = percent}console.log(`已下载: ${task.downloadedSize} 总大小: ${task.totalSize}`);break;case 4:  // 下载完成console.log('下载完成');break;}});
关键字:uniapp + 安卓APP + H5 + 微信小程序实现PDF文件的预览和下载

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: