Search code examples
swiftuiwkwebviewuiviewrepresentable

How do I display WKWebView url?


I was wondering how I can display my current URL on WKWebView and display URL on change also. Currently I added a Text() but it does not display the URL at all. Any ideas how I can fix it?

WebView

import SwiftUI
import WebKit

struct WebView : UIViewRepresentable {
    
    let request: URLRequest
    private var webView: WKWebView?

    init (request: URLRequest) {
        self.webView = WKWebView()
        self.request = request
    }
    
    func makeUIView(context: Context) -> WKWebView  {
        webView?.load(request)
        return webView!
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) {
    
    }

    func URL() -> String {
        return (webView?.url)?.absoluteString ?? ""
    }

    func goBack() {
        webView?.goBack()
    }
    
    func goForward() {
        webView?.goForward()
    }
    
}

MainView

struct MainView: View {
   var webView: WebView = WebView(request: URLRequest(url: URL(string: "https://www.google.com")!))

 var body: some View {
  VStack {
   //...
   Text(webView.URL())
   webView
   Button(action: { webView.goBack() }, label: { Text("Test") })
//...
  }
 }

Solution

  • To keep track of the URL of the WKWebView, you'll need to use a WKNavigationDelegate.

    You can use a Coordinator in your UIViewRepresentable for the WKNavigationDelegate and an ObservableObject with a @Published value to communicate between the WebView and your parent view:

    class NavigationState : ObservableObject {
        @Published var url : URL?
    }
    
    struct WebView : UIViewRepresentable {
        
        let request: URLRequest
        var navigationState : NavigationState
        
        func makeCoordinator() -> Coordinator {
            return Coordinator()
        }
        
        func makeUIView(context: Context) -> WKWebView  {
            let webView = WKWebView()
            context.coordinator.navigationState = navigationState
            webView.navigationDelegate = context.coordinator
            webView.load(request)
            return webView
        }
        
        func updateUIView(_ uiView: WKWebView, context: Context) {
            
        }
    
        class Coordinator : NSObject, WKNavigationDelegate {
            var navigationState : NavigationState?
            
            func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
                navigationState?.url = webView.url
            }
        }
        
    }
    
    struct ContentView: View {
        @StateObject var navigationState = NavigationState()
        
        var body: some View {
            VStack(){
                Text(navigationState.url?.absoluteString ?? "(none)")
                WebView(request: URLRequest(url: URL(string: "https://www.google.com")!), navigationState: navigationState)
            }
        }
    }
    

    Update, based on comments:

    class NavigationState : NSObject, ObservableObject {
        @Published var url : URL?
        let webView = WKWebView()
    }
    
    extension NavigationState : WKNavigationDelegate {
        func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
            self.url = webView.url
        }
    }
    
    struct WebView : UIViewRepresentable {
        
        let request: URLRequest
        var navigationState : NavigationState
        
        func makeUIView(context: Context) -> WKWebView  {
            let webView = navigationState.webView
            webView.navigationDelegate = navigationState
            webView.load(request)
            return webView
        }
        
        func updateUIView(_ uiView: WKWebView, context: Context) { }
    }
    
    struct ContentView: View {
        @StateObject var navigationState = NavigationState()
        
        var body: some View {
            VStack(){
                Text(navigationState.url?.absoluteString ?? "(none)")
                WebView(request: URLRequest(url: URL(string: "https://www.google.com")!), navigationState: navigationState)
                HStack {
                    Button("Back") {
                        navigationState.webView.goBack()
                    }
                    Button("Forward") {
                        navigationState.webView.goForward()
                    }
                }
            }
        }
    }