WKWebView加载Angular应用时无法下载jsPDF生成的PDF问题求助
解决WKWebView中Angular应用jsPDF下载无响应的问题
这个问题很常见——WKWebView不像Safari那样自带下载处理逻辑,当你的Angular应用用jsPDF触发下载时,WebView不知道该怎么处理这个请求,所以才会出现控制台没输出但下载无响应的情况。下面给你两种可行的解决方案,你可以根据自己的iOS版本需求选择:
方案一:通过WKNavigationDelegate接管下载任务(iOS 13+)
从iOS 13开始,WKWebView提供了直接处理下载任务的代理方法,我们可以用它来捕获jsPDF触发的下载请求,然后把PDF保存到本地并提供分享选项:
- 首先更新你的ViewController代码,添加
WKNavigationDelegate协议并设置代理:
import UIKit import WebKit class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate { @IBOutlet var mWebKit: WKWebView! let url = URL(string: "foo.bar") override func viewDidLoad() { super.viewDidLoad() mWebKit.uiDelegate = self // 必须设置navigationDelegate才能接收下载回调 mWebKit.navigationDelegate = self let request = URLRequest(url: url!) mWebKit.load(request) } // 当下载任务完成时调用 func webView(_ webView: WKWebView, downloadTask: WKDownloadTask, didFinishDownloadingTo location: URL) { // 读取下载的PDF数据 guard let pdfData = try? Data(contentsOf: location) else { print("无法读取PDF数据") return } // 将PDF保存到应用的文档目录 let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let saveURL = documentsDir.appendingPathComponent("generated.pdf") do { try pdfData.write(to: saveURL) // 弹出分享面板,让用户选择保存或分享PDF let shareVC = UIActivityViewController(activityItems: [saveURL], applicationActivities: nil) present(shareVC, animated: true) } catch { print("保存PDF失败:\(error.localizedDescription)") } } // 允许下载请求继续执行 func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { if navigationAction.shouldPerformDownload { decisionHandler(.allow) } else { decisionHandler(.allow) } } }
方案二:通过JS与原生交互传递PDF数据(兼容所有iOS版本)
如果你的App需要支持iOS 12及以下版本,或者jsPDF是通过Blob URL触发的下载(这种情况方案一可能捕获不到),可以用JS把PDF的base64数据直接传给原生,再由原生处理保存:
原生代码修改:
import UIKit import WebKit class ViewController: UIViewController, WKUIDelegate, WKScriptMessageHandler { @IBOutlet var mWebKit: WKWebView! let url = URL(string: "foo.bar") override func viewDidLoad() { super.viewDidLoad() mWebKit.uiDelegate = self // 添加消息处理器,接收JS传来的PDF数据 let userContentController = mWebKit.configuration.userContentController userContentController.add(self, name: "savePDF") let request = URLRequest(url: url!) mWebKit.load(request) } // 接收JS发送的消息 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard message.name == "savePDF", let pdfBase64 = message.body as? String else { print("无效的PDF数据") return } // 将base64转为Data guard let pdfData = Data(base64Encoded: pdfBase64) else { print("base64解码失败") return } // 保存并分享PDF,逻辑和方案一一致 let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let saveURL = documentsDir.appendingPathComponent("generated.pdf") do { try pdfData.write(to: saveURL) let shareVC = UIActivityViewController(activityItems: [saveURL], applicationActivities: nil) present(shareVC, animated: true) } catch { print("保存PDF失败:\(error.localizedDescription)") } } }
Angular前端代码修改:
把原来的doc.save()替换成向原生发送消息的代码:
// 生成PDF的代码不变,修改保存逻辑 const doc = new jsPDF(); doc.text("Hello World!", 10, 10); // 将PDF转为base64并发送给原生 const pdfBase64 = doc.output('datauristring').split('base64,')[1]; if (window.webkit?.messageHandlers?.savePDF) { window.webkit.messageHandlers.savePDF.postMessage(pdfBase64); }
注意事项
- 如果你选择方案一,确保你的App部署目标是iOS 13或更高版本;
- 保存文件到相册或其他系统目录时,需要在
Info.plist中添加对应的权限描述(比如NSPhotoLibraryAddUsageDescription); - 先在桌面浏览器测试你的Angular应用,确保jsPDF能正常生成PDF,排除前端代码的问题。
内容的提问来源于stack exchange,提问作者Inbar Azulay
相关产品推荐
相关产品推荐

