WKWebView - Javascript 确认和警报不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34185339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:00:55  来源:igfitidea点击:

WKWebView - Javascript Confirm and Alert not working

javascriptiosswiftwebviewwkwebview

提问by Mike Purcell

I am using WKWebView to open up example.com, and on there I have a test link which is supposed to open up a JS alert, but I can't get it to display on the device, it only works if I view the site from browser.

我正在使用 WKWebView 打开 example.com,在那里我有一个测试链接,它应该打开一个 JS 警报,但我无法让它在设备上显示,它只有在我查看网站时才有效从浏览器。

I am using WKUIDelegate, and added this piece of code to the ViewController.swift file:

我正在使用 WKUIDelegate,并将这段代码添加到 ViewController.swift 文件中:

func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: (() -> Void)) {

    NSLog("Hello")
}

I don't see anything in the XCode console when I click the link that spawns the JS alert.

单击生成 JS 警报的链接时,我在 XCode 控制台中看不到任何内容。

What am I missing?

我错过了什么?

回答by wiredolphin

A little late but I would like to add my experience for future reference. The answer of @Bon Bon brought me on the path to the solution while I was trying to make things work with Swift 3and IOS 10, in which case the code needs some modifications. Firstly you need to implement also WKUIDelegate, so add it to the ViewControllerdeclaration:

有点晚了,但我想添加我的经验以供将来参考。@Bon Bon 的回答让我走上了解决方案的道路,而我正试图让事情与Swift 3和 IOS 10 一起工作,在这种情况下,代码需要一些修改。首先,您还需要实现WKUIDelegate,因此将其添加到ViewController声明中:

class ViewController: UIViewController, WKUIDelegate {

Then when you instantiate the WKWebViewobject, as for example like so:

然后当你实例化WKWebView对象时,例如像这样:

self.webView = WKWebView(frame: self.view.frame)

you need also to assign the correct value to the uiDelegateproperty of the instance:

您还需要uiDelegate为实例的属性分配正确的值:

self.webView?.uiDelegate = self

Then finally you can use the code provided by @Bon Bon, but note that there are some little differences required by Swift 3, as for example, the name of the presentViewControllermethod becomes present:

然后最后你可以使用@Bon Bon 提供的代码,但请注意,Swift 3 需要一些小差异,例如,presentViewController方法名称变为present

func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {

    let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)

    alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
        completionHandler()
    }))

    self.present(alertController, animated: true, completion: nil)
}

func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> 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)
    }))

    self.present(alertController, animated: true, completion: nil)
}

func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {

    let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .alert)

    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)

    }))

    self.present(alertController, animated: true, completion: nil)
}

That made alert, confirmationand text inputto work correctly within WKWebView, without any compiler warning in Xcode 8. I'm not an expert Swift programmer, so any useful comment about correctness of the code would be very appreciated.

这使得Xcode 8 中没有任何编译器警告alertconfirmationtext input在其中正常工作。我不是专业的 Swift 程序员,因此非常感谢有关代码正确性的任何有用评论。WKWebView

回答by Onato

You also need to set the uiDelegate on the WKWebView.

您还需要在 WKWebView 上设置 uiDelegate。

import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

    var wkWebView: WKWebView!

    public override func viewDidLoad() {
        super.viewDidLoad()

        wkWebView = WKWebView(frame: view.bounds, configuration: WKWebViewConfiguration())
        wkWebView.uiDelegate = self
        wkWebView.navigationDelegate = self
        view.addSubview(wkWebView!)
        let url = URL(string: "https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_alert")!
        wkWebView.load(URLRequest(url: url))
    }

    func webView(_ webView: WKWebView,
                 runJavaScriptAlertPanelWithMessage message: String,
                 initiatedByFrame frame: WKFrameInfo,
                 completionHandler: @escaping () -> Void) {

        let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
        let title = NSLocalizedString("OK", comment: "OK Button")
        let ok = UIAlertAction(title: title, style: .default) { (action: UIAlertAction) -> Void in
            alert.dismiss(animated: true, completion: nil)
        }
        alert.addAction(ok)
        present(alert, animated: true)
        completionHandler()
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        wkWebView.evaluateJavaScript("alert('Hello from evaluateJavascript()')", completionHandler: nil)
    }
}

For confirm()and prompt()see the other delegate methods.

查看confirm()prompt()查看其他委托方法。

回答by John the Traveler

Here is a sample code for various javascript alert implementation in Swift:

以下是 Swift 中各种 javascript 警报实现的示例代码:

It's all about converting info in javascript alert into native UI, and call the completionHandler() to send the user action back to javascript engine.

这一切都是关于将 javascript alert 中的信息转换为原生 UI,并调用 completionHandler() 将用户操作发送回 javascript 引擎。

func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {

        let alertController = UIAlertController(title: nil, message: message, preferredStyle: .ActionSheet)

        alertController.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { (action) in
            completionHandler()
        }))

        self.presentViewController(alertController, animated: true, completion: nil)
}

func webView(webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: (Bool) -> 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)
        }))

        self.presentViewController(alertController, animated: true, completion: nil)
}

func webView(webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: (String?) -> Void) {

        let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .ActionSheet)

        alertController.addTextFieldWithConfigurationHandler { (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)

        }))

        self.presentViewController(alertController, animated: true, completion: nil)
}