Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I try to catch the url about to load in WKWebView before it loads. Based on documents
decidePolicyFor navigationAction
(WKNavigationDelegate) should do the job but my problem is this delegate gets called after new url get loaded not before that.
here is the extension I wrote.
extension MyWebViewController: WKNavigationDelegate {
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let navigationURL = navigationAction.request.url else {
decisionHandler(.allow)
return
let forbiddenUrlPattern = Configuration.current.links.forbiddenUrlPattern
if forbiddenUrlPattern.matches(url: navigationURL) {
decisionHandler(.cancel)
showFullScreenError(error: .forbidden)
return
// Default policy is to allow navigation to any links the subclass doesn't know about
decisionHandler(.allow)
*PS the matches extension checks the pattern and it works fine.
now the problem is that the content of forbiddenUrl showed for a time before this delegate func gets called and then the error page comes to screen, and if I close it the last visible webPage is from forbidden link pattern.
is there any way to understand about the link before actually loading it in webView?
I am using Xcode 11.2.1 & Swift 5.0
–
–
–
–
–
I wrote the answer I found here that it may help someone else as well.
After lots of struggle I found out decisionHandler
wont get called if the url is relative (not absolute urls).
So why decisionHandler
got called after loading that page?
the answer I found is: when we have urls like href:"/foo/ba"
then after calling that url, it will load and resolve as www.domain.com/foo/ba
and only then desicionHandler
got called.
Also didCommit
only called once when I wanted to load the url for the first time in webView.
so the solution helped me was to add an observer to webView
webView.addObserver(self, forKeyPath: "URL", options: [.new,.old], context: nil)
override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
/// This observer is in addition to the navigationAction delegate to block relative urls and intrrupt them and do native
/// action if possible.
if let newValue = change?[.newKey] as? URL, let oldValue = change?[.oldKey] as? URL, newValue != oldValue {
let forbiddenUrlPattern = Configuration.current.links.forbiddenUrlPattern
if forbiddenUrlPattern.matches(url: newValue) {
showFullScreenError(error: .forbidden)
return
/// These two action needed to cancel the webView loading the offerDetail page.
/// otherwise as we stop loading the about to start process webView will show blank page.
webView.stopLoading()
///This is small extension for make webView go one step back
webView.handleBackAction(sender: newValue)
return
So this observer in addition to decisionHandler
would cover both absolute and relative urls any one wants to listen and take action if needed.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.