uniapp中使用PDF.js实现应用内预览PDF的实践与避坑指南

1,540 阅读3分钟

uniapp中使用PDF.js实现应用内预览PDF的实践与避坑指南

背景

在我们现有项目中,PDF预览功能一直是通过下载到本地后调用第三方应用来实现。这种交互方式存在两个主要问题:

  1. 用户体验不友好:用户需要等待下载完成,然后跳出应用进行预览
  2. 功能流程中断:部分功能需要用户在预览文件后进行特定操作,跳出应用会导致流程中断;如:给pdf文件签名、阅读等操作;

技术选型

经过调研,我们选择了PDF.js来实现这一功能。PDF.js是Mozilla开发的一个开源JavaScript库,具有以下优势:

  • 成熟的PDF渲染引擎
  • 自带完整的预览界面(viewer.html)
  • 支持缩放、旋转、搜索等常用功能
  • 开源免费,可定制性强

实现方案

在uniapp中,我们使用web-view组件来加载PDF.js自带的viewer.html实现PDF预览。这样可以避免自行实现预览、缩放等基础功能,专注于业务逻辑开发。

下载PDF预览相关文件并放在服务端

image-20250627140601829.png

  • 在服务端(为什么要放在服务端看避坑记录)新建一个文件夹,将解压文件放到该文件夹下,如:

image-20250627141935902.png

核心代码

// 在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项目的hybridstatic(部分人说放在static目录正式打包后也可以正常加载,试了不行)目录下,安卓正式打包后无法正常加载viewer.html,开发环境正常;

image-20250627142851521.png image-20250627143042308.png image-20250627143205887.png **解决方案:**将PDF.js组件资源放在服务端,但要求PDF附件的路径必须是网络路径;

4. 服务器部署问题

问题:将PDF.js组件资源放在后端服务器时,不能正常加载多语言资源,原因是IIS不能识别扩展名为.properties的文件;

解决方案:在IIS中添加MIME类型映射

  • 扩展名:.properties
  • MIME类型:application/x-text

image-20250627154253926.png

image-20250627154310466.png

5. 多语言支持限制

问题:PDF.js不能任意指定多语言语种:

  • 只能根据浏览器或系统的语种自动切换
  • 不能根据应用的语种进行指定
  • 不能通过URL的hash参数指定(除非开启调试模式 pdfBugEnabled=true)

解决方案

  • 修改PDF.js源码,强制支持通过URL的hash参数指定语种,不受调试模式控制 image-20250627154838161.png