Swift WKWebView中window.close()触发后webViewDidClose未调用问题排查
问题原因
webViewDidClose(_:) 仅在由createWebViewWith代理方法创建的子窗口WKWebView调用window.close()时才会触发,你当前调用window.close()的是主WKWebView实例,主窗口的window.close()默认不会触发该代理方法,也不会有任何默认行为。
解决方法
方法一:注入JS拦截window.close(),通过消息通知原生关闭
通过WKUserScript拦截网页的window.close()调用,转而向原生发送消息,直接触发关闭逻辑:
- 配置WKWebView时注册消息处理器:
// 初始化用户内容控制器 let userContentController = WKUserContentController() // 注册名为"closeWebView"的消息处理器 userContentController.add(self, name: "closeWebView") // 配置WKWebViewConfiguration let config = WKWebViewConfiguration() config.userContentController = userContentController config.uiDelegate = self // 创建WKWebView let webView = WKWebView(frame: view.bounds, configuration: config)
- 实现
WKScriptMessageHandler代理接收消息:
extension YourViewController: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard message.name == "closeWebView" else { return } dismiss(animated: true, completion: nil) } }
- 注入拦截
window.close()的脚本:
// 编写拦截脚本,替换原生window.close逻辑 let closeInterceptorScript = """ window.close = function() { if(confirm("confirm?")) { // 向原生发送关闭消息 window.webkit.messageHandlers.closeWebView.postMessage(null); } }; """ // 创建用户脚本,在文档加载前注入主框架 let userScript = WKUserScript(source: closeInterceptorScript, injectionTime: .atDocumentStart, forMainFrameOnly: true) userContentController.addUserScript(userScript)
方法二:修改网页JS逻辑(若有权限)
如果可以修改网页代码,直接让Common.Close方法调用原生消息通知,跳过window.close():
var Common = { Close : function (){ if(confirm("confirm?")) { window.webkit.messageHandlers.closeWebView.postMessage(null); } } }
之后按方法一的步骤注册消息处理器即可。
方法三:在确认回调中主动关闭(无需修改网页)
在你已实现的runJavaScriptConfirmPanelWithMessage方法中,判断确认消息内容,用户点击确认后直接关闭控制器:
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { let alert = UIAlertController(title: message, message: nil, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "cancel", style: .cancel) { _ in completionHandler(false) }) alert.addAction(UIAlertAction(title: "ok", style: .default) { [weak self] _ in completionHandler(true) // 匹配关闭弹窗的消息,主动关闭控制器 if message == "confirm?" { self?.dismiss(animated: true, completion: nil) } }) DispatchQueue.main.async { self.present(alert, animated: true) } }
注意:如果网页中有其他相同内容的确认弹窗,可能会误触发,建议和网页端约定唯一的确认文本。
内容的提问来源于stack exchange,提问作者dh0rmfpdlxm
相关产品推荐
相关产品推荐

