WKWebView runJavaScriptAlertPanelWithMessage 从 iOS 9.3 崩溃

Posted

技术标签:

【中文标题】WKWebView runJavaScriptAlertPanelWithMessage 从 iOS 9.3 崩溃【英文标题】:WKWebView runJavaScriptAlertPanelWithMessage crash from iOS 9.3 【发布时间】:2016-04-01 18:45:07 【问题描述】:

我的 WebViewController 中有以下实现,它使用 WkWebview 以使用 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 中的所有场景中都调用了完成处理程序。有其他人遇到过这个问题并解决了吗?

【问题讨论】:

【参考方案1】:

即使URLnil,也必须调用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)

【讨论】:

哇,我觉得自己像个笨蛋! .但我想知道为什么崩溃之前没有出现,但现在开始发生了? (可能发生了 webkit 修复,这使这个问题变得明朗)......几天后将向应用商店发布代码......希望这能解决崩溃......谢谢 即使在 else 场景中调用完成处理程序后,崩溃仍然发生 :( 如果if let input = alertController.textFields?.first?.text 的行是nil,completionHandler 永远不会被调用。【参考方案2】:

事实证明,问题是因为网页尝试启动 javascript 模态面板,而此时已经存在导致这些崩溃的本机模态面板。因此,我们确保在渲染此模态条目之前检查了没有模态面板。如果已经存在模态面板,我们只需调用 completionHAndler() 并在 func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, InitialByFrame frame: WKFrameInfo, completionHandler: () -> Void)

中返回

【讨论】:

以上是关于WKWebView runJavaScriptAlertPanelWithMessage 从 iOS 9.3 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

使用 Qt runJavaScript 函数访问 Javascript 类对象

使用 Python“运行 Javascript”输入更新 Google 地图标记位置

WKWebView:表单未在 WKWebView (Swift) 中提交

iOS wkwebview怎么写localStorage

已有iOS项目集成cordova并使用wkwebview

滚动视图中的 WKWebView