【问题标题】:WKWebView - Javascript Confirm and Alert not workingWKWebView - Javascript 确认和警报不起作用
【发布时间】:2016-03-15 02:40:37
【问题描述】:

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

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

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

    NSLog("Hello")
}

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

我错过了什么?

【问题讨论】:

标签: javascript ios swift webview wkwebview


【解决方案1】:

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

class ViewController: UIViewController, WKUIDelegate {

那么当你实例化WKWebView对象时,例如像这样:

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

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

self.webView?.uiDelegate = self

那么终于可以使用@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)
}

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

【讨论】:

  • 感谢 @Bon Bon 提供的原始代码,没有它我会工作一夜!
  • preferredStyle: .alert 应设置为提示而不是 preferredStyle: .actionSheet - 如果没有此更改,我会收到错误消息,说文本字段只能添加到警报
  • 除非您应用 Godblessstrawberry 注释,否则使用 Swift 4 的我似乎 prompt() 失败并带有信号 SIGABRT。 @wiredolphin 可能会很好地将您的答案更正更改为使用 preferredStyle: .alert
  • 这应该是选择的答案
【解决方案2】:

您还需要在 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)
    }
}

对于 confirm()prompt(),请参阅其他委托方法。

【讨论】:

  • 是的,这是设置的。你能让 js 与 WKWebView 一起工作吗?我必须更改我所有的原生 js 警报/确认对话框以使用引导框对话框来解决问题。
  • 是的,它对我来说很好用。你的控制器是你的 UIDelegate 还是你有一个单独的对象?也许委托正在被释放?
  • 你能用这段代码打开原生js对话框吗?
  • 是的。如果您将示例项目上传到 Github,我可以看看为什么它不适合您。
  • 这不适用于 wkwebview 的 evaluateJavaScript(),参考这篇文章stackoverflow.com/q/43600624/6521116
【解决方案3】:

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

这都是关于将 javascript alert 中的信息转换为 native 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)
}

【讨论】:

  • 如何修改此代码使其也适用于 ipad?
  • 我需要以下行作为对此答案的编辑:alertController.popoverPresentationController?.sourceView = self.view
  • @applecrusher 谢谢你的评论。它肯定会帮助更多的人:)
  • @applecrusher 如果您尝试一次显示多个警报,您是否遇到过应用程序崩溃的问题?在 iPhone 上运行良好,但在 iPad 上崩溃。
猜你喜欢
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多