WKWeb 视图。未调用 didStartProvisionalNavigation

Posted

技术标签:

【中文标题】WKWeb 视图。未调用 didStartProvisionalNavigation【英文标题】:WKWebView. didStartProvisionalNavigation not called 【发布时间】: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 调用它的委托方法,在这种情况下什么可能是一个可靠的解决方案?谢谢

【问题讨论】:

【参考方案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

【讨论】:

以上是关于WKWeb 视图。未调用 didStartProvisionalNavigation的主要内容,如果未能解决你的问题,请参考以下文章

未调用 iphone 视图控制器方法但视图显示

关闭模式视图时未调用 onDisappear

MVC:编辑操作未调用编辑视图

自定义视图中未调用 UIButton 操作

正在启动视图,但未调用 drawRect:

表视图控制器未调用 didSelectRowAtIndexPath