Как узнать, что заблокировано WKContentRuleList - PullRequest
2 голосов
/ 14 июля 2020

Как мы знаем, мы можем использовать WKContentRuleList для блокировки запросов URL / файлов cookie или выполнения других действий в WKWebView. Есть ли способ узнать, что было заблокировано WKWebView на основе этого WKContentRuleList?

Ответы [ 2 ]

0 голосов
/ 08 августа 2020

У меня есть некоторый уровень уверенности, что не существует простого способа просто получить эту информацию с помощью API c publi. Таким образом, я собрал обходной путь 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
        }
    }
}

0 голосов
/ 02 августа 2020

Вы имеете в виду, что хотите получить все правила в списке или хотите просмотреть список правил? Затем вы можете использовать приведенный ниже api WKContentRuleListStore https://developer.apple.com/documentation/webkit/wkcontentruleliststore

// 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)!)

Вы также можете обратиться к ответу на вопрос ниже, если вам требуются дополнительные сведения: заблокировать рекламу с загруженного URL-адреса в WKWebView

ОБНОВЛЕНИЕ : проверьте эту ветку, если она поможет Как показать инспектор в вашем настольном приложении на основе WKWebView?

...