Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 通过JavaScript事件观察WKWebView URL更改的问题_Ios_Swift_Xcode_Macos_Wkwebview - Fatal编程技术网

Ios 通过JavaScript事件观察WKWebView URL更改的问题

Ios 通过JavaScript事件观察WKWebView URL更改的问题,ios,swift,xcode,macos,wkwebview,Ios,Swift,Xcode,Macos,Wkwebview,我有一个展示web应用程序的WKWebView。我目前有我的ViewController设置来捕获URL更改,并且它捕获了大部分更改。但是,WKWebView似乎忽略了通过JavaScript事件进行的少量URL更改 我已经尝试了以下所有解决方案,并在下面的代码中实现了它们: 在我介绍代码之前,有一个有趣的注意事项:它能够检测简单的散列更改,但无法检测从第1页加载到第2页的JavaScript事件操作(这是我试图捕获的URL更改): https://myweb.com/dashbo

我有一个展示web应用程序的WKWebView。我目前有我的ViewController设置来捕获URL更改,并且它捕获了大部分更改。但是,WKWebView似乎忽略了通过JavaScript事件进行的少量URL更改

我已经尝试了以下所有解决方案,并在下面的代码中实现了它们:

在我介绍代码之前,有一个有趣的注意事项:它能够检测简单的散列更改,但无法检测从第1页加载到第2页的JavaScript事件操作(这是我试图捕获的URL更改):

https://myweb.com/dashboard
→ <代码>https://myweb.com/dashboard/projects/new

ViewController.swift

import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

    @IBOutlet var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.navigationDelegate = self
        webView.uiDelegate = self

        webView.addObserver(self, forKeyPath: "URL", options: .new, context: nil)
        webView.addObserver(self, forKeyPath: #keyPath(WKWebView.url), options: .new, context: nil)

        webView.load(URLRequest(url: URL(string: "https://myweb.com/")!))
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if object as AnyObject? === webView && keyPath == "URL" {
            print("URL Change 1:", webView.url?.absoluteString ?? "No value provided")
        }
        if keyPath == #keyPath(WKWebView.url) {
            print("URL Change 2:", self.webView.url?.absoluteString ?? "# No value provided")
        }
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        let webURL = webView.url?.absoluteString
        let reqURL = navigationAction.request.url?.absoluteString
        print("webURL:", webURL)
        print("reqURL:", reqURL)
        decisionHandler(.allow)
    }

    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        let webURL = webView.url?.absoluteString
        print("webURL:", webURL)
    }
}
有一段代码似乎在JavaScript事件操作中触发,那就是
keyPath==#keyPath(WKWebView.url)

然而,它似乎只是触发了这一点,以及它在控制台上的打印:
URL更改2:#没有提供值
(由于nil合并操作符:
self.webView.URL?.absoluteString???#没有提供值

也就是说,这两行观察者代码是捕获此更改的唯一内容,但不会返回该更改的值:

webView.addObserver(self,forKeyPath:#keyPath(WKWebView.url),选项:。新建,上下文:nil)

在调用
didStartProvisionalNavigation
后,任何其他试图检索此更改的值或强制将其展开的尝试都会在启动时立即导致崩溃:

Xcode错误

线程1:致命错误:在展开可选值时意外发现nil

Xcode控制台日志

Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/me/Apps/MyWeb/iOS/MyWeb/ViewController.swift, line 125
2020-02-11 12:47:55.169765-0500 MyWeb[3066:124221] Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/me/Apps/MyWeb/iOS/MyWeb/ViewController.swift, line 125
(lldb) 

我怎样才能输出URL更改的值呢?同样,它似乎是我单击JS按钮加载页面时触发的唯一代码(或者至少控制台这么说)。在Safari中,对于iOS和MacOS,URL更改似乎确实反映在URL搜索栏中;因此,我认为这不是一个与基于web的代码(即框架、URL欺骗)有关的问题

但是,我无法确认这一点,因为它是一个基于web的PHP/JS脚本

编辑 当第一次加载
https://myweb.com
在WKWebView中,代码也不会检测到初始重定向到
https://myweb.com/dashboard
。只有上面提到的两条观察者行似乎检测到了此重定向

编辑2 我能够使用observerValue函数代码将准确的URL值打印到控制台:

if let key = change?[NSKeyValueChangeKey.newKey] {
    print("URL: \(key)") // url value
}
但是,我无法将其转换为字符串、将值分配给变量或以其他方式将其传递给另一个函数。如果此键
。包含(“https://”)
,是否有办法将其设置为变量?启动时,键值=
0
,但之后,值=所需的URL(
https://myweb.com/dashboard
https://myweb.com/dashboard/project/new


此解决方案使用较旧的KVO方法实现与@Rudedog相同的结果,但负担更重(即,您仍然需要删除观察者并处理独立的关键路径)。有关更现代的解决方案,请参阅下文@Rudedog的答案

编辑3(KVO解决方案) 我能够将KVO
WKWebView.url
分配给一个字符串变量。从那里,我能够将字符串值传递给一个函数,然后该函数处理我要查找的每个输出:

var cURL = ""

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let key = change?[NSKeyValueChangeKey.newKey] {
        cURL = "\(key)"         // Assign key-value to String
        print("cURL:", cURL)    // Print key-value
        cURLChange(url: cURL)   // Pass key-value to function
    }
}

func cURLChange(url: String) {
    if cURL.contains("/projects/new") {
        print("User launched new project view")
        // Do something
    } else {
        // Do something else
    }
}

在您继续之前,我强烈建议您使用现代的Swift观察方法:

var webViewURLObserver: NSKeyValueObservation?

override func viewDidLoad() {
  // ...
  webViewURLObserver = webview.observe(\.url, options: .new) { webview, change in 
    print("URL: \(String(describing: change.newValue))")
    // The webview parameter is the webview whose url changed
    // The change parameter is a NSKeyvalueObservedChange
    // n.b.: you don't have to deregister the observation; 
    // this is handled automatically when webViewURLObserver is dealloced.
  }
}

这样做可以在调试问题时使您的代码更清晰,更易于推理。

谢谢您提供的解决方案!我不知道有一种“现代”的观察方式。您的代码工作得很好,可以按预期检测URL更改。有没有办法让它调用函数,即
urlditchange()
,在值发生更改时?不管怎样,我都能通过以下操作完成:
webViewURLObserver=webView.observe(\.url,options:.new){webView,在let url=“\(String(description:change.newValue))”ViewController().urlChange(url:url)}
var webViewURLObserver: NSKeyValueObservation?

override func viewDidLoad() {
  // ...
  webViewURLObserver = webview.observe(\.url, options: .new) { webview, change in 
    print("URL: \(String(describing: change.newValue))")
    // The webview parameter is the webview whose url changed
    // The change parameter is a NSKeyvalueObservedChange
    // n.b.: you don't have to deregister the observation; 
    // this is handled automatically when webViewURLObserver is dealloced.
  }
}