通过JavaScript事件观察WKWebView URL更改的问题 [英] Issue with observing WKWebView URL changes via JavaScript events

查看:74
本文介绍了通过JavaScript事件观察WKWebView URL更改的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个WKWebView,它显示一个 Laravel Web应用程序.目前,我有ViewController设置来捕获URL更改-它可以捕获大多数更改.但是,通过WKWebView似乎忽略的JavaScript事件进行的URL更改很少.

I have a WKWebView that presents a Laravel web application. I currently have my ViewController setup to catch URL changes – and it catches most of them. However, there are a small number of URL changes that are made via JavaScript events that WKWebView seems to ignore.

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

I have tried all of the following solutions and implemented them in the code below:

  • How to detect hash changes in WKWebView?
  • How can I detect when url of amp page changed with WKWebview
  • WKWebView function for detecting if the URL has changed
  • How can I detect when url of amp page changed with WKWebview
  • using KVO to observe WKWebView's URL property not work in iOS 10

在我展示代码之前,一个有趣的注释:它能够检测到简单的#hash更改,但是无法检测到从第1页加载到第2页的JavaScript事件操作(这是我尝试进行的URL更改)捕获):

An interesting note before I present the code: it is able to detect simple #hash changes, but is unable to detect a JavaScript event action that loads from page 1 to page 2 (this is the URL change I'm attempting to catch):

https://myweb.com/dashboardhttps://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).

There is one single piece of code that seems to fire on the JavaScript event action, and that is keyPath == #keyPath(WKWebView.url).

但是,它似乎只是触发了它,以及它在控制台上显示的结果:URL Change 2: # No value provided(由于nil合并运算符:self.webView.url?.absoluteString ?? "# No value provided"的结果.

However, it only seems to fire just that, as well as its resulting print to console: URL Change 2: # No value provided (as a consequence of the nil coalescing operator: self.webView.url?.absoluteString ?? "# No value provided".

这意味着,只有两行观察者代码可以捕获此更改,但不会返回该更改的值:

Meaning, these 2 lines of observer code are the only things that catch this change, but do not return the value of that change:

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

if keyPath == #keyPath(WKWebView.url) {
    print("URL Change 2:", self.webView.url?.absoluteString ?? "# No value provided")
}

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

Any other attempt made to retrieve this changed value, or force unwrap it, results in a crash on launch immediately after didStartProvisionalNavigation is called:

Xcode错误

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

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欺骗)无关.

How am I able to output the value of that URL change? Again, it seems to be the only code that fires when I click the JS button to load the page (or at least, so says the console). In Safari, for both iOS and MacOS, the URL change does seem to reflect in the URL Search bar; thus, I don't believe this is an issue having to do with the web-based code (ie. frames, URL spoofing).

但是,由于它是基于Web的PHP/JS脚本,因此我无法确认.

However, I cannot confirm this as it is a web-based PHP/JS script.

看来,当第一次在WKWebView中加载https://myweb.com时,该代码也没有检测到对https://myweb.com/dashboard的初始重定向.上面提到的只有两条观察者行似乎可以检测到这种重定向.

It appears that, when first loading https://myweb.com in the WKWebView, the code also does not detect the initial redirect to https://myweb.com/dashboard. Only the two observer lines, mentioned above, seem to detect this redirect.

我能够使用ObserverValue函数代码将确切的URL值打印到控制台上:

I am able to get the exact URL value printed to the console with the observerValue function code:

if let key = change?[NSKeyValueChangeKey.newKey] {
    print("URL: \(key)") // url value
}

但是,我无法将其强制转换为字符串,将值分配给变量或将其传递给其他函数.有什么办法可以将此键设置为.contains("https://")的变量?启动时,键值= 0,但之后,该值=所需的URL(https://myweb.com/dashboardhttps://myweb.com/dashboard/project/new).

However, I am unable to cast it as a String, assign the value to a variable or pass it to another function otherwise. Is there any way to set this key as a variable if it .contains("https://")? On launch, the key value = 0, but after that, the value = the desired URL (https://myweb.com/dashboard and https://myweb.com/dashboard/project/new).

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

This solution uses older KVO methods to achieve the same result as @Rudedog, but with much more baggage (ie. you still need to remove the observer and handle independent key paths). See @Rudedog's answer below for a more modern solution.

我能够将KVO WKWebView.url分配给String变量.从那里,我能够将String值传递给一个函数,该函数然后处理要查找的每个输出:

I was able to assign the KVO WKWebView.url to a String variable. From there, I was able to pass the String value to a function that then handles each output I'm looking for:

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观察方法:

Before you go any further, I would strongly recommend that you use the modern Swift method of observing:

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.
  }
}

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

Doing this makes your code much cleaner and easier to reason about while you're debugging the issue.

这篇关于通过JavaScript事件观察WKWebView URL更改的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