WKWebView使用addEventListener无法接收Calendly事件问题咨询
解决方案
核心问题点
- 加载HTML时
baseURL传入nil触发跨域限制,Calendly iframe发送的postMessage无法被父页面捕获 - Calendly初始化配置未添加
parent参数,事件消息会被浏览器跨域策略拦截 - 注入的JS代码存在语法错误:第二个message监听回调中误用了未声明的
event变量,应使用回调参数e - 直接将对象类型的
e.data与字符串拼接,会转为无意义的[object Object],丢失事件数据 - 重复定义
isCalendlyEvent函数,冗余且可能引发逻辑异常
修正后完整代码
import UIKit import WebKit class ViewController: UIViewController, WKScriptMessageHandler { var webView: WKWebView! var count = 0 var html = """ <html> <head> <meta name='viewport' content='width=device-width' /> </head> <body> <!-- Calendly inline widget begin --> <div class="calendly-inline-widget" data-auto-load="false"> <script type="text/javascript" src="https://assets.calendly.com/assets/external/widget.js"></script> <script> Calendly.initInlineWidget({ url: 'https://calendly.com/XXX', parent: window.location.origin, // 新增parent配置,解决跨域发消息问题 prefill: { name: "John Doe", email: "john@joe2.com", customAnswers: { a1: "yes" } } }); </script> </div> <!-- Calendly inline widget end --> </body> </html> """ override func viewDidLoad() { let config = WKWebViewConfiguration() let js = """ function isCalendlyEvent(e) { return e.data?.event && e.data.event.indexOf('calendly') === 0; }; window.addEventListener('message', function(e) { console.log('In listener. Event.type: ' + e.type + ' e.data.event: ' + e.data?.event + ' event: ' + JSON.stringify(e.data)); if (isCalendlyEvent(e)) { console.log('calendly event!!!!'); // 序列化事件数据后传给原生 window.webkit.messageHandlers.clickListener.postMessage('Calendly:' + JSON.stringify(e.data)); } else { window.webkit.messageHandlers.clickListener.postMessage('Other:' + JSON.stringify(e.data)); } }); """ let script = WKUserScript(source: js, injectionTime: .atDocumentEnd, forMainFrameOnly: false) config.userContentController.addUserScript(script) config.userContentController.add(self, name: "clickListener") webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self // 可选,方便排查加载错误 view.addSubview(webView) // 传入有效baseURL解决跨域问题 self.webView.loadHTMLString(self.html, baseURL: URL(string: "https://calendly.com")) } func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { count = count + 1 print("Msg \(count): \(message.body) ") } } // 可选:实现导航代理排查加载问题 extension ViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { print("页面加载完成") } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { print("加载失败:\(error)") } }
验证说明
用户完成预约后会收到calendly.event_scheduled类型的事件,可直接从序列化后的字符串中解析出预约相关信息。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

