0

I already saw this and this and this but I couldn't apply the answers to my problem.

I am new to swiftui so I'm not sure how to get this done. In my app, I need to display some HTML content so I created a UIViewRepresentable like below:

import SwiftUI
import WebKit

struct HTMLStringView: UIViewRepresentable {
    let htmlContent: String

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

    func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.loadHTMLString(htmlContent, baseURL: nil)
    }
    
}

and I display it in my view like so:

HTMLStringView(htmlContent: "HTML String")

The problem is that some of the HTML content have links and they open within the view. How can I open the links in Safari Browser or at least a sheet instead if the link is reachable or valid?

MartinTexy
  • 27
  • 5

1 Answers1

0

I had the same problem and I was able to solve it with some addition to @jnpdx 's accepted answer here

First of all you want to check if the link is reachable. Create a URL extension:

extension URL {
    func isReachable(completion: @escaping (Bool) -> ()) {
        var request = URLRequest(url: self)
        request.httpMethod = "HEAD"
        URLSession.shared.dataTask(with: request) { _, response, _ in
            completion((response as? HTTPURLResponse)?.statusCode == 200)
        }.resume()
    }
}

Then create a Coordinator class:

class Coordinator : NSObject, WKNavigationDelegate {
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            guard let url = navigationAction.request.url else {
                decisionHandler(.allow)
                return
            }
            
            if url.absoluteString.contains("www.youtube.com"){ //In my case I needed to allow links with Youtube
                decisionHandler(.allow)
            } else {
                url.isReachable { success in //To test if the URL is reachable
                    if success {
                        decisionHandler(.cancel)
                        DispatchQueue.main.async { //Needs to run on the main thread to prevent UI issues
                            UIApplication.shared.open(url)
                        }
                    } else {
                        decisionHandler(.allow)
                    }
                }
            }
        }
    }

Reference the Coordinator by adding this to your struct:

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

Finally, assign the coordinator as the view's navigation delegate by adding this line to your updateUIView func so that it now looks like this:

func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.navigationDelegate = context.coordinator //Assign the coordinator as the view's navigation delegate
        uiView.loadHTMLString(htmlContent, baseURL: nil)
    }
oracle
  • 66
  • 1
  • 10