shrutim
shrutim

Reputation: 1078

WKWebView runJavaScriptAlertPanelWithMessage crash from iOS 9.3

I have the following implementation in my WebViewController that uses WkWebview in order to show the javascript alert using the WKWebView's WKUIDelegate methods

 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)
    }
}

Now I have noticed that since iOS 9.3 released, my app started getting many crashes with the following stack trace

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

the error means that I am not calling the completionHandler which is impossible given that I am calling completion handler in all scenarios in the UIAlertController I am creating. Has anyone else faced this issue and resolved it?

Upvotes: 1

Views: 6070

Answers (2)

shrutim
shrutim

Reputation: 1078

So turns out that the issue is because the web Page tries to launch a javascript modal panel when there is already a native modal panel present causing these crashes. So we have ensure that we checked that there are no modal panels before rendering this modal entry. IF there is already a modal panel present, we just call the completionHAndler() and return in the func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {

Upvotes: 0

Shingo Fukuyama
Shingo Fukuyama

Reputation: 1542

completionHandler must be called even if URL is nil

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)
}

Upvotes: 5

Related Questions