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

文章目录

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、新建一个预览页面

javascript 复制代码
<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>

以下为业务代码

js 复制代码
// APP下载------------------------------------START----------------------------------------------------
handlePdfDownload(approvalId, attachmentName) {
    uni.showLoading({
        title: '下载中...'
    });
    let data = {
        approvalId: approvalId,
        downloadType: '1'
    }
    let _this = this
    this.$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 H5
        this.download4H5(fileUrl, attachmentName)
        // #endif

        //条件编译,若为App端,则需要将本地文件系统URL转换为平台绝对路径
        // #ifdef APP-PLUS
        this.download4App(fileUrl, attachmentName)
        // #endif

        // #ifdef MP-WEIXIN
        this.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官方的下载api
                            uni.downloadFile({
                                //需要预览的文件地址
                                url: fileUrl,
                                header: {
                                    "Access-Control-Expose-Headers": 'Content-Disposition'
                                },
                                success: (res) => {
                                    if (res.statusCode === 200) {
                                        //下载成功,得到文件临时地址
                                        console.log('下载成功', res.tempFilePath);
                                        uni.hideLoading();

                                        //条件编译,若为h5端则直接赋值文件地址
                                        // #ifdef H5
                                        let newUrl = res.tempFilePath
                                        // uni.hideLoading();
                                        //这里新建一个vue页面,跳转并预览pdf文档
                                        uni.navigateTo({
                                            url: "/pages/pdfView?url=" + newUrl,
                                        })
                                        // #endif

                                        //条件编译,若为App端,则需要将本地文件系统URL转换为平台绝对路径	
                                        // #ifdef APP-PLUS
                                        let newUrl = plus.io.convertLocalFileSystemURL(res.tempFilePath)
                                        // uni.hideLoading();
                                        //这里新建一个vue页面,跳转并预览pdf文档
                                        uni.navigateTo({
                                            url: "/pages/pdfView?url=" + newUrl,
                                        })
                                        // #endif

                                        // #ifdef MP-WEIXIN
                                        let newUrl = res.tempFilePath
                                        // 微信小程序中使用 wx.openDocument
                                        wx.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"
相关推荐
kymjs张涛9 分钟前
前沿技术周刊 2025-06-09
android·前端·ios
我本梁人9 分钟前
WinForms中实现Adobe PDF Reader实现旋转PDF功能
pdf·winform
用户2018792831671 小时前
View的filterTouchesWhenObscured属性
android
宋智孝的小迷弟2 小时前
抽丝剥茧带你掌握 Kotlin Flow(一):协程时代的异步数据流处理“神器”
android·面试·app
小鱼人爱编程3 小时前
现代大前端是如何编码的?
android·前端·flutter
移动开发者1号3 小时前
Android中Activity、Task与Process的关系
android·kotlin
琪阿不会编程3 小时前
Mysql8 忘记密码重置,以及问题解决
android·数据库·sql·mysql
CYRUS_STUDIO3 小时前
一文搞懂 SO 脱壳全流程:识别加壳、Frida Dump、原理深入解析
android·安全·逆向
移动开发者1号4 小时前
Activity onCreate解析
android·kotlin
甜甜的资料库4 小时前
基于微信小程序的作业管理系统源码数据库文档
java·数据库·微信小程序·小程序