FaviconFinder 是一个小型、纯 Swift 库,专为 iOS、macOS 和 Linux 应用程序设计,可帮助您检测网站使用的网站图标。
为什么不直接下载 https://site.com/favicon.ico
上的文件呢?开发者可以放置网站图标的位置有很多,不仅仅是在根目录下使用特定的文件名 favicon.ico
。网站图标的地址可能链接在 HTML 头部标签中,或者可能在 Web 应用程序清单 JSON 文件中,甚至可能是一个具有自定义文件名的文件。
FaviconFinder 为您处理这些繁琐的工作,并遍历所有可能的网站图标位置,一旦找到,就会简单地将图像交付给您。
FaviconFinder 将会
https://subdomain.site.com/favicon.ico
失败,将检查 https://site.com/favicon.ico
)。checkForMetaRefreshRedirect
设置为 true,FaviconFinder 将分析 HTML 中是否有 meta refresh 重定向标签。如果找到此类标签,则标签中的 URL 将是要查询的 URL。FaviconFinder 使用简单的语法,让您可以轻松下载所需的网站图标,并继续您的项目。只需将此代码插入您的项目中即可。
let favicon = try await FaviconFinder(url: url)
.fetchFaviconURLs()
.download()
.largest()
self.imageView.image = favicon.image
FaviconFinder 将遍历网站图标可能存在的各种来源,并确保检查每个来源。目前,来源包括
一旦 FaviconFinder 找到特定来源的所有可用网站图标,它将返回一个 FaviconURL
数组。FaviconURL
将包含图像的源 URL,以及从其提取图像的位置存在的其他元数据(即,相关的 HTML 标签等)。
在 FaviconURL
数组上,您可以调用 download()
,它将下载每个 FaviconURL
并将您的数组转换为 Favicon
数组。Favicon
包含图像、其原始数据和 FaviconURL
属性。
在 Favicon
数组上,您可以调用
first()
largest()
smallest()
FaviconFinder 适用于 UIKit、SwiftUI、AppKit 和 macOS Catalyst。
FaviconFinder 还支持 Linux 平台,并且我重新实现了 FaviconFinder 的部分内容,以确保 Linux 被视为一流平台。重要的是要注意,Linux 上的 Swift 本身不支持任何 Image
格式,因此当您调用 download 时,只会下载 data
本身,而没有图像类型可以将数据转换为该类型。 также из-за этого,largest()
和 smallest()
在 Linux 上无效。
FaviconFinder 通过自动搜索网站图标可以定义的各种位置,简化了定位和检索网站图标的过程。由于网站图标可能存在于多个位置,FaviconFinder 会系统地查询每个潜在来源,并遵循您可以自定义的优先级顺序。
主要步骤
HTML 标头查询和解析
FaviconFinder 首先查询您提供的 URL。然后,它检查网页的 HTML,并在下载的 HTML 文件的标头中查找 <link>
或 <meta>
标签中的任何网站图标声明。这可以包括指定为标准图标的网站图标 (<link rel="icon">
)、Apple touch 图标 (<link rel="apple-touch-icon">
) 或在 Open Graph 元数据中定义的其他图标。
回退到网站图标文件
如果在 HTML 中未找到网站图标,FaviconFinder 将检查域根目录中的传统网站图标位置 (https://site.com/favicon.ico)。这是许多网站放置其网站图标的默认位置,因此此检查是一种快速有效的回退方法。如果在此处找不到,FaviconFinder 将检查提供的 URL 是否为子域(即 https://example.site.com),如果是,将查询根域(即 https://site.com)。
回退到 Web 应用程序清单文件
对于使用 Web 应用程序清单 (manifest.json) 的站点,FaviconFinder 会解析 JSON 文件,以查找专门为渐进式 Web 应用程序定义的任何图标。这些图标通常在移动优化的网站或应用程序中找到,并提供更高分辨率的网站图标。
Meta-Refresh 重定向(可选)
某些网站可能使用 meta-refresh 重定向而不是服务器端 HTTP 重定向。如果在配置中启用,FaviconFinder 将检查 HTML 中是否存在这些 meta-refresh 重定向,并跟随它们以从重定向的 URL 检索网站图标。
网站图标大小排序
FaviconFinder 从 HTML 或 Web 应用程序清单中提取大小元数据,以按尺寸(例如,120x120、32x32)对网站图标进行排序。这使您可以轻松确定最大或最小的网站图标,而无需下载每个图像,从而节省带宽并提高性能。
自定义和偏好设置
FaviconFinder 允许您自定义其搜索网站图标的方式。您可以优先考虑某些网站图标类型(例如,Apple touch 图标、.ico 文件),甚至可以为身份验证提供预取 HTML 或自定义 HTTP 标头,从而使您可以完全控制库与站点的交互方式。
跨平台兼容性
FaviconFinder 旨在跨 macOS、iOS 和 Linux 工作。它会根据平台调整其方法,因此无论您是在 SwiftUI、UIKit 还是 AppKit 中工作,都可以无缝使用它。在 Linux 上,即使平台缺少本机图像处理功能,FaviconFinder 也能确保兼容性,而是使用数据驱动的方法。
虽然此自述文件提供了 FaviconFinder 的基本概述、如何使用它以及它可以做什么,但更全面的文档可以在这里找到
https://will-lumley.github.io/FaviconFinder/documentation/faviconfinder/
如果您想要精细控制要查找的网站图标类型,FaviconFinder 可以让您轻松指定您的偏好。您可以选择您希望首先查询哪个网站图标来源 - 无论是 HTML、实际文件还是 Web 应用程序清单文件 - 甚至可以为每个来源指定您想要的网站图标类型。
例如,您可能更喜欢在 HTML 标头中声明的网站图标,并且特别想要 appleTouchIcon 类型。FaviconFinder 将在 HTML 中搜索该特定标签,但如果未找到,它将自动搜索其他 HTML 网站图标类型。
如果指定的下载类型(例如,HTML 或 .ico)不可用,FaviconFinder 将自动尝试其他可用方法,如果找不到任何方法,它将返回错误。
您还可以请求 FaviconFinder 检查 HTML 中的 meta-refresh 重定向,使其能够跟随任何重定向并查询正确的 URL。
以下是如何配置您的偏好的示例
let favicon = try await FaviconFinder(
url: url,
configuration: .init(
preferredSource: .html,
preferences: [
.html: FaviconFormatType.appleTouchIcon.rawValue,
.ico: "favicon.ico",
.webApplicationManifestFile: FaviconFormatType.launcherIcon4x.rawValue
]
)
)
.fetchFaviconURLs()
.download()
.largest()
self.imageView.image = favicon.image
这允许您控制
如果您的首选下载类型在 URL 上不可用(例如,没有文件或没有 HTML 标签指定网站图标),FaviconFinder 将尝试其他来源,直到找到有效的网站图标或返回错误。
当站点从 oldsite.com 移动到 newsite.com 时,常见的做法是让 oldsite.com 响应 HTTP 301 重定向,以及要重定向到的 URL。在此示例中,URLSession
(以及扩展的大多数获取网站图标的库)将在收到 HTTP 301 重定向后,本机重新请求 newsite.com。
然而,还有一种不太常用(坦率地说较差)的重定向方法 - 它称为 meta-refresh 重定向。
这类似于 HTTP 301 重定向,只是它发生在前端,并且浏览器应该读取和解析 HTML,并以这种方式将用户发送到新的 URL。当 URLSession
遇到指向包含 meta-refresh 重定向的 HTML 文件的 HTTP 请求时,什么也不会发生。
但是,使用 FaviconFinder
,您很幸运。如果您在配置中将其设置为这样做,FaviconFinder
将扫描您提供给它的 URL 中的 HTML,以查找任何 meta-refresh 重定向,以确保如果遇到 meta-refresh 重定向,您不必担心它。
但重要的是要注意,解析和检查此项可能会花费额外的计算时间,因此默认情况下它设置为关闭。
以下是如何使用它。
let favicon = try await FaviconFinder(
url: url,
configuration: .init(
preferredSource: .html,
preferences: [
.html: FaviconFormatType.appleTouchIcon.rawValue,
.ico: "favicon.ico",
.webApplicationManifestFile: FaviconFormatType.launcherIcon4x.rawValue
],
checkForMetaRefreshRedirect: true
)
)
.fetchFaviconURLs()
.download()
.largest()
self.imageView.image = favicon.image
FaviconFinder 允许您传递预取的 HTML 文档,以避免多次下载 HTML,或者如果您已经从其他来源获得 HTML 内容。您可以使用配置中的 prefetchedHTML 属性来传递此文档。
我们使用 SwiftSoup 的 Document 类型,因为它具有出色的 HTML 存储和解析功能,可以轻松地操作和遍历文档树。
此功能在以下情况下很有用
以下是如何使用它
import SwiftSoup
// Assuming you have already fetched and parsed the HTML
let htmlString = "<html><head>...</head></html>"
let document = try SwiftSoup.parse(htmlString)
let favicon = try await FaviconFinder(
url: url,
configuration: .init(prefetchedHTML: document)
)
.fetchFaviconURLs()
.download()
.largest()
self.imageView.image = favicon.image
在某些情况下,网站图标可能存储在身份验证层之后,或者需要自定义 HTTP 标头才能访问,例如 API 令牌或用户会话的 Cookie。FaviconFinder 支持使用自定义 HTTP 标头查询网站图标,即使它们需要身份验证,您也可以获取网站图标。
要指定自定义 HTTP 标头,您可以在初始化 FaviconFinder 时在 Configuration 对象中传递它们。这些标头将与 FaviconFinder 发出的每个 HTTP 请求一起发送,从而确保即使网站图标位于身份验证层之后也可以访问。
以下是如何设置使用自定义 HTTP 标头来访问需要身份验证的网站图标的请求的示例(例如,使用 bearer 令牌)
let headers = [
"Authorization": "Bearer your_token_here",
"Cookie": "session_id=your_session_id_here"
]
let favicon = try await FaviconFinder(
url: url,
configuration: .init(
httpHeaders: headers
)
)
.fetchFaviconURLs()
.download()
.largest()
self.imageView.image = favicon.image
通过提供自定义 HTTP 标头,您可以处理更高级的场景,其中网站图标受到限制或受安全层保护,从而确保 FaviconFinder 在各种环境中保持灵活性和功能性。
FaviconFinder 包含允许您确定可用最大或最小网站图标的功能,而无需首先下载所有图像。当您只需要基于大小元数据的最大或最小图像时,这对于优化性能非常有用。
通过检查 HTML 或 Web 应用程序清单文件中提供的大小标签,FaviconFinder 可以对可用的网站图标 URL 进行排序,并选择尺寸最大或最小的 URL。
要在不下载图像的情况下找到最大或最小的网站图标 URL
let faviconURL = try await FaviconFinder(url: url)
.fetchFaviconURLs()
.largest() // or .smallest()
print("Largest Favicon URL: \(faviconURL.source)")
这将根据大小标签中的元数据返回最大或最小的网站图标。
一旦您确定了最大或最小的网站图标 URL,您就可以继续下载实际图像
let largestFavicon = try await FaviconFinder(url: url)
.fetchFaviconURLs()
.largest()
.download()
self.imageView.image = largestFavicon.image
使用此方法有优点和缺点。
优点
局限性
此功能使您可以有效地按大小对网站图标 URL 进行排序,并仅下载您需要的网站图标,使其成为以优化方式处理网站图标的强大工具。
有时您可能想要从 URL 获取标头或 Hero 图像。您可以使用配置中的 acceptHeaderImage
参数告知 FaviconFinder 您希望它执行此操作。默认值设置为 false
,此参数是可选参数。
您可以像这样使用它
let favicon = try await FaviconFinder(
url: url,
configuration: .init(acceptHeaderImage: true)
)
.fetchFaviconURLs()
.download()
.largest()
要运行示例项目,请克隆 repo,然后在 iOSFaviconFinderExample
或 macOSFaviconFinderExample
中打开示例 Xcode 项目,具体取决于您的构建目标。
或者,如果您将其用于 Linux 项目,则可以打开位于 LinuxFaviconFinderExample
中的示例 Swift 项目。
FaviconFinder 现在使用 Swift 6.0 编写。这意味着我们可以使用 Swift Testing
而不是 XCTest
,但更重要的是,这意味着 FaviconFinder 现在是数据竞争安全的,并遵守严格的并发性。
Swift 6.0 从 5.1.0
及更高版本开始支持。如果您需要在 Swift 5.9 及更低版本中使用 FaviconFinder,请使用版本 5.0.4
。
FaviconFinder 现在支持 await/async 并发,如下面的示例所示。因此,最新版本的 FaviconFinder 需要 iOS 15.0 和 macOS 12.0。如果您需要支持旧版本的 iOS 或 macOS,FaviconFinder 的版本 3.3.0
使用闭包来回调成功/失败,而不是 await/async 并发。
FaviconFinder 可通过 Swift Package Manager 获得。要安装它,只需将依赖项添加到您的 Package.Swift 文件中
...
dependencies: [
.package(url: "https://github.com/will-lumley/FaviconFinder.git", from: "5.1.4"),
],
targets: [
.target( name: "YourTarget", dependencies: ["FaviconFinder"]),
]
...
FaviconFinder 以前可以通过 CocoaPods 和 Carthage 获得,但是使该库可用于所有三个平台(Cocoapods、Carthage 和 SPM)并在这三个平台上都能正常工作变得很麻烦。再加上 SPM 的采用率和功能显着提升,这导致我取消了对 CocoaPods 和 Carthage 的支持。
William Lumley, will@lumley.io
FaviconFinder 在 MIT 许可证下可用。有关更多信息,请参阅 LICENSE 文件。