Before I begin it should be noted that part of my question is a duplicate of this post which doesn't have an accepted answer. Also, I have read several other SO posts that are similar to my question, but not exact, such as this and this.
Question:
I use a WKWebView for displaying text marked up in HTML. Some of the text contains links, which I want to be opened in Safari when tapped. I've gotten pretty far, but I'm still experiencing 2 major issues.
1) The WKWebView doesn't respond to the first tap of the session, i.e. the first link that is tapped has to be tapped twice for Safari to open. Any link tapping afterwards opens Safari immediately.
2) Safari only opens to the URL of the first link that is tapped. Let's say 3 URLs are being displayed: A, B, and C. If A is tapped first then tapping any of the other 2 URLs will always open Safari to A as long as that WKWebView is initialized. If B is tapped first, Safari will only open to B, etc.
Here is my Swift code that I think is most relevant to this question:
class CustomWebView: WKWebView, WKUIDelegate, WKNavigationDelegate {
convenience init() {
let config = WKWebViewConfiguration()
config.dataDetectorTypes = [.all]
self.init(frame: .zero, configuration: config)
navigationDelegate = self
uiDelegate = self
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (_: WKNavigationResponsePolicy) -> Void) {
decisionHandler(.allow)
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (_: WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
print("url: \(url)")
let paths = url.absoluteString.components(separatedBy: ",")
print("paths: \(paths)")
for path in paths {
if path.contains("link:") {
let link = path.replacingOccurrences(of: "link:", with: "").replacingOccurrences(of: "%22", with: "")
print("link: \(link)")
if let cleanedURL = URL(string: link) {
print("cleanedURL: \(cleanedURL)")
UIApplication.shared.open(cleanedURL, options: [:], completionHandler: nil)
decisionHandler(.cancel)
return
}
}
}
}
decisionHandler(.allow)
}
}
Here is some sample HTML that I'm testing:
<a href="https://www.bbc.com/">https://www.bbc.com/</a>
<div>
<br />
</div>
<div><a href="https://www.youtube.com/">https://www.youtube.com/</a>
<br />
</div>
<div>
<br />
</div>
<div><a href="https://stackoverflow.com/">https://stackoverflow.com/</a>
<br />
</div>
Here are what the print statements show:
Step 1
Tap link A:
url: callback://0/underline,justifyLeft,textColor
paths: ["callback://0/underline", "justifyLeft", "textColor"]
Step 2
Tap link A for a second time:
url: callback://0/underline,justifyLeft,textColor,link:https://www.bbc.com/
paths: ["callback://0/underline", "justifyLeft", "textColor", "link:https://www.bbc.com/"]
link: https://www.bbc.com/
cleanedURL: https://www.bbc.com/
Step 3
Tapping link A, B, or C after doing Step 2 gives the same print statements as Step 2.
Other notes:
The HTML is coming from ZSSRichTextEditor, which is implemented in another part of the app to let the user input marked up HTML. Sometimes when a user inputs a link the HTML that is spat out by the editor surrounds it in %22
, which is why I include removing it in the code above.