SwiftUI runJavaScriptConfirmPanelWithMessage不适用于WKWebView

dkqlctbz  于 2023-08-02  发布在  Swift
关注(0)|答案(3)|浏览(153)

我正在使用SwiftUI构建一个简单的Web应用程序,它只需将我的网站加载到Web视图中。从我的网站上,它必须显示JavaScript confirm,以便用户能够从应用程序中注销,而我的runJavaScriptConfirmPanelWithMessage内部的函数在Javascript确认被触发时会导致应用程序崩溃。
下面是我的Web应用程序的完整代码。

import SwiftUI
import WebKit

struct Webview : UIViewRepresentable {
    let request: URLRequest
    var webview: WKWebView?

    init(web: WKWebView?, req: URLRequest) {
        self.webview = WKWebView()
        self.request = req
    }

    class Coordinator: NSObject, WKUIDelegate {
        var parent: Webview

        init(_ parent: Webview) {
            self.parent = parent
        }

        // Delegate methods go here

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

            // alert functionality goes here
            let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)

            alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))

            alertController.present(alertController, animated: true)

            completionHandler()

        }

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

            // confirm functionality goes here. THIS CRASHES THE APP
            let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)

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

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

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

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

            // prompt functionality goes here

        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> WKWebView  {
        return webview!
    }

    func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.uiDelegate = context.coordinator
        uiView.load(request)
    }

    func goBack(){
        webview?.goBack()
    }

    func goForward(){
        webview?.goForward()
    }

    func reload(){
        webview?.reload()
    }
}

struct ContentView: View {

    let webview = Webview(web: nil, req: URLRequest(url: URL(string: "https://google.com")!))

    var body: some View {
        VStack {
            webview
            HStack() {
                Button(action: {
                    self.webview.goBack()
                }){
                    Image(systemName: "chevron.left")
                }.padding(32)

                Button(action: {
                    self.webview.reload()
                }){
                    Image(systemName: "arrow.clockwise")
                }.padding(32)

                Button(action: {
                    self.webview.goForward()
                }){
                    Image(systemName: "chevron.right")
                }.padding(32)
            }.frame(height: 40)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

字符串
我不知道我在runJavaScriptConfirmPanelWithMessage的这一节中做错了什么,使应用程序崩溃。
这就是我遇到麻烦的地方。

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

            // confirm functionality goes here. THIS CRASHES THE APP
            let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)

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

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

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


谁能告诉我我做错了什么?

bvhaajcl

bvhaajcl1#

参考Artem Kovalev回答其只在iPhone上工作。对于弹出窗口在iPad中工作需要遵循https://stackoverflow.com/a/60403127/22185295

if (UIDevice.current.userInterfaceIdiom == .pad) {
  alertStyle = UIAlertController.Style.alert
}

字符串

jw5wzhpr

jw5wzhpr2#

您需要一个视图控制器来显示警报。试试这个:

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) })
    )
    
    if let controller = topMostViewController() {
        controller.present(alertController, animated: true, completion: nil)
    }
    
}

private func topMostViewController() -> UIViewController? {
    guard let rootController = keyWindow()?.rootViewController else {
        return nil
    }
    return topMostViewController(for: rootController)
}

private func keyWindow() -> UIWindow? {
    return UIApplication.shared.connectedScenes
        .filter {$0.activationState == .foregroundActive}
        .compactMap {$0 as? UIWindowScene}
        .first?.windows.filter {$0.isKeyWindow}.first
}

private func topMostViewController(for controller: UIViewController) -> UIViewController {
    if let presentedController = controller.presentedViewController {
        return topMostViewController(for: presentedController)
    } else if let navigationController = controller as? UINavigationController {
        guard let topController = navigationController.topViewController else {
            return navigationController
        }
        return topMostViewController(for: topController)
    } else if let tabController = controller as? UITabBarController {
        guard let topController = tabController.selectedViewController else {
            return tabController
        }
        return topMostViewController(for: topController)
    }
    return controller
}

字符串
感谢这个答案https://stackoverflow.com/a/57877120/11212894

dojqjjoe

dojqjjoe3#

请注意,您正在尝试从alertController呈现alertController,这是一个崩溃原因。

相关问题