I have a WKWebView
wrapped in a UIViewRepresentable
. I want to modify certain URLs during page navigation, but the code for the delegate never gets called...
import SwiftUI
import WebKit
struct SwiftUIWebView: UIViewRepresentable {
let url: URL
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ webView: WKWebView, context: Context) {
let request = URLRequest(url: url)
webView.load(request)
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
}
extension SwiftUIWebView {
@MainActor class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy {
print("Delegate called...")
webView.uiDelegate = self
webView.navigationDelegate = self
if let url = navigationAction.request.url, url.host != "somedomain.com", await UIApplication.shared.open(url) {
return .cancel
} else {
return .allow
}
}
}
}
I never see the text in the console, and the behavior is not what I expect. What am I missing? 🤔
Ok, got it sussed. The code is simpler, and the delegate method now fires with each nav request, allowing me to define different behavior for internal vs. external links. Here's the working code:
import SwiftUI
import WebKit
struct SwiftUIWebView: UIViewRepresentable {
let url: URL
func makeUIView(context: Context) -> WKWebView {
print("makeUIView called...")
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
return webView
}
func updateUIView(_ webView: WKWebView, context: Context) {
print("updateUIView called...")
let request = URLRequest(url: url)
webView.load(request)
}
func makeCoordinator() -> Coordinator {
print("makeCoordinator called...")
let coord = Coordinator()
return coord
}
@MainActor class Coordinator: NSObject, WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy {
print("Delegate called...")
if let frame = navigationAction.targetFrame, frame.isMainFrame {
print("Target is main frame...")
return .allow
} else {
print("Target is external...")
return .cancel
}
}
}
}
The webView.navigationDelegate = context.coordinator
line was absolutely key, and the following article...
www.hackingwithswift.com/books/ios-swiftui/using-coordinators-to-manage-swiftui-view-controllers
...was a big help in getting the proper incantation for setting the navigationDelegate
.
Thanks again, @BabyJ, for pointing me in the right direction!