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"
相关推荐
黄林晴12 分钟前
如何判断手机是否是纯血鸿蒙系统
android
火柴就是我20 分钟前
flutter 之真手势冲突处理
android·flutter
Emma歌小白29 分钟前
如何首次运行小程序后端
微信小程序
法的空间39 分钟前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
循环不息优化不止1 小时前
深入解析安卓 Handle 机制
android
恋猫de小郭1 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
jctech1 小时前
这才是2025年的插件化!ComboLite 2.0:为Compose开发者带来极致“爽”感
android·开源
赣州云智科技的技术铺子1 小时前
【一步步开发AI运动APP】十二、自定义扩展新运动项目1
微信小程序·小程序·云开发·智能小程序
用户2018792831671 小时前
为何Handler的postDelayed不适合精准定时任务?
android
叽哥1 小时前
Kotlin学习第 8 课:Kotlin 进阶特性:简化代码与提升效率
android·java·kotlin