【问题标题】:WKWebView decidePolicyFor gets called after page loadedWKWebView 决定策略在页面加载后被调用
【发布时间】:2020-08-13 17:04:41
【问题描述】:

我尝试在 WKWebView 加载之前捕获即将加载的 url。基于文档decidePolicyFor navigationAction (WKNavigationDelegate) 应该可以完成这项工作,但我的问题是在加载新 url 之后而不是在此之前调用这个委托。

这是我写的扩展。

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 匹配扩展检查模式并且工作正常。 现在的问题是,在调用此委托函数之前,forbiddenUrl 的内容显示了一段时间,然后错误页面出现在屏幕上,如果我关闭它,最后一个可见的网页来自禁止链接模式。

在将链接实际加载到 webView 之前,有什么方法可以了解链接吗?

我正在使用 Xcode 11.2.1 和 Swift 5.0

【问题讨论】:

  • 一些评论,因为它可能会以某种方式帮助您:我怀疑可能还有其他事情发生,可能与您正在使用的网页有关。我们在我们的应用程序中使用相同的模式(据我所知),对我们来说,如果满足.cancel 条件,则不会执行重定向,并且不会显示新内容。所以我可以确认这个设置,原则上,正如你最初预期的那样工作。另外(为了测试基本设置)如果您只是将decisionHandler(.cancel); return 放在委托函数中,如果您仍然可以看到任何内容加载,我会感到非常惊讶。祝你好运!
  • 您是否尝试过 webView didCommitNavigation 功能,因为它不能正常工作?您也可以尝试设置webView.isOpaque = falsewebView.backgroundColor = UIColor.clear,直到您确认该URL 未被禁止。
  • 提供更多细节。你加载哪个网址?什么是禁止的 URL 模式?您在加载的 URL 中单击哪个链接来体验错误?
  • 在这里工作正常。 Xcode 11.4 / iOS 13.4。所以我假设这是在其他代码中,或者过滤器不匹配所有 url。尝试在返回 .allow 大小写之前记录 url。如果您提供您使用的 URL 和应该过滤掉的 URL,则可以进行更深入的测试。
  • @Gamma 感谢您的评论,您是对的,网页有问题,因为所有网址都是相对的而不是绝对的,请参阅下面的回答。

标签: ios swift wkwebview


【解决方案1】:

我写了我在这里找到的答案,它也可以帮助其他人。 经过大量的努力,我发现decisionHandler 不会被调用,如果 url 是相对的(不是绝对的 url)。 那么为什么decisionHandler 在加载该页面后被调用呢? 我找到的答案是:当我们有像href:"/foo/ba" 这样的网址时,在调用该网址后,它将加载并解析为www.domain.com/foo/ba,然后才调用desicionHandler
当我想在 webView 中第一次加载 url 时,didCommit 也只调用了一次。

所以对我有帮助的解决方案是向 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
            }
        }
    }

因此,除了decisionHandler 之外,这个观察者将涵盖任何人想要收听的绝对和相对 url,并在需要时采取行动。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多