阻止来自WKWebView中加载的网址的广告

时间:2018-05-24 09:10:47

标签: objective-c xcode wkwebview nsurlrequest adblock

我在webView中加载url,现在我想在webView中阻止来自url的广告。我怎样才能做到这一点?

[_webVw loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:page_url]]];

2 个答案:

答案 0 :(得分:3)

您需要使用 UIWebViewDelegate 中的 webView:shouldStartLoadWithRequest:navigationType:方法,并使用要阻止的黑名单列表进行验证。如果您需要灵感或类似的过程,您可以看到此库Ad Blocker iOS

---编辑---

这是我从NSString广告阻止WKWebView的代码。

//
//  ViewController.m
//  WKWebView
//
//  Created by Carlos Landaverde on 6/21/18.
//

#import "ViewController.h"

#define NSStringMultiline(...) [[NSString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]

static NSString *rexKey1 = @"rexKey1";

@interface ViewController () <WKNavigationDelegate, WKUIDelegate>
@property (nonatomic) WKWebView *webView;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.view setBackgroundColor: [UIColor whiteColor]];

    dispatch_group_t dispatchGroup = dispatch_group_create();
    __weak typeof(self) weakSelf = self;

    [NSUserDefaults.standardUserDefaults registerDefaults: @{ rexKey1: @NO }];
    [NSUserDefaults.standardUserDefaults synchronize];

    _webView = [[WKWebView alloc] initWithFrame: self.view.bounds];
    [_webView setNavigationDelegate: self];
    [_webView setUIDelegate: self];
    [_webView setAllowsBackForwardNavigationGestures: YES];
    [self.view addSubview: _webView];

    // If you want to remove previous WKContentRuleList
    // [_webView.configuration.userContentController removeAllContentRuleLists];

    dispatch_group_enter(dispatchGroup);
    [self setupContentBlockFromStringLiteral: ^{
        dispatch_group_leave(dispatchGroup);
    }];

    dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
        [weakSelf beginLoading];
    });
}

- (void)beginLoading
{
    NSURLRequest *urlReq = [[NSURLRequest alloc] initWithURL: [NSURL URLWithString: @"https://www.google.com"]];
    [_webView loadRequest: urlReq];
}

- (void)setupContentBlockFromStringLiteral: (void (^)(void))callback
{
    /*
     Or you can block from a JSON file
     */
    NSString *jsonStr = NSStringMultiline([{
        "trigger": {
            "url-filter": "://googleads\\\\.g\\\\.doubleclick\\\\.net.*"
        },
        "action": {
            "type": "block"
        }
    }]);

    if ([[NSUserDefaults.standardUserDefaults objectForKey: rexKey1] boolValue]) {
        [WKContentRuleListStore.defaultStore compileContentRuleListForIdentifier: rexKey1 encodedContentRuleList: jsonStr completionHandler: ^(WKContentRuleList *contentRuleList, NSError *err) {

            if (err != nil) {
                NSLog(@"Error on content rule list compiled");
                [NSUserDefaults.standardUserDefaults setObject: @NO forKey: rexKey1];
                return;
            }

            if (contentRuleList) {
                [_webView.configuration.userContentController addContentRuleList: contentRuleList];
                callback();
            }
        }];
    }
    else {
        [WKContentRuleListStore.defaultStore compileContentRuleListForIdentifier: rexKey1 encodedContentRuleList: jsonStr completionHandler: ^(WKContentRuleList *contentRuleList, NSError *err) {

            if (err != nil) {
                NSLog(@"Error on content rule list not compiled");
            }

            if (contentRuleList) {
                [_webView.configuration.userContentController addContentRuleList: contentRuleList];
                [NSUserDefaults.standardUserDefaults setObject: @YES forKey: rexKey1];
                callback();
            }
        }];
    }
}

@end

答案 1 :(得分:1)

假设您不介意将广告投放到iOS 10或更早版本,则iOS 11和更高版本包含内容阻止规则。

概述

假设我有一个UIViewController子类,它有一个指向我的webView实例的WKWebView属性。我实现了一个名为goHome的自定义方法,该方法访问一些已定义的“主页” URL。但是,在执行此操作之前,我可能想将内容阻止规则加载到Web视图中。我从这样的事情开始:

