Hi,
I have a UIViewRepresentable
for a WKWebView
which is loaded in ContentView
, all is well and I can respond to UI and Navigation delegate methods.
Part of what I want to do is raise Alert
when JavaScript
raises events (which is handled fine by passing in a couple of Binding
and setting the wrappedValue
). I am be able to raise Alerts with confirmation buttons in a similar fashion.
The runJavaScriptConfirmPanelWithMessage
delegate method called by WKWebView
excepts to call completionHandler
with a Boolean
value which would be the result of what the user tapped on the Alert
.
Question What would be the ideal way to bubble back the the resposne from the Alert
back to the Coordinator
housed in the ContentView
?
Any pointers are very welcome. Thank you for sparing your time to read and respond.
Reference implementation of UIViewRepresentable
with Coordinator
:
import Foundation
import SwiftUI
import WebKit
struct WebView : UIViewRepresentable {
let request: URLRequest
@Binding var showAlert: Bool
@Binding var alertMessage: String
// This has to be inside the representable structure
class Coodinator: NSObject, WKUIDelegate, WKNavigationDelegate {
var parent: WebView
var showAlert: Binding<Bool>
var alertMessage: Binding<String>
init(_ parent: WebView, showAlert: Binding<Bool>, alertMessage: Binding<String>) {
self.parent = parent
self.showAlert = showAlert
self.alertMessage = alertMessage
}
// MARK: - UI Delegate
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
self.alertMessage.wrappedValue = message
self.showAlert.wrappedValue.toggle()
completionHandler()
}
func webView(_ webView: WKWebView,
runJavaScriptConfirmPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping (Bool) -> Void) {
self.alertMessage.wrappedValue = message
self.showAlert.wrappedValue.toggle()
completionHandler(true)
}
// MARK: - Navigation Delegate
func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
decisionHandler(.allow)
}
}
func makeCoordinator() -> Coodinator {
return Coodinator(self, showAlert: self.$showAlert, alertMessage: self.$alertMessage)
}
func makeUIView(context: Context) -> WKWebView {
let webview = WKWebView()
webview.uiDelegate = context.coordinator
webview.navigationDelegate = context.coordinator
return webview
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.load(request)
}
}
and extract from the CotnentView
that houses it:
var body: some View {
NavigationView {
VStack {
WebView(request: URLRequest(url: URL(string: "https://.....")!), showAlert: self.$showAlert, isAlertConfirmation: self.$isAlertConfirmation, alertMessage: self.$alertMessage)
.alert(isPresented: self.$showAlert) { () -> Alert in
var alert = Alert(title: Text(alertMessage))
if(self.isAlertConfirmation == true) {
alert = Alert(title: Text("Are you Sure?"), message: Text(alertMessage), primaryButton: .default(Text("Confirm"), action: {
print("OK")
}), secondaryButton: .cancel({
print("Cancel")
}))
}
return alert;
}
}