【问题标题】:WKWebView. didStartProvisionalNavigation not calledWKWeb 视图。未调用 didStartProvisionalNavigation
【发布时间】:2016-11-21 14:25:03
【问题描述】:

我在我的应用程序中使用WKWebView,一切正常,直到用户转到money.cnn.com。对于该站点的主页,一切都很好,但是当用户离开主页并转到例如http://money.cnn.com/2016/11/21/news/dubai-trump-golf-course-developer/index.html?iid=hp-toplead-intl 或该站点上的任何其他页面时,不会调用委托方法didStartProvisionalNavigationdidCommitNavigation。但我需要这些方法来检测导航的开始。 decidePolicyForNavigationAction 一开始就被调用了,但是被调用了多次,我觉得使用这种方法并不是一个完美的解决方案。所以我的问题是:在这种情况下我该怎么办?在那个站点有什么特别的东西不能让WKWebView 调用它的委托方法,在这种情况下什么可能是一个可靠的解决方案?谢谢

【问题讨论】:

    标签: ios swift webkit wkwebview


    【解决方案1】:

    我不是很了解 web 开发,但在我看来,money.cnn.com 网站的 JavaScript 有问题。似乎站点页面之间的转换及其加载是在 JavaScript 的帮助下进行的。该 JavaScript 与本机 WKWebView 处理程序冲突。

    但是!您可以在页面开头使用处理程序注入您自己的 JavaScript。当页面开始打开时,脚本将首先运行。

    详情

    • Xcode 版本 10.2.1 (10E1001),Swift 5

    完整示例代码

    import UIKit
    import WebKit
    
    class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
    
        private weak var webView: WKWebView?
        private lazy var scriptName = "GetUrl"
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupWebView()
            loadUrl(string: "http://money.cnn.com/2016/11/21/news/dubai-trump-golf-course-developer/index.html?iid=hp-toplead-intl")
        }
    
        func setupWebView() {
            let contentController = WKUserContentController();
            let script = "webkit.messageHandlers.\(scriptName).postMessage(document.URL)"
            let userScript = WKUserScript(source: script, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: true)
            contentController.addUserScript(userScript)
            contentController.add(self, name: scriptName)
    
            let config = WKWebViewConfiguration()
            config.userContentController = contentController
    
            let webView = WKWebView(frame:  UIScreen.main.bounds, configuration: config)
            webView.navigationDelegate = self
            view.addSubview(webView)
            self.webView = webView
        }
    
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            if message.name == scriptName {
                guard let url = message.body as? String else { return }
                if url.contains("http://money.cnn.com/") {
                    print("!!! \(url)")
                } else {
                    print("??? \(url)")
                }
            }
        }
    
        func loadUrl(string: String) {
            guard   let url = URL(string: string),
                    let webView = self.webView else { return }
            webView.load(URLRequest(url: url))
        }
    }
    

    Info.plist

    添加 Info.plist 传输安全设置

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
    

    结果

    更多

    Call JavaScript function from native code in WKWebView

    【讨论】:

    • 感谢您的帮助,但它不起作用。如果我按照您的示例的方式使用它,它就会起作用 - 显式加载请求。它适用于网站的主页。但是,当我从 money.cnn.com 转到 money.cnn.com/2016/11/21/news/dubai-trump-golf-course-developer/… 或任何其他子页面时,不会调用委托方法。我唯一能做的就是将 false 传递给 forMainFrameOnly 然后它也可以工作,但它会导致过于频繁地调用委托方法来加载页面上的每个资源
    • 这很奇怪。我做了小修复并添加了控制台的屏幕截图。看一看。在我的示例中,在显示每个页面之前触发脚本。
    • 从头开始创建了一个新项目,并在那里复制粘贴了您的代码。仅适用于第一页,即显式调用加载时。如果我进一步浏览 userContentController didReceive 消息方法永远不会被调用)))
    • 在 func userContentController() 中,我们只检测到 money.cnn.com 页面(编辑此函数以显示所有 url)。你可能会打开另一个 cnn 网站吗?
    • 不,方法本身没有被调用。我当然检查了
    【解决方案2】:

    将委托设置为:

    webView.navigationDelegate = self
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-24
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多