- ( void ) viewDidLoad
{
    [ super viewDidLoad ];

    // (other setup stuff here...)

    [ self reloadContentBlockingRulesAndGoHome ];
}

如果我在iOS 11或更高版本上,“重新加载阻止规则”内容将加载规则。如果您需要其他版本的iOS支持,请参阅其他答案。原谅这里的空白布局怪异之处,当我涉及在参数中包含块的Objective C消息时,我有一种古怪的编码风格:

- ( void ) reloadContentBlockingRulesAndGoHome
{
    if ( @available( iOS 11, * ) )
    {
        [
            WKContentRuleListStore.defaultStore
                compileContentRuleListForIdentifier: @"ContentBlockingRules"
                             encodedContentRuleList: @"...see below!..."
                                  completionHandler: ^ ( WKContentRuleList * ruleList, NSError * error )
            {
                [ super viewDidLoad ];

                if ( error == nil )
                {
                    [ self.webView.configuration.userContentController addContentRuleList: ruleList ];
                    [ self goHome ];
                }
            }
        ];
    }
    else
    {
        [ self goHome ];
    }
}

encodedContentRuleList参数采用JSON字符串。为了清楚起见,我倾向于将其放在自己的方法中,因此上面的代码实际上可能会说:

[ WKContentRuleListStore.defaultStore
     compileContentRuleListForIdentifier: @"ContentBlockingRules"
                  encodedContentRuleList: [ self contentBlockingRules ]
                       completionHandler: ^ ( WKContentRuleList * ruleList, NSError * error ) { ... } ];

那么[ self contentBlockingRules ]会做什么?那只是返回一个NSString提供内容阻止数据。无需与某种第三方广告块服务集成,您所要做的就是检查感兴趣的各个页面,并开始注意到包含广告的HTML元素的常见类名或ID,以及通知(例如,来自Safari Web检查器的“网络”标签) )从中提取广告材料的所有域。一旦您意识到现在在典型的网站上仅包含了多少广告材料,这便是一个令人振奋的过程,甚至令人感到沮丧。

规则JSON示例

请仔细阅读以下内容:

这是一个示例,其中包括一些CSS选择器阻止内容,阻止服务器本身的特定URL(例如,它们可能自己提供的一些自定义广告代码),以及一些要阻止的通用第三方域的规则(我使用这些很多)。

- ( NSString * ) contentBlockingRules
{
    return @" \
    [ \
      { \
        \"trigger\": { \
          \"url-filter\": \".*\" \
        }, \
        \"action\": { \
          \"type\": \"css-display-none\", \
          \"selector\": \".some_css_class, .some_other_class, #some_css_id\" \
        } \
      }, \
      { \
        \"trigger\": { \
          \"url-filter\": \"\\/some\\/very-specific-filename\\\\.js\", \
          \"resource-type\": [ \"script\" ] \
        }, \
        \"url-filter-is-case-sensitive\": true, \
        \"action\": { \
          \"type\": \"block\" \
        } \
      }, \
      { \
        \"trigger\": { \
          \"url-filter\": \".*\", \
          \"if-domain\": [ \"doubleclick.net\", \"adservice.google.com\", \"etc\" ], \
          \"resource-type\": [ \"script\" ] \
        }, \
        \"action\": { \
          \"type\": \"block\" \
        } \
      } \
    ]";
}

采用JSON并将其编码为NSString真是令人讨厌-如您所见,进行大量转义的结果非常混乱,尤其是对于某些URL部分,这些部分对于JSON进行过一次转义,然后针对NSString文字。可能有更清洁的方法可以使JSON数据的维护更加容易。

最终想法

由于许多网站上广告和跟踪代码的数量巨大,因此当您阻止内容时,页面加载速度的差异会很大。值得努力为您的用户提供更好的体验,并减少他们的移动数据,但是:

  • 您可能违反了所访问网站上的服务条款和条件
  • 如果网站更新了代码,那么您可能最终会丢失一些您打算阻止的广告
  • 网站更新或过于笼统的阻止规则可能会意外地隐藏“合法”非广告页面内容。

而不是仅复制并粘贴上面的任何内容,而是请仔细阅读有关上述各种技术和框架方法的Apple Developer文档,以便您了解限制,错误处理要求等。上面的示例只是为了使您入门而已,但是从完全了解您正在做的事情的角度编写真实代码很重要-您的应用程序用户应享有稳定的体验:-)