iOS应用WKWebView中Alert弹窗触发崩溃,添加代码仍未解决求助
我开发了一款集成WKWebView的iOS应用,点击带有Alert弹窗的链接时,应用崩溃并跳转至AppDelegate,收到如下提示:
Your application has presented a UIAlertController (<UIAlertController: 0x7f916a840a00>) of style UIAlertControllerStyleActionSheet from Kronos_Sport.ViewController (<Kronos_Sport.ViewController: 0x7f9168808c00>). The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.
我不确定要在ViewController里加什么代码才能修复这个问题。
补充说明:我已经在viewDidLoad里加了下面这段代码,但应用还是崩溃:
self.popoverPresentationController?.delegate = self self.popoverPresentationController?.sourceView = self.view self.popoverPresentationController?.sourceRect = self.view.bounds self.popoverPresentationController?.permittedArrowDirections = []
你现在的问题核心是:WKWebView里JS触发的ActionSheet弹窗,不是你ViewController自身的popoverPresentationController,所以你在viewDidLoad里设置自己的popover属性根本没用。
正确的做法是通过WKUIDelegate协议拦截并处理WebView的弹窗:
- 先让你的ViewController遵守
WKUIDelegate和UIPopoverPresentationControllerDelegate协议:
class ViewController: UIViewController, WKUIDelegate, UIPopoverPresentationControllerDelegate { // ... 你的其他代码 }
- 给WKWebView实例设置
uiDelegate为当前ViewController:
webView.uiDelegate = self
- 实现WKUIDelegate中处理确认弹窗(对应JS的confirm)的方法,手动创建UIAlertController并配置好popover参数:
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet) // 配置popover的位置信息,绑定到WebView上 alertController.popoverPresentationController?.sourceView = webView alertController.popoverPresentationController?.sourceRect = webView.bounds alertController.popoverPresentationController?.permittedArrowDirections = [] alertController.popoverPresentationController?.delegate = self // 添加按钮并处理回调 alertController.addAction(UIAlertAction(title: "确认", style: .default) { _ in completionHandler(true) }) alertController.addAction(UIAlertAction(title: "取消", style: .cancel) { _ in completionHandler(false) }) present(alertController, animated: true) } // 实现代理方法,确保iPad上弹窗正常展示 func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle { return .none }
如果还需要处理普通的Alert弹窗(对应JS的alert),也要实现对应的方法:
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "确定", style: .default) { _ in completionHandler() }) present(alertController, animated: true) }
这样就能拦截WebView中JS触发的所有弹窗,正确配置popover的位置信息,解决崩溃问题。
内容的提问来源于stack exchange,提问作者Camille Gallet

