引擎盖下的网络浏览器的工作历史
Posted
技术标签:
【中文标题】引擎盖下的网络浏览器的工作历史【英文标题】:How work history of web browser under the hood 【发布时间】:2021-06-08 15:24:29 【问题描述】:我正在尝试在 ios 上为 WKWebView 实现我自己的 Web 浏览器历史记录,但我无法完全实现此功能,并且每次遇到麻烦。 我可以创建用户所在的历史,然后在历史中前后移动。 但是我遇到了下一个麻烦,我认为这只是我遇到的许多问题之一。 当我有例如 10 个元素的历史记录,然后我回到第 5 个元素,然后不要前进但尝试打开新链接,我无法删除元素 6-10 并放置新链接。
我认为我的问题是我无法完全理解历史在所有浏览器中的工作原理,这不是一项艰巨的任务,但我对这个算法感到困惑。 我保存历史的主要数据结构 帮助我了解如何在浏览器中使用此算法,或者是否存在一个很好的理论?
【问题讨论】:
我不太明白这个问题。如果有人在元素 5 并访问一个新页面,只需删除元素 6-10 并添加一个新元素 6。您可以使用链表或数组来做到这一点。 理论上这并不难,但是在实现的过程中,复杂性在增加。我不完全理解如何必须完成一个完整的历史算法。因此,当我在历史之间移动时遇到问题,当我想进入一个停留在历史中间的新页面时,我的历史会变得混乱。 我的意思是,不就是这样吗:返回:currentPosition--
,转发:currentPosition++
,访问新页面:history.remove(currentPosition + 1, history.length()); history.add(newPage); currentPosition++
? (这是伪代码,remove
删除给定索引之间的元素)。
我已经按照你的建议解决了这个问题,谢谢:) 目前所有算法都运行良好,等我完成所有任务,我会发布代码。
【参考方案1】:
我已经解决了这个问题并很好地实现了完整的算法,完成的项目在这里:https://github.com/IhorYachmenov/Custom-browser-history-for-WKWebView。
算法:
struct PlayerHistory
static var shared = PlayerHistory()
var historyExist: Bool = false
var historyCurrentPosition: Int = 0
var historyLastPositionBeforeUpdatingHistory: Int!
var userHistoryKey: String!
var backPressed: Bool!
var forwardPressed: Bool!
var urlOfPlayer: String!
// Function only for first loading inside <viewDidLoad or another method from app LifeCycle>.
mutating func getUrlForFirstLoading(initURL: String, key: String) -> String
urlOfPlayer = initURL
guard HistoryStorage.shared.getHistoryFromUserDefaults() != nil else
updateFirstElement(key: key, url: initURL)
return initURL
guard HistoryStorage.shared.getHistoryFromUserDefaults()![key] != nil else
return initURL
let position = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!.count - 1
historyExist = true
historyCurrentPosition = position
userHistoryKey = key
let initUrlFromHistoryStorage = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!.last!.url
return initUrlFromHistoryStorage
// Create new or update exist history, use this method indsede <decidePolicyForNavigation>.
mutating func updatePlayerHistory(backlisk: [String], key: String)
var history = [WebViewHistory]()
for i in backlisk
history.append(WebViewHistory(i))
if (historyExist == true)
// If old history exist need compound both and then to save.
let oldHistory = HistoryStorage.shared.getHistoryFromUserDefaults()![key]
let oldAndNewHostoryTogether = oldHistory! + history
var keyValuePair = Dictionary<String, [WebViewHistory]>()
keyValuePair.updateValue(oldAndNewHostoryTogether, forKey: key)
HistoryStorage.shared.removeHistory()
HistoryStorage.shared.saveHistory(keyValuePair)
setCurrentPosition(url: backlisk.last!, key: key)
else
var keyValuePair = Dictionary<String, [WebViewHistory]>()
keyValuePair.updateValue(history, forKey: key)
historyExist = true
HistoryStorage.shared.removeHistory()
HistoryStorage.shared.saveHistory(keyValuePair)
setCurrentPosition(url: backlisk.last!, key: key)
// Before using this method check if result don't equals nil. Use this method for navigation beetween history
func moveThroughHistory(key: String, direction: Bool) -> String?
guard historyExist != false else
return nil
let history = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!
if (direction == true)
let index = historyCurrentPosition + 1
guard index != history.count else return nil
return history[index].url
else
let index = historyCurrentPosition - 1
guard index > 0 else return history[0].url
return history[index].url
// Method <setCurrentPosition> each time set position at history
mutating func setCurrentPosition(url: String, key: String)
guard HistoryStorage.shared.getHistoryFromUserDefaults() != nil else return
guard HistoryStorage.shared.getHistoryFromUserDefaults()![key] != nil else return
let history = HistoryStorage.shared.getHistoryFromUserDefaults()![key]
let index = history?.firstIndex(of: WebViewHistory(url))
guard index != nil else
historyCurrentPosition = 0
return
historyCurrentPosition = index!
// <removeUnusedPeaceOfHistory> need use when user want open new page staying inside the middle of history
mutating func removeUnusedPeaceOfHistory(key: String)
guard HistoryStorage.shared.getHistoryFromUserDefaults() != nil else
return
guard HistoryStorage.shared.getHistoryFromUserDefaults()![key] != nil else
return
var history = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!
let startIndex = historyCurrentPosition + 1
let endIndex = history.endIndex - 1
let countOfAllElements = history.count
guard startIndex != countOfAllElements else return
let range = startIndex...endIndex
history.removeSubrange(range)
var keyValuePair = Dictionary<String, [WebViewHistory]>()
keyValuePair.updateValue(history, forKey: key)
HistoryStorage.shared.removeHistory()
HistoryStorage.shared.saveHistory(keyValuePair)
// Use <updateFirstElement> inside <getUrlForFirstLoading> if history doesn't exist
private mutating func updateFirstElement(key: String, url: String)
var history = [WebViewHistory]()
history.insert(WebViewHistory(url), at: 0)
var keyValuePair = Dictionary<String, [WebViewHistory]>()
keyValuePair.updateValue(history, forKey: key)
HistoryStorage.shared.saveHistory(keyValuePair)
historyExist = true
historyCurrentPosition = 0
// Use <webViewWillBeClosedSaveHistory> when WKWebView should be closed, if the user moves through history new position will be saved.
mutating func webViewWillBeClosedSaveHistory(key: String)
let history = HistoryStorage.shared.getHistoryFromUserDefaults()![key]!
let currentPosition = historyCurrentPosition + 1
guard currentPosition != history.count else return
removeUnusedPeaceOfHistory(key: key)
【讨论】:
以上是关于引擎盖下的网络浏览器的工作历史的主要内容,如果未能解决你的问题,请参考以下文章