我在webView中加载url,现在我想在webView中阻止来自url的广告。我怎样才能做到这一点?
[_webVw loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:page_url]]];
答案 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检查器的“网络”标签) )从中提取广告材料的所有域。一旦您意识到现在在典型的网站上仅包含了多少广告材料,这便是一个令人振奋的过程,甚至令人感到沮丧。
请仔细阅读以下内容:
这是一个示例,其中包括一些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文档,以便您了解限制,错误处理要求等。上面的示例只是为了使您入门而已,但是从完全了解您正在做的事情的角度编写真实代码很重要-您的应用程序用户应享有稳定的体验:-)