从 WKWebView 获取 favicon.co

Posted

技术标签:

【中文标题】从 WKWebView 获取 favicon.co【英文标题】:get favicon.co from WKWebView 【发布时间】:2016-02-05 10:58:40 【问题描述】:

我正在为 OS X 和 ios 使用新的 wkWebView。为了将 webview 显示为图标,我需要显示的 URL 的图标。在旧的 webview 中,我可以使用以下功能:

var mainFrameIcon: NSImage!  get 

如何在 Swift 或 Objective-C 中使用 wkWebView 获取图像?

【问题讨论】:

【参考方案1】:

新的 WKWebView 类似乎没有任何内置的公共网站图标,但有一种简单的方法可以检索它。由于网站将 favicon url 存储在 /favicon.ico,因此您只需从 web 视图中获取主机 url,将 /favicon.ico 添加到末尾并将 url 作为 nsimage 获取

这样做:

NSURL *webpageURL = myWebView.URL;
NSString *hostURL = webpageURL.host;
NSString *faviconURL = [NSString stringWithFormat:@"http://%@/favicon.ico",hostURL];
NSImage *faviconImage = [[NSImage alloc] initWithContentsOfURL:[NSURL URLWithString:faviconURL]];

希望对你有帮助

【讨论】:

我对这种方法有点紧张。许多网站现在在其 html 中指定图标。此外,这种方法不使用 https。【参考方案2】:

就像这个帖子中的许多其他人所说的那样,找到一个网站图标不再是一件简单的事情。

因此,我开发了一个开源框架,可以为您完成繁重的工作。 https://github.com/will-lumley/FaviconFinder/

【讨论】:

【参考方案3】:

不幸的是,获取网站图标不再是一个简单的属性。原因是网站可以为不同的分辨率声明多个网站图标。您(应用程序开发人员)需要根据您的需要选择合适的图标。

另一个复杂的问题是您(应用程序开发人员)需要在 WKWebView 对象中执行 javascript 才能从链接标签中获取网站图标!

(注意:依赖 /favicon.ico 容易出错。有些网站不会更新其 CMS 的 /favicon.ico,而仅通过链接标签进行设置。在这种情况下,具有正确图标的页面Chrome 可能会在您的自定义浏览器中显示 Drupal 图标。)

这里是 Javascript 来解析链接标签,然后是 Swift 来进一步读取结果。

// Based on code from  https://***.com/questions/10282939/how-to-get-favicons-url-from-a-generic-webpage-in-javascript
static private var GET_FAVICON_SCRIPT = """
    var favicons = [];
    var nodeList = document.getElementsByTagName('link');
    for (var i = 0; i < nodeList.length; i++)
    
        if((nodeList[i].getAttribute('rel') == 'icon')||(nodeList[i].getAttribute('rel') == 'shortcut icon'))
        
            const node = nodeList[i];
            favicons.push(
                url: node.getAttribute('href'),
                sizes: node.getAttribute('sizes')
            );
        
    
    favicons;
"""

public private(set) var faviconUrls = Set<FaviconUrl>()

func updateFavicon() 
    self.webView.evaluateJavaScript(TabViewController.GET_FAVICON_SCRIPT)  (result, error) in
        // Favicon is returned from Javascript as an NSMutableArray with NSMutableDictionaries
        // Needs to be turned into a list
        var faviconUrls = Set<FaviconUrl>();

        // If the script returned correctly
        if let favicons = result as? NSArray 
            for faviconObject in favicons 
                if let faviconDictionary = faviconObject as? NSDictionary 
                    if let urlString = faviconDictionary["url"] as? String 
                        
                        // The favicon url (href in link tag) needs to be resolved to the url from the page
                        if let url = URL(string: urlString, relativeTo: self.webView.url) 
                            let sizesString = faviconDictionary["sizes"] as? String;
                            let sizeStrings = sizesString?.components(separatedBy: "x") ?? []
                            
                            if (sizeStrings.count == 2) 
                                let width = Int(sizeStrings[0])
                                let height = Int(sizeStrings[1])
                                faviconUrls.insert(FaviconUrl(url: url, width: width, height: height))
                             else 
                                faviconUrls.insert(FaviconUrl(url: url, width: nil, height: nil))
                            
                        
                    
                
            
        
        
        // If no favicons were found, fallback to /favicon.ico
        // Note that some sites never replace the one that comes with the CMS. If you don't
        // use Javascript to parse the <link ...> tags, a site that works correctly in Chrome
        // could have a Drupal icon in your application
        if faviconUrls.count == 0 
            if let webViewUrl = self.webView.url 
                let schemeAndHostUrl = webViewUrl.deletingPathExtension()
                let url = schemeAndHostUrl.appendingPathComponent("favicon.ico")
                faviconUrls.insert(FaviconUrl(url: url, width: nil, height: nil))
            
        
        
        if (faviconUrls != self.faviconUrls) 
            self.faviconUrls = faviconUrls
            self.delegate?.faviconChanged()
        
        
        if error != nil 
            NSLog("Can not determine favicons: %@", error?.localizedDescription ?? "")
        
    

为了完整起见,这里是 FaviconUrl 类:

import Cocoa

class FaviconUrl: NSObject 

    public private(set) var url: URL
    public private(set) var width: Int?
    public private(set) var height: Int?
    
    init(url: URL, width: Int?, height: Int?) 
        self.url = url
        self.width = width
        self.height = height
    
    
    public var area: Int? 
        get 
            if let width = self.width 
                if let height = self.height 
                    return width * height;
                
            
            
            return nil
        
    

【讨论】:

以上是关于从 WKWebView 获取 favicon.co的主要内容,如果未能解决你的问题,请参考以下文章

IOS - 如何从 WKWebView 获取缓存的资源?

如何从 WKWebView 启用和获取 cookie?

如何从 WKWebView 获取 cookie?

使用 evaluateJavaScript 从 WKWebView 获取标题

从WkWebView获取JSON

WKWebView 没有从 language.url 获取正确的语言字符串