WKWebView runJavaScriptAlertPanelWithMessage 从 iOS 9.3 崩溃
WKWebView runJavaScriptAlertPanelWithMessage crash from iOS 9.3
我在使用 WkWebview 的 WebViewController 中有以下实现,以便使用 WKWebView 的 WKUIDelegate 方法显示 javascript 警报
func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
if let host = self.webkitWebView?.URL?.host {
let alertController = UIAlertController(title: host, message: message, preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("close"), style: UIAlertActionStyle.Cancel, handler: { (action: UIAlertAction!) in
completionHandler()
}))
self.presentViewController(alertController, animated: true, completion: nil)
}
}
func webView(webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: (Bool) -> Void) {
if let host = self.webkitWebView?.URL?.host {
let alertController = UIAlertController(title: host, message: message, preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("ok_button"), style: .Default, handler: { (action: UIAlertAction!) in
completionHandler(true)
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("cancel"), style: .Cancel, handler: { (action: UIAlertAction!) in
completionHandler(false)
}))
self.presentViewController(alertController, animated: true, completion: nil)
}
}
func webView(webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: (String?) -> Void) {
if let host = self.webkitWebView?.URL?.host {
let alertController = UIAlertController(title: prompt, message: host, preferredStyle: .Alert)
alertController.addTextFieldWithConfigurationHandler({ (textField: UITextField!) in
textField.text = defaultText
})
alertController.addAction(UIAlertAction(title: NSLocalizedString("ok_button"), style: .Default, handler: { (action: UIAlertAction!) in
if let input = alertController.textFields?.first?.text {
completionHandler(input)
}
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("cancel"), style: .Default, handler: { (action: UIAlertAction!) in
completionHandler(nil)
}))
self.presentViewController(alertController, animated: true, completion: nil)
}
}
现在我注意到,自 iOS 9.3 发布以来,我的应用程序开始出现多次崩溃,并出现以下堆栈跟踪
oreFoundation
__exceptionPreprocess
libobjc.A.dylib
objc_exception_throw
CoreFoundation
-[NSException initWithCoder:]
WebKit
WebKit::CompletionHandlerCallChecker::~CompletionHandlerCallChecker()
WebKit
WTF::ThreadSafeRefCounted<WebKit::CompletionHandlerCallChecker>::deref()
WebKit
WebKit::UIDelegate::UIClient::runJavaScriptAlert(WebKit::WebPageProxy*, WTF::String const&, WebKit::WebFrameProxy*, WebKit::SecurityOriginData const&, std::__1::function<void ()>)
WebKit
WebKit::WebPageProxy::runJavaScriptAlert(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>)
WebKit
void IPC::callMemberFunctionImpl<WebKit::WebPageProxy, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>), Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply, std::__1::tuple<unsigned long long, WebKit::SecurityOriginData, WTF::String>, 0ul, 1ul, 2ul>(WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>), WTF::PassRefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>, std::__1::tuple<unsigned long long, WebKit::SecurityOriginData, WTF::String>&&, std::index_sequence<0ul, 1ul, 2ul>)
WebKit
void IPC::callMemberFunction<WebKit::WebPageProxy, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>), Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply, std::__1::tuple<unsigned long long, WebKit::SecurityOriginData, WTF::String>, std::make_index_sequence<3ul> >(std::__1::tuple<unsigned long long, WebKit::SecurityOriginData, WTF::String>&&, WTF::PassRefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>))
WebKit
void IPC::handleMessageDelayed<Messages::WebPageProxy::RunJavaScriptAlert, WebKit::WebPageProxy, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>)>(IPC::Connection&, IPC::MessageDecoder&, std::__1::unique_ptr<IPC::MessageEncoder, std::__1::default_delete<IPC::MessageEncoder> >&, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>))
WebKit
IPC::MessageReceiverMap::dispatchSyncMessage(IPC::Connection&, IPC::MessageDecoder&, std::__1::unique_ptr<IPC::MessageEncoder, std::__1::default_delete<IPC::MessageEncoder> >&)
WebKit
WebKit::WebProcessProxy::didReceiveSyncMessage(IPC::Connection&, IPC::MessageDecoder&, std::__1::unique_ptr<IPC::MessageEncoder, std::__1::default_delete<IPC::MessageEncoder> >&)
WebKit
IPC::Connection::dispatchSyncMessage(IPC::MessageDecoder&)
WebKit
IPC::Connection::dispatchMessage(std::__1::unique_ptr<IPC::MessageDecoder, std::__1::default_delete<IPC::MessageDecoder> >)
WebKit
IPC::Connection::dispatchOneMessage()
JavaScriptCore
WTF::RunLoop::performWork()
JavaScriptCore
WTF::RunLoop::performWork(void*)
CoreFoundation
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
CoreFoundation
__CFRunLoopDoSources0
CoreFoundation
__CFRunLoopRun
CoreFoundation
CFRunLoopRunSpecific
GraphicsServices
GSEventRunModal
UIKit
UIApplicationMain
错误意味着我没有调用 completionHandler,这是不可能的,因为我在我正在创建的 UIAlertController 中的所有场景中都调用了完成处理程序。还有其他人遇到过这个问题并解决了吗?
即使 URL
是 nil
也必须调用 completionHandler
if let host = self.webkitWebView?.URL?.host {
...
}
else {
//webView(_:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)
completionHandler()
//webView(_:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)
//completionHandler(false)
//webView(_:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)
//completionHandler(nil)
}
事实证明,问题是因为当已经存在导致这些崩溃的本机模态面板时,网页试图启动 javascript 模态面板。因此,我们确保在呈现此模态条目之前检查没有模态面板。如果已经存在模态面板,我们只需调用 func webView 中的 completionHAndler() 和 return(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
我在使用 WkWebview 的 WebViewController 中有以下实现,以便使用 WKWebView 的 WKUIDelegate 方法显示 javascript 警报
func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
if let host = self.webkitWebView?.URL?.host {
let alertController = UIAlertController(title: host, message: message, preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("close"), style: UIAlertActionStyle.Cancel, handler: { (action: UIAlertAction!) in
completionHandler()
}))
self.presentViewController(alertController, animated: true, completion: nil)
}
}
func webView(webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: (Bool) -> Void) {
if let host = self.webkitWebView?.URL?.host {
let alertController = UIAlertController(title: host, message: message, preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("ok_button"), style: .Default, handler: { (action: UIAlertAction!) in
completionHandler(true)
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("cancel"), style: .Cancel, handler: { (action: UIAlertAction!) in
completionHandler(false)
}))
self.presentViewController(alertController, animated: true, completion: nil)
}
}
func webView(webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: (String?) -> Void) {
if let host = self.webkitWebView?.URL?.host {
let alertController = UIAlertController(title: prompt, message: host, preferredStyle: .Alert)
alertController.addTextFieldWithConfigurationHandler({ (textField: UITextField!) in
textField.text = defaultText
})
alertController.addAction(UIAlertAction(title: NSLocalizedString("ok_button"), style: .Default, handler: { (action: UIAlertAction!) in
if let input = alertController.textFields?.first?.text {
completionHandler(input)
}
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("cancel"), style: .Default, handler: { (action: UIAlertAction!) in
completionHandler(nil)
}))
self.presentViewController(alertController, animated: true, completion: nil)
}
}
现在我注意到,自 iOS 9.3 发布以来,我的应用程序开始出现多次崩溃,并出现以下堆栈跟踪
oreFoundation
__exceptionPreprocess
libobjc.A.dylib
objc_exception_throw
CoreFoundation
-[NSException initWithCoder:]
WebKit
WebKit::CompletionHandlerCallChecker::~CompletionHandlerCallChecker()
WebKit
WTF::ThreadSafeRefCounted<WebKit::CompletionHandlerCallChecker>::deref()
WebKit
WebKit::UIDelegate::UIClient::runJavaScriptAlert(WebKit::WebPageProxy*, WTF::String const&, WebKit::WebFrameProxy*, WebKit::SecurityOriginData const&, std::__1::function<void ()>)
WebKit
WebKit::WebPageProxy::runJavaScriptAlert(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>)
WebKit
void IPC::callMemberFunctionImpl<WebKit::WebPageProxy, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>), Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply, std::__1::tuple<unsigned long long, WebKit::SecurityOriginData, WTF::String>, 0ul, 1ul, 2ul>(WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>), WTF::PassRefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>, std::__1::tuple<unsigned long long, WebKit::SecurityOriginData, WTF::String>&&, std::index_sequence<0ul, 1ul, 2ul>)
WebKit
void IPC::callMemberFunction<WebKit::WebPageProxy, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>), Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply, std::__1::tuple<unsigned long long, WebKit::SecurityOriginData, WTF::String>, std::make_index_sequence<3ul> >(std::__1::tuple<unsigned long long, WebKit::SecurityOriginData, WTF::String>&&, WTF::PassRefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>))
WebKit
void IPC::handleMessageDelayed<Messages::WebPageProxy::RunJavaScriptAlert, WebKit::WebPageProxy, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>)>(IPC::Connection&, IPC::MessageDecoder&, std::__1::unique_ptr<IPC::MessageEncoder, std::__1::default_delete<IPC::MessageEncoder> >&, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned long long, WebKit::SecurityOriginData const&, WTF::String const&, WTF::RefPtr<Messages::WebPageProxy::RunJavaScriptAlert::DelayedReply>))
WebKit
IPC::MessageReceiverMap::dispatchSyncMessage(IPC::Connection&, IPC::MessageDecoder&, std::__1::unique_ptr<IPC::MessageEncoder, std::__1::default_delete<IPC::MessageEncoder> >&)
WebKit
WebKit::WebProcessProxy::didReceiveSyncMessage(IPC::Connection&, IPC::MessageDecoder&, std::__1::unique_ptr<IPC::MessageEncoder, std::__1::default_delete<IPC::MessageEncoder> >&)
WebKit
IPC::Connection::dispatchSyncMessage(IPC::MessageDecoder&)
WebKit
IPC::Connection::dispatchMessage(std::__1::unique_ptr<IPC::MessageDecoder, std::__1::default_delete<IPC::MessageDecoder> >)
WebKit
IPC::Connection::dispatchOneMessage()
JavaScriptCore
WTF::RunLoop::performWork()
JavaScriptCore
WTF::RunLoop::performWork(void*)
CoreFoundation
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
CoreFoundation
__CFRunLoopDoSources0
CoreFoundation
__CFRunLoopRun
CoreFoundation
CFRunLoopRunSpecific
GraphicsServices
GSEventRunModal
UIKit
UIApplicationMain
错误意味着我没有调用 completionHandler,这是不可能的,因为我在我正在创建的 UIAlertController 中的所有场景中都调用了完成处理程序。还有其他人遇到过这个问题并解决了吗?
URL
是 nil
也必须调用 completionHandler
if let host = self.webkitWebView?.URL?.host {
...
}
else {
//webView(_:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)
completionHandler()
//webView(_:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)
//completionHandler(false)
//webView(_:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)
//completionHandler(nil)
}
事实证明,问题是因为当已经存在导致这些崩溃的本机模态面板时,网页试图启动 javascript 模态面板。因此,我们确保在呈现此模态条目之前检查没有模态面板。如果已经存在模态面板,我们只需调用 func webView 中的 completionHAndler() 和 return(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {