【问题标题】:How to know what's blocked by WKContentRuleList如何知道 WKContentRuleList 阻止了什么
【发布时间】:2020-07-14 09:35:41
【问题描述】:

正如我们所知,我们可以使用 WKContentRuleList 来阻止 url 请求/cookie 或在 WKWebView 中执行其他操作。有没有什么方法可以根据 WKContentRuleList 知道 WKWebView 阻止了什么?

【问题讨论】:

    标签: ios wkwebview safari-content-blocker


    【解决方案1】:

    我有一定程度的把握,没有一种简单的方法可以仅使用公共 API 检索此信息。因此,我已经为我的目的整理了一个“足够好”的解决方案的 javascript 解决方案。它尝试从解析的 html 中提取资源,然后将它们与从 window.performance 模块获得的加载资源进行比较。主要的警告是,有些资源类型根本没有被处理,而有些则可能被遗漏了。

    显然,它应该在页面完全加载它要加载的内容后调用。通常,这将通过“webViewDidFinishNavigation”委托方法完成。提供的完成参数是闭包,它以被阻塞资源的数组作为单个参数调用。

    这第一部分是构建 javascript 以从页面中提取资源的函数。 Stackoverflow 似乎通过这种拆分来更好地格式化。

    
    private static func buildResourceInfoJavascript() -> String {
        let script = """
    
    function extractUrls( fromCss ) {
        let matches = fromCss.match(/url\\(.+?\\)/g);
        if( !matches ) {
            return [] ;
        }
        let urls = matches.map(url => url.replace(/url\\(['\\"]?(.+?)['\\"]?\\)/g, "$1"));
        return urls;
    }
    
    function getPageResources() {
        let pageResources = [...document.images].map(x => x.src);
        pageResources = [...pageResources, ...[...document.scripts].map(x => x.src) ] ;
        pageResources = [...pageResources, ...[...document.getElementsByTagName("link")].map(x => x.href) ];
    
        [...document.styleSheets].forEach(sheet => {
            if( !sheet.cssRules ) {
                return ;
            }
            [...sheet.cssRules].forEach(rule => {
                 pageResources = [...pageResources, ...extractUrls( rule.cssText )];
            } );
        });
    
        let inlineStyles = document.querySelectorAll( '*[style]') ;
        [...inlineStyles].forEach(x => {
            pageResources = [...pageResources, ...extractUrls( x.getAttributeNode("style").value )];
        }) ;
    
        let backgrounds = document.querySelectorAll( 'td[background], tr[background], table[background]') ;
        [...backgrounds].forEach(x => {
            pageResources.push( x.getAttributeNode("background").value );
        }) ;
    
        return pageResources.filter(x => (x != null && x != '') );
    }
    
    let pageResources = getPageResources() ;
    let loadedResources = window.performance.getEntriesByType('resource').map(x => x.name );
    
    let resourceInfo = {
        'pageResources' : pageResources,
        'loadedResources' : loadedResources.filter(x => (x != null && x != '') ),
    };
    JSON.stringify(resourceInfo);
    """
    
        return script 
    }
    

    下一部分是从 didFinishNavigation 委托调用的函数。

    
    public static func getBlockedResourcesAsync( fromWebView:WKWebView, completion:@escaping (([String]) -> Void)) {
        
           let script = buildResourceInfoJavascript()
           fromWebView.evaluateJavaScript(script) { (results, error) in
    
            guard let resultsData = (results as? String)?.data(using: .utf8) else {
                NSLog("No results for getBlockedResources" )
                completion( [] )
                return
            }
            do {
                let resourceInfo = try JSONSerialization.jsonObject(with: resultsData) as? [String:[String]] ?? [:]
                let pageResources = Array(Set(resourceInfo["pageResources"] ?? []) )
                let loadedResources = Array(Set( resourceInfo["loadedResources"] ?? []) )
                let blockedResources = pageResources.filter { !loadedResources.contains($0) }
                let unrecognizedResources = loadedResources.filter { !pageResources.contains($0) }
                if unrecognizedResources.count > 0 {
                    NSLog("Didn't recognized resources \(unrecognizedResources)" )
                }
                completion( blockedResources )
            }
            catch let err {
                NSLog("JSON decoding failed: \(err.localizedDescription)" )
                    completion([])
                    return
            }
        }
    }
    
    

    【讨论】:

      【解决方案2】:

      您的意思是要获取列表中的所有规则还是要查找规则列表?然后你可以使用下面的 WKContentRuleListStore https://developer.apple.com/documentation/webkit/wkcontentruleliststore的api

      // Gets the identifiers for all rules lists in the store.
      func getAvailableContentRuleListIdentifiers((([String]?) -> Void)!)
      
      // Searches for a specific rules list in the store.
      func lookUpContentRuleList(forIdentifier: String!, completionHandler: 
         ((WKContentRuleList?, Error?) -> Void)!)
      

      如果您需要更多详细信息,也可以参考以下问题的答案: block ads from url loaded in WKWebView

      更新:如果有任何帮助,请检查此线程 How to show the inspector within your WKWebView based desktop app?

      【讨论】:

      • 就我而言,两者都不是。我正在查找因与列表中的规则匹配而被阻止加载的资源。
      • 同@RichWaters 我想知道由于我提供的内容规则列表,哪些资源被阻止了。
      • 如果有任何帮助,请检查此线程:stackoverflow.com/questions/25200116/…
      【解决方案3】:

      您可以使用 WebKit SDK 做到这一点。 使用 WKScriptMessageHandler : https://developer.apple.com/documentation/webkit/wkscriptmessagehandler/1396222-usercontentcontroller

      您可以在开源项目 iOS 浏览器 DuckDuckGo 中找到该技术的示例: https://github.com/duckduckgo/iOS

      看看这个文件: https://github.com/duckduckgo/iOS/blob/develop/Core/ContentBlockerRulesUserScript.swift

      【讨论】:

        猜你喜欢
        • 2018-08-09
        • 1970-01-01
        • 1970-01-01
        • 2019-12-07
        • 2020-12-13
        • 2014-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多