【问题标题】:How to clear the WKBackForwardList of a WKWebView?如何清除 WKWebView 的 WKBackForwardList?
【发布时间】:2017-09-07 01:51:49
【问题描述】:

WKWebView 的backForwardList 似乎是只读的,但我见过人们用一些非常神奇的东西来解决这个问题。我需要想办法清除 WKWebView 的历史记录。任何想法我怎么可能这样?到目前为止,我尝试了一些失败的技巧:

  • 使用 keyValue:forKey 无效。
  • 使用 C 指针 -> 不起作用。

我看到人们谈论合成属性和扩展类,但我真的不知道它是如何工作的,也无法弄清楚。还有其他想法吗?

【问题讨论】:

  • 你可以尝试实现你自己的存储...WKBackForwardList是不可变的
  • 如何使用:allowsBackForwardNavigationGesturescanGoBackcanGoForward?还是你特别需要清除backForwardList
  • @nyg 我需要清除历史记录,而不仅仅是防止滑动。

标签: ios objective-c swift wkwebview


【解决方案1】:

在 iOS8 ~ iOS11 上写的。

目标-C

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[wek.backForwardList performSelector:NSSelectorFromString(@"_removeAllItems")];
#pragma clang diagnostic pop

斯威夫特 4

webView.backForwardList.perform(Selector(("_removeAllItems")))

!!!!注意!!!!这个方法是在 WebKit 开放资源中声明的,不是公共方法。

【讨论】:

  • “declear”是什么意思,其次,你从哪里知道如何做到这一点的?
  • @Chet 它是“声明的”。拼写错误。在 WebKit 开放资源中查找
  • 徐彤的解决方案会被苹果接受吗?有没有因此被拒绝?
  • 肯定会因为使用这种方法而被拒绝。很简单,WKBackForwardList api doc中没有列出,所以是private api。当 Apple 决定在未来版本的 iOS 中更改该签名时,这是解决问题并产生崩溃的一种非常糟糕的方法。
  • 这意味着它现在正在工作,但它不是一个记录的方法,所以你不应该使用它,因为它可能会在没有警告的情况下消失。
【解决方案2】:

这段代码可以编译,但我没有测试过...

首先,我将WKWebView 子类化为我自己的WKBackForwardList 子类覆盖backForwardList

然后,在我的 WKBackForwardList 子类中,我可以覆盖 backItemforwardItem 以使它们返回 nil,而不是让它们查看各自的列表(这很可能是默认实现)。

或者我可以覆盖backListforwardList,就像在WKWebView 中使用backForwardList 一样。我这样做是为了添加一个 setter,这将允许我从列表中删除项目。

import Foundation
import WebKit

class WebViewHistory: WKBackForwardList {

    /* Solution 1: return nil, discarding what is in backList & forwardList */

    override var backItem: WKBackForwardListItem? {
        return nil
    }

    override var forwardItem: WKBackForwardListItem? {
        return nil
    }

    /* Solution 2: override backList and forwardList to add a setter */

    var myBackList = [WKBackForwardListItem]()

    override var backList: [WKBackForwardListItem] {
        get {
            return myBackList
        }
        set(list) {
            myBackList = list
        }
    }

    func clearBackList() {
        backList.removeAll()
    }
}

class WebView: WKWebView {

    var history: WebViewHistory

    override var backForwardList: WebViewHistory {
        return history
    }

    init(frame: CGRect, configuration: WKWebViewConfiguration, history: WebViewHistory) {
        self.history = history
        super.init(frame: frame, configuration: configuration)
    }

    /* Not sure about the best way to handle this part, it was just required for the code to compile... */

    required init?(coder: NSCoder) {

        if let history = coder.decodeObject(forKey: "history") as? WebViewHistory {
            self.history = history
        }
        else {
            history = WebViewHistory()
        }

        super.init(coder: coder)
    }

    override func encode(with aCoder: NSCoder) {
        super.encode(with: aCoder)
        aCoder.encode(history, forKey: "history")
    }
}

【讨论】:

  • 感谢您的帮助!试图弄清楚如何将其转换为 Objective C 并集成到这个插件中:github.com/apache/cordova-plugin-wkwebview-engine/blob/master/…
  • 这是我的尝试——不过似乎不起作用。 github.com/ccorcos/cordova-plugin-wkwebview-engine/commit/… 再说一次,无论如何我都不是 Objective C 专家……
  • backForwardList 在导航期间永远不会改变。它在我的应用程序中仍然是空的。怎么了?
  • 不幸的是,这个绝妙的想法行不通。 backList 似乎只是一个派生属性,因此 WebKit 内部不使用它来存储实际访问的项目。
  • 确实不行。一种解决方法是创建一个新的 WKWebView 并传递旧配置。
【解决方案3】:

因为 Apple 将 WKBackForwardList 的界面严格锁定,并且对不使用 published public interfaces 的开发人员非常严格,所以您有两种选择:

  1. 最简单的方法(当然也是 Apple 的意图)是创建一个新的 WKWebView 并用它替换您当前的。这不是一个很难实现的解决方案,因为您可能必须从旧实例复制到新实例的配置数量非常有限。您甚至可以创建一个包装器视图来为您执行此操作,这样您只需调用 clearHistory() 并且包装器视图将为您执行底层交换。

  2. 如果由于某种原因您无法替换 WKWebView 的实例,您可以利用历史记录的一维特性将历史记录减少到两项。恐怕你不能把它清除得更远。要将 URL 清除为两个 URL,假设它们存储在值 urlA 和 urlB 中,您可以这样做:

// At initialization, ensure that urlA is the first item in the history
let webview = WKWebView()
// ... whatever other init you need
webview.load(URLRequest(url: urlA))

然后“清除”历史记录:

func clearHistory() {
    // First we make sure the webview is on the earliest item in the history
    if webview.canGoBack {
        webview.go(to: webview.backForwardList.backList.first)
    }
    // Then we navigate to our urlB so that we destroy the old "forward" stack
    webview.load(URLRequest(url: urlB))
} 

【讨论】:

    【解决方案4】:

    阅读文档,您可以获得 WKWebView 的 WKBackForwardList。 之后,您可以在 WKBackForwardList 的 backList 中找到第一项,然后使用: func go(to: WKBackForwardListItem) -> WKNavigation? 有了这个,您可以将历史记录清理到第一个 url。

    【讨论】:

      猜你喜欢
      • 2016-01-18
      • 1970-01-01
      • 2020-02-08
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 2015-09-26
      • 1970-01-01
      相关资源
      最近更新 更多