当前位置: 首页 > news >正文

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

文章目录

  • uniapp + 安卓APP + H5 + 微信小程序实现PDF文件的预览和下载
    • 1、用到的技术及插件
    • 2、简述操作:
      • 下载
      • 预览
    • 3、上代码:(主要是写后端,前端不大熟,我感觉写的还凑活,不对的请指正嘻嘻)
    • 4、注意的问题

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"
http://www.lryc.cn/news/423441.html

相关文章:

  • Elasticsearch 8 RAG 技术分享
  • 根据字典值回显,有颜色的
  • 多台PC网络ADB连接同一台RK3399 Android7.1.2设备
  • 前端黑科技:使用 JavaScript 实现网页扫码功能
  • 【人工智能】全景解析:【机器学习】【深度学习】从基础理论到应用前景的【深度探索】
  • MySQL与PostgreSQL语法区别
  • vue2+OpenLayers 天地图上凸显出当前地理位置区域(4)
  • 基于Python、Django开发Web计算器
  • 高性能并行计算面试-核心概念-问题理解
  • java-activiti笔记
  • Layui——隐藏表单项后不再进行验证
  • Github Copilot 使用技巧
  • 【实现100个unity特效之20】用unity实现物品悬浮和发光像素粒子特效
  • GPT-4o mini发布,轻量级大模型如何颠覆AI的未来?
  • 高性能的 C++ Web 开发框架 CPPCMS + WebSocket 模拟实现聊天与文件传输案例。
  • 合合信息OCR支持30类国内常见票据一站式分类识别,支持医疗发票、数电票识别
  • LeetCode-day40-3151. 特殊数组 I
  • 技术研究:Redis 数据结构与 I/O 模型
  • 46-扇孔的处理及铺铜以及布线
  • LVS实验的三模式总结
  • 游戏安全入门-扫雷分析远程线程注入
  • bert-base-chinese模型的完整训练、推理和一些思考
  • JS基础5(JS的作用域和JS预解析)
  • Doris 夺命 30 连问!(中)
  • 书生.浦江大模型实战训练营——(四)书生·浦语大模型全链路开源开放体系
  • SpringBoot 整合 RabbitMQ 实现延迟消息
  • Cilium:基于开源 eBPF 的网络、安全性和可观察性
  • Axios 详解与使用指南
  • 深度学习 —— 个人学习笔记20(转置卷积、全卷积网络)
  • 解决Mac系统Python3.12版本pip安装报错error: externally-managed-environment的问题