Ad

SwiftUI Open A New View On Link Click Inside Of WKWebView

- 1 answer

I would like to open a new view in SwfitUI (webview) after clicking on a link inside of WKWebView, I do not know how to do. I understand that you have to go through Coordinator, but I don't know more. I don't have a very high level in swift.

Here is my Swiftui view (I removed superfluous elements) and al calsse to display my content in my view :

struct PostDetailView: View {

    var p: Post
    @ObservedObject var dataManager: DataManager



    let preferences:Preferences = parsePreferences()
    let contentWebView = ArticleCustomView()
    @State var showComments = false
    @Binding var favorite: Bool



    @Environment(\.colorScheme) var colorScheme


    var body: some View {
    
        let content: String =  contentWebView.contentArticle(title: p.title.rendered.stringByDecodingHTMLEntities, content: p.content.rendered, date: formatDateDetailPost(dateToChange: p.date), author: p.author_meta.nickname)
        
        
        ZStack{
        
            BackgroundView()
            
            articleWebView(text: content, color: colorScheme)
                
         
        }
        .navigationBarTitle(...)
        .navigationBarItems(...)

    }
}

x

struct articleWebView: UIViewRepresentable  {
    @State var text: String
    @State var color: ColorScheme
    
    func makeUIView(context: Context) -> WKWebView {
    
         return _wkwebview
        
    }
    

    
    func updateUIView(_ uiView: WKWebView, context: Context) {
        
        
        var html = ""
        var normalizeCSS: String = ""
        var articlesCSS: String = ""
        //let articlesDarkCSS: String
        let altCSS: String
        

        altCSS = "-dark" 
        
        guard let fileURL = Bundle.main.url(forResource: "articles", withExtension: "html") else { return print("articles.html introuvable")}
        guard let fileURLNormalizeCss = Bundle.main.url(forResource: "normalize", withExtension: "css") else { return print("normalize.css introuvable")}
        guard let fileURLArticlesCss = Bundle.main.url(forResource: "articles\(altCSS)", withExtension: "css") else { return print("articles\(altCSS).css introuvable")}
        
        do {
            html = try String(contentsOf: fileURL)
        } catch  {
            print("Unable to get the articles.html")
        }
        
        do {
            normalizeCSS = try String(contentsOf: fileURLNormalizeCss)
        } catch  {
            print("Unable to get the normalize.css")
        }
        
        do {
            articlesCSS = try String(contentsOf: fileURLArticlesCss)
        } catch  {
            print("Unable to get the articles.css")
        }
        
        html = html.replacingOccurrences(of: "[article:content]", with: text)
        html = html.replacingOccurrences(of: "[normalize:CSS]", with: normalizeCSS)
        html = html.replacingOccurrences(of: "[style:articles]", with: articlesCSS)
        
        
        uiView.loadHTMLString(html, baseURL: nil)
        
        
        
        
        
        //----------------------------------------------//
        uiView.allowsBackForwardNavigationGestures = true
        uiView.isOpaque = false
        uiView.backgroundColor = .clear
        uiView.scrollView.backgroundColor = UIColor.clear
        uiView.scrollView.showsVerticalScrollIndicator = false
        uiView.scrollView.pinchGestureRecognizer?.isEnabled = false 

        
        
              
        
        
        
    }
 }   

Thank you in advance.

Ad

Answer

I finally found a solution to my problem. You have to use the Coordinator to know when there is a click on a link and to retrieve the link.

Using Binding I transfer the url to the view and I open a sheetView and inside I have my my webview which opens the url

struct PostDetailView: View {

var p: Post
@ObservedObject var dataManager: DataManager



let preferences:Preferences = parsePreferences()
let contentWebView = ArticleCustomView()
@State var showComments = false
@Binding var favorite: Bool

@State var activeSheet: Bool = false
@State var urlToOpenInSheet: String = ""

@Environment(\.colorScheme) var colorScheme


var body: some View {

    let content: String =  contentWebView.contentArticle(title: p.title.rendered.stringByDecodingHTMLEntities, content: p.content.rendered, date: formatDateDetailPost(dateToChange: p.date), author: p.author_meta.nickname)
    
    
    ZStack{
    
        BackgroundView()
        
        articleWebView(text: content, color: colorScheme, activeSheet: $activeSheet, urlToOpenInSheet: $urlToOpenInSheet)
            
     
    }
    .navigationBarTitle(...)
    .navigationBarItems(...)
    .sheet(isPresented: $activeSheet) {
            if !urlToOpenInSheet.isEmpty {
                ExternalWebView(urlToVisite: urlToOpenInSheet, activeButtons: true, fromSheet: true, closeSheet: $activeSheet)
                    .ignoresSafeArea()
                    .accentColor(.white)
            }
        }
    .onChange(of: urlToOpenInSheet) { newValue in
            print("url changed to \(urlToOpenInSheet)!")
        }

    }
}




struct articleWebView: UIViewRepresentable  {
@State var text: String
@State var color: ColorScheme
@Binding var activeSheet: Bool
@Binding var urlToOpenInSheet: String


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

func makeUIView(context: Context) -> WKWebView {
    
    let WKWebView = WKWebView()
    WKWebView.navigationDelegate = context.coordinator
    return WKWebView
}



func updateUIView(_ uiView: WKWebView, context: Context) {
    
    var html = ""
    var normalizeCSS: String = ""
    var articlesCSS: String = ""
    //let articlesDarkCSS: String
    let altCSS: String
    

    
    guard let fileURL = Bundle.main.url(forResource: "articles", withExtension: "html") else { return print("articles.html introuvable")}
    guard let fileURLNormalizeCss = Bundle.main.url(forResource: "normalize", withExtension: "css") else { return print("normalize.css introuvable")}
    guard let fileURLArticlesCss = Bundle.main.url(forResource: "articles\(altCSS)", withExtension: "css") else { return print("articles\(altCSS).css introuvable")}
    
    do {
        html = try String(contentsOf: fileURL)
    } catch  {
        print("Unable to get the articles.html")
    }
    
    do {
        normalizeCSS = try String(contentsOf: fileURLNormalizeCss)
    } catch  {
        print("Unable to get the normalize.css")
    }
    
    do {
        articlesCSS = try String(contentsOf: fileURLArticlesCss)
    } catch  {
        print("Unable to get the articles.css")
    }
    
    html = html.replacingOccurrences(of: "[article:content]", with: text)
    html = html.replacingOccurrences(of: "[normalize:CSS]", with: normalizeCSS)
    html = html.replacingOccurrences(of: "[style:articles]", with: articlesCSS)
    
    //print(html)
    uiView.loadHTMLString(html, baseURL: nil)
    
    
    
    
    
    //---------------------- Activer /Desactiver certaines options sur la Webview -------------------------//
    uiView.allowsBackForwardNavigationGestures = true
    uiView.isOpaque = false
    uiView.backgroundColor = .clear
    uiView.scrollView.backgroundColor = UIColor.clear
    uiView.scrollView.showsVerticalScrollIndicator = false // indicateur de scroll
    uiView.scrollView.pinchGestureRecognizer?.isEnabled = false // zommer-dezommer avec le doigt
    
    
}

class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {
    var parent: articleWebView
    

    init(_ parent: articleWebView) {
        self.parent = parent
    }
    
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        
        
        if navigationAction.navigationType == .linkActivated  {
            if let url = navigationAction.request.url {
                
                if UIApplication.shared.canOpenURL(url) {
                    
                    //UIApplication.shared.open(url)
                    print(url)
                    parent.urlToOpenInSheet = url.absoluteString
                    print(self.parent.urlToOpenInSheet)
                    parent.activeSheet = true
                    
                   
                    decisionHandler(.cancel)
                } else {
                    decisionHandler(.allow)
                }
            }
        } else {
            //print("not a user click")
            decisionHandler(.allow)
        }
    }
    
    
}



}
Ad
source: stackoverflow.com
Ad