uniapp中使用PDF.js实现应用内预览PDF的实践与避坑指南
背景
在我们现有项目中,PDF预览功能一直是通过下载到本地后调用第三方应用来实现。这种交互方式存在两个主要问题:
- 用户体验不友好:用户需要等待下载完成,然后跳出应用进行预览
- 功能流程中断:部分功能需要用户在预览文件后进行特定操作,跳出应用会导致流程中断;如:给pdf文件签名、阅读等操作;
技术选型
经过调研,我们选择了PDF.js来实现这一功能。PDF.js是Mozilla开发的一个开源JavaScript库,具有以下优势:
- 成熟的PDF渲染引擎
- 自带完整的预览界面(viewer.html)
- 支持缩放、旋转、搜索等常用功能
- 开源免费,可定制性强
实现方案
在uniapp中,我们使用web-view组件来加载PDF.js自带的viewer.html实现PDF预览。这样可以避免自行实现预览、缩放等基础功能,专注于业务逻辑开发。
下载PDF预览相关文件并放在服务端
-
解压后的效果
- 在服务端(为什么要放在服务端看避坑记录)新建一个文件夹,将解压文件放到该文件夹下,如:
核心代码
// 在uniapp页面中
<template>
<view>
<web-view :src="webviewSrc"></web-view>
</view>
</template>
<script setup>
import {
ref
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import {
getLangFlag,
langCodeObj
} from '@/locale/index.js';
const viewerHtmlUrl = "http://10.13.xx.xx:xxxx/Scripts/pdfjs/web/viewer.html"; // 线上地址
const webviewSrc = ref("");
const PDFJS_LANG = {
CN: "zh-CN",
EN: "en-US"
}
const initPdfViewer = (filePath)=>{
try{
// 根据应用的语种指定pdfjs组件的语种
const lang = getLangFlag() === langCodeObj.en ? PDFJS_LANG.EN : PDFJS_LANG.CN ;
webviewSrc.value = `${viewerHtmlUrl}?file=${encodeURIComponent(filePath)}#locale=${lang}`;
} catch (err){
uni.showToast({
title: "pdf文件预览失败"
})
}
}
onLoad((e)=>{
// filePath是网络地址:https://zjjcmspublic.oss-cn-hangzhou-zwynet-d01-a.internet.cloud.zj.gov.cn/jcms_files/jcms1/web3096/site/attach/0/f81f4e5464f944c292a1e2e7425966d5.pdf
initPdfViewer(e.filePath);
})
</script>
踩坑记录与解决方案
1. PDF.js版本问题
问题:PDF.js使用最新的语法糖,不向下兼容
- 4.3.x以上的版本在存在兼容性问题,安卓报Promise.withResolvers is not a function,iOS白屏、报错;
- 4.3.x以下的版本在安卓设备可以正常使用; iOS报错、白屏 ,2.6.347以下版本可以正常显示;
解决方案:在安卓和iOS都能正常使用的情况下,使用高的PDF.js版本;
2. iOS本地文件预览问题
问题:当需要预览下载到本地的PDF文件时(PDF.js资源放在项目中):
- iOS不能正常加载
- 多语言资源无法正常加载(iOS安全策略和路径协议差异问题)
解决方案:
- 对于iOS平台,将本地PDF文件转换为base64格式进行预览
3. 资源放置问题
问题:将PDF.js组件资源放在uniapp项目的hybrid或static(部分人说放在static目录正式打包后也可以正常加载,试了不行)目录下,安卓正式打包后无法正常加载viewer.html,开发环境正常;
**解决方案:**将PDF.js组件资源放在服务端,但要求PDF附件的路径必须是网络路径;
4. 服务器部署问题
问题:将PDF.js组件资源放在后端服务器时,不能正常加载多语言资源,原因是IIS不能识别扩展名为.properties的文件;
解决方案:在IIS中添加MIME类型映射
- 扩展名:
.properties - MIME类型:
application/x-text
5. 多语言支持限制
问题:PDF.js不能任意指定多语言语种:
- 只能根据浏览器或系统的语种自动切换
- 不能根据应用的语种进行指定
- 不能通过URL的hash参数指定(除非开启调试模式 pdfBugEnabled=true)
解决方案:
- 修改PDF.js源码,强制支持通过URL的hash参数指定语种,不受调试模式控制