uni.openDocument打开PDF常失败因iOS/Android原生预览对路径、权限、MIME敏感;iOS不支持__UNI__路径,安卓拦截file://;其无法嵌入签名,须用web-view加载自托管viewer.html,注意PDF.js worker路径配置、PDF本地下载与file://转换、Canvas签名层叠加及服务端嵌入签名。

App端直接用uni.openDocument打开PDF为什么经常失败
因为iOS和Android的原生预览组件对路径协议、文件权限、MIME类型极其敏感。iOS WKWebView不支持__UNI__前缀路径,安卓部分厂商系统(如华为EMUI、小米MIUI)会拦截file://协议或拒绝渲染未签名的本地PDF。更关键的是,uni.openDocument完全无法嵌入签名区域——它只是个黑盒阅读器,你没法在上面画一笔。
必须用web-view加载自托管的viewer.html,但要注意worker加载失败
PDF.js依赖pdf.worker.js做后台解析,而App端WKWebView默认禁用Worker构造函数。常见报错是ReferenceError: Worker is not defined或页面白屏。解决方法不是删掉worker,而是显式指定其路径并确保可访问:
- 把
pdf.worker.min.js放在static/pdfjs/目录下(不能放hybrid或assets) - 在
viewer.html里加一行:PDFJS.workerSrc = '/static/pdfjs/pdf.worker.min.js'; - 确认
static目录在H5和App编译后都存在且路径一致(App端会自动映射到_www/static/)
PDF文件必须先下载到uni.env.USER_DATA_PATH再转file://协议
直接传网络URL给viewer.html会触发跨域或token失效;传base64会因iOS WKWebView限制导致空白页。唯一稳定路径是走本地文件流:
- 调用
uni.downloadFile,tempFilePath存到uni.env.USER_DATA_PATH + '/contract.pdf' - 用
plus.io.resolveLocalFileSystemURL把绝对路径转成file:///格式(注意:H5端不用这步,直接用tempFilePath) -
web-view的src设为/hybrid/pdfjs/viewer.html?file=你的file://路径 - 务必在
viewer.html里补全location.search解析逻辑,否则PDF不会加载
签名功能不能塞进PDF.js viewer,得用独立Canvas层叠加
PDF.js渲染后的页面是只读DOM,强行插入canvas会破坏缩放和滚动同步。正确做法是让web-view只负责显示PDF,签名区域用原生view+canvas覆盖在上方:
- 监听
web-view的message事件,等PDF加载完成后再显示签名层 - 用
uni.createSelectorQuery获取web-view在屏幕上的真实位置和尺寸,动态设置canvas宽高和transform偏移 - 签名笔迹数据导出为PNG后,用
uni.canvasToTempFilePath生成临时路径,再通过uni.postMessage发回web-view内JS进行图层合成(需修改viewer.html增加接收逻辑) - 最终合并效果必须在服务端完成——前端拼接的PNG只是预览,真合同要由后端用
pdf-lib或Ghostscript把签名图嵌入PDF原文件
最易被忽略的点:iOS上web-view与原生canvas的z-index层级关系不稳定,必须用position: fixed配合pointer-events: none控制穿透,否则签名时会误触PDF缩放按钮。



















