Delphi TWebBrowser在Android/iOS端Window.Print功能失效问题
核心根因
FMX 跨平台框架封装的 TWebBrowser 组件在 iOS、Android 端本质是调用系统原生 WebView 内核,默认没有实现完整浏览器自带的 window.print 事件响应逻辑,这和独立 Safari、Chrome 这类完整浏览器的实现存在差异,和你写的 PDF.js 业务逻辑本身没有关系。
排查步骤
- 先做最小场景验证:剥离所有PDF.js相关逻辑,在嵌入页面加一个绑定
window.print()调用的测试按钮,确认最简打印调用是否生效。如果这个场景下点击按钮也没有任何打印响应,即可确定问题出在WebView层的能力缺失,和前端PDF.js逻辑无关。 - 开启WebView远程调试确认链路:iOS端用Mac端Safari连接设备调试WebView,Android端用PC端Chrome连接设备调试WebView,在PDF.js打印按钮的点击逻辑、
window.print调用位置加断点,确认:- 点击打印按钮后逻辑是否正常走到
window.print调用 - 控制台有没有抛出Blob资源访问、权限类的静默错误
- PDF.js生成的打印用临时Blob URL是否被WebView安全策略拦截
- 点击打印按钮后逻辑是否正常走到
- 核对平台配置差异:
- iOS端:确认当前TWebBrowser使用的是WKWebView(老版本FMX默认用被废弃的UIWebView,本身打印支持就有缺陷),确认FMX封装层有没有实现WKWebView的打印相关代理方法。
- Android端:确认应用是否声明了打印相关权限,当前设备的系统WebView版本是否支持打印API,TWebBrowser有没有开启JavaScript自动弹窗/文件访问权限。
解决方案
优先推荐:JS桥接原生打印方案(跨版本兼容性最好)
不要依赖WebView默认的window.print实现,自行打通前端和原生层的打印通信链路:
- 前端层重写全局
window.print方法,拦截PDF.js的打印请求,把待打印的PDF数据通过桥接传给原生层:
// 在Web应用初始化阶段注入这段逻辑,适配FMX WebView环境 const originalPrint = window.print; window.print = function() { // 优先判断是否在FMX WebView环境,存在原生桥接方法时走原生打印 if (window.FMXBridge && typeof window.FMXBridge.printPDF === 'function') { // 从PDF.js实例获取当前打开的PDF二进制数据,根据自身业务的PDF.js初始化逻辑调整取值方式 const pdfBinaryData = pdfViewer.currentDocument.getData(); // 转成Base64传给原生层,避免二进制传输的类型转换问题 const base64Pdf = btoa(String.fromCharCode.apply(null, new Uint8Array(pdfBinaryData))); window.FMXBridge.printPDF(base64Pdf); return; } // 普通浏览器环境走原有打印逻辑 originalPrint.call(window); }
- FMX原生层实现桥接逻辑:
- 给TWebBrowser组件注册JS交互接口,暴露
FMXBridge.printPDF方法给前端调用 - 接收到前端传的Base64格式PDF数据后,转存为平台可识别的PDF文件
- 调用系统原生打印API完成打印:iOS端用
UIPrintInteractionController弹出系统打印面板,Android端用系统PrintManager提交PDF打印任务
快速修复方案(改动量小,适配特定FMX版本)
- iOS端:如果使用Delphi 11及以上版本,可以直接给WKWebView注入一段补丁JS,手动把
window.print调用桥接到原生的viewPrintFormatter方法,不需要改动现有PDF.js逻辑;低于11的版本需要手动补全WKWebView的打印代理实现,替换掉FMX默认的空实现。 - Android端:给TWebBrowser绑定的WebView注册自定义
JavascriptInterface,拦截window.print调用,主动唤起系统打印服务,同时在应用Manifest里添加android.permission.PRINT权限,开启WebView的文件访问开关。
避坑注意
- 不要直接用PDF.js默认的iframe打印方案,iOS WKWebView对跨域iframe、Blob iframe的打印有严格的沙箱限制,大概率会静默失败。
- Android端存储待打印PDF时,不要放到公共存储目录,Android 10及以上的分区存储机制会拦截文件访问,直接存到应用私有缓存目录即可。
- FMX的TWebBrowser默认会吞掉大部分JS权限类错误,不开启远程调试的话很难定位到具体失败点,排查阶段一定要开远程调试看控制台日志。
内容的提问来源于stack exchange,提问作者Carlos Z.
相关产品推荐
相关产品推荐

