title: WKWebView javascript alert, prompt, confirm won't work
body: <p>hi I'm implementing simple WKWebView appplication and I want to be able to ask user for input via prompt dialogue, I tried to use solution mentioned here </p>
  
  <blockquote>
    <p><a href="https://stackoverflow.com/a/40157363/1665293">https://stackoverflow.com/a/40157363/1665293</a></p>
  </blockquote>
  
  <p>but I'm not sure how should it work when implemented - should this just add extension to WKWebView for triggering e.g. regular <code>alert()</code> from javascript or I should pass some different instructions in js to trigger this native alert?</p>
  
  <p>so my question is:
  1) how this should work when implemented
  2) what am I missing in implementation</p>
  
  <p>here's my controller code (giving whole controller, as I dont know what could be important here)</p>
  
  <p>thanks in advance!</p>
  
  <pre><code>import UIKit
  import WebKit
  
  class ViewController:
      UIViewController
      , WKNavigationDelegate
      , UIScrollViewDelegate
      , WKUIDelegate
  {
  
      @IBOutlet var webView: WKWebView!
      let getUrlAtDocumentStartScript = "GetUrlAtDocumentStart"
      let getUrlAtDocumentEndScript = "GetUrlAtDocumentEnd"
  
      override func loadView() {
          self.webView = WKWebView()
          self.webView.navigationDelegate = self
  
          //for prompt
          self.webView?.uiDelegate = self
  
          view = webView
      }
  
      override func viewWillAppear(_ animated: Bool) {//white status bar
          super.viewWillAppear(animated)
          webView.isOpaque = false //removes white flash on WKWebView load
          webView.backgroundColor = UIColor(red: 41/255, green: 45/255, blue: 91/255, alpha: 1)
          UIApplication.shared.statusBarStyle = .lightContent
  
          do {
  
              let paid = Bundle.main.infoDictionary?["paid"]  as? Bool;
              var fileName = "none"
  
              if(paid!){
                  fileName = "index-ios-wvd-inlined--paid"
              } else {
                  fileName = "index-ios-wvd-inlined"
              }
              guard let filePath = Bundle.main.path(forResource: fileName, ofType: "html")
                  else {
                      print ("File reading error")
                      return
              }
  
  
              let contents =  try String(contentsOfFile: filePath, encoding: .utf8)
              let baseUrl = URL(fileURLWithPath: filePath)
              webView.loadHTMLString(contents as String, baseURL: baseUrl)
  
          }
          catch {
              print ("File HTML error")
          }
  
      }
  
      override var preferredStatusBarStyle : UIStatusBarStyle {//white status bar
          return .lightContent
      }
  
      override func viewDidLoad() {
          webView.scrollView.bounces = false;
          super.viewDidLoad()
          webView.scrollView.delegate = self //disable zoom
  
  
          //for haptics
          let config = WKWebViewConfiguration()
          config.addScript(script: WKUserScript.getUrlScript(scriptName: getUrlAtDocumentStartScript), scriptHandlerName:getUrlAtDocumentStartScript, scriptMessageHandler: self, injectionTime: .atDocumentStart)
          config.addScript(script: WKUserScript.getUrlScript(scriptName: getUrlAtDocumentEndScript), scriptHandlerName:getUrlAtDocumentEndScript, scriptMessageHandler: self, injectionTime: .atDocumentEnd)
          webView = WKWebView(frame:  UIScreen.main.bounds, configuration: config)
          webView.navigationDelegate = self
          view.addSubview(webView)
      }
  
      //disable zoom        
      func viewForZooming(in: UIScrollView) -&gt; UIView? {
          return nil;
      }
  
      override func didReceiveMemoryWarning() {
          super.didReceiveMemoryWarning()
          // Dispose of any resources that can be recreated.
      }
  
      func tapped(i:Int) {
          print("Triggering haptic #\(i)")
  
          switch i {
          case 1:
              let generator = UINotificationFeedbackGenerator()
              generator.notificationOccurred(.error)
  
          case 2:
              let generator = UINotificationFeedbackGenerator()
              generator.notificationOccurred(.success)
  
          case 3:
              let generator = UINotificationFeedbackGenerator()
              generator.notificationOccurred(.warning)
  
          case 4:
              let generator = UIImpactFeedbackGenerator(style: .light)
              generator.impactOccurred()
  
          case 5:
              let generator = UIImpactFeedbackGenerator(style: .medium)
              generator.impactOccurred()
  
          case 6:
              let generator = UIImpactFeedbackGenerator(style: .heavy)
              generator.impactOccurred()
  
          default:
              let generator = UISelectionFeedbackGenerator()
              generator.selectionChanged()
          }
      }
  
      //alert/prompt/confirm dialogs
      func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
                   completionHandler: @escaping () -&gt; Void) {
  
          let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
          alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
              completionHandler()
          }))
  
          present(alertController, animated: true, completion: nil)
      }
  
  
      func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
                   completionHandler: @escaping (Bool) -&gt; Void) {
  
          let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)
  
          alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
              completionHandler(true)
          }))
  
          alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
              completionHandler(false)
          }))
  
          present(alertController, animated: true, completion: nil)
      }
  
  
      func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo,
                   completionHandler: @escaping (String?) -&gt; Void) {
  
          let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .actionSheet)
  
          alertController.addTextField { (textField) in
              textField.text = defaultText
          }
  
          alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
              if let text = alertController.textFields?.first?.text {
                  completionHandler(text)
              } else {
                  completionHandler(defaultText)
              }
          }))
  
          alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
              completionHandler(nil)
          }))
  
          present(alertController, animated: true, completion: nil)
      }
  
  }
  
  //sending scripts commands to JS and back
  extension ViewController: WKScriptMessageHandler {
      func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
          switch message.name {
  
          case getUrlAtDocumentStartScript:
              tapped(i: message.body as! Int)
              //print("start: \(message.body)")
  
          case getUrlAtDocumentEndScript:
              tapped(i: message.body as! Int)
              //print("tapped: \(message.body)")
  
          default:
              break;
          }
      }
  }
  
  extension WKUserScript {
      class func getUrlScript(scriptName: String) -&gt; String {
          return "webkit.messageHandlers.\(scriptName).postMessage(1)"
      }
  }
  
  extension WKWebView {
      func loadUrl(string: String) {
          if let url = URL(string: string) {
              load(URLRequest(url: url))
          }
      }
  }
  
  extension WKWebViewConfiguration {
      func addScript(script: String, scriptHandlerName:String, scriptMessageHandler: WKScriptMessageHandler, injectionTime:WKUserScriptInjectionTime) {
          let userScript = WKUserScript(source: script, injectionTime: injectionTime, forMainFrameOnly: false)
          userContentController.addUserScript(userScript)
          userContentController.add(scriptMessageHandler, name: scriptHandlerName)
      }
  }
  </code></pre>