iOS11开始 WebKit支持拦截url 有两种方案可实现
1 WKContentRuleListStore规则声明
1.1 原理
给WebView提供一个json数据,用来声明规则,告诉webview拦截哪些url,执行怎样的操作,这个json包含两个字段 trigger 和 actio
1.1.1 trigger
trigger字段声明要拦截哪些的url,trigger对应的value也是一个字典,其中url-filter字段是必须的,匹配url的正则表达式,比如匹配所有以gif结尾的url则可以这么写 @"trigger": @{@"url-filter": @".*(.gif)$" }。
1.1.2 action
action字段声明当匹配到对应的url请求时执行哪些操作,其中有个必须的字段 type,表示操作类型 。
block:放弃加载,同时忽略缓存
block-cookies:请求忽略cookie
css-display-none:隐藏关联指定select的css元素,所以当type值设定为css-display-none时,必须同时存在一个字段selector, 什么意思呢,比如网页上有个标签绑定了一个方法 func play(),那就可以在设置type为css-display-none的同时,通过selector:play 来表示 隐藏绑定了play方法的标签
1.2 具体代码
比如使用json声明不请求所以gif结尾url
#pragma mark - 屏蔽GIF
- (void)shieldGif
{
NSArray *json = @[@{@"trigger": @{@"url-filter": @".*(.gif)$" },
@"action": @{@"type": @"block"}}];
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[[WKContentRuleListStore defaultStore] compileContentRuleListForIdentifier: @"demoRuleList" encodedContentRuleList:jsonStr completionHandler:^(WKContentRuleList *contentRuleList, NSError *error) {
if (error) return;
[self.webView.configuration.userContentController addContentRuleList:contentRuleList];
}];
}
2 WKWebViewConfiguration Scheme配置
2.1 原理
在创建webview的时候传入一个WKWebViewConfiguration对象,这个对象可以描述哪些scheme的请求要自行处理,当符合这个scheme的请求时会触发代理方法,那么在代理方法中可以自行操作。
2.2 代码实现
比如要监听http、https的请求时可以按以下代码创建webview
WKWebViewConfiguration *configuration = [WKWebViewConfiguration new];
//支持https和http的方法1 这个需要去hook +[WKwebview handlesURLScheme]的方法,可以去看WKWebView+Custome类的实现
[configuration setURLSchemeHandler:self forURLScheme:@"https"];
[configuration setURLSchemeHandler:self forURLScheme:@"http"];
_webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
#pragma mark - 网络请求拦截代理方法
- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask{
NSURLRequest *request = urlSchemeTask.request;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if ([request.URL.absoluteString.pathExtension isEqualToString:@"gif"]) {
[urlSchemeTask didReceiveResponse:[NSURLResponse new]];
[urlSchemeTask didReceiveData:[NSData data]];
} else {
[urlSchemeTask didReceiveResponse:response];
[urlSchemeTask didReceiveData:data];
}
[urlSchemeTask didFinish];
}];
[task resume];
}
- (void)webView:(nonnull WKWebView *)webView stopURLSchemeTask:(nonnull id<WKURLSchemeTask>)urlSchemeTask {
[urlSchemeTask didFinish];
}
2.3 会遇到的问题
但是运行起来发现会报一个错
Terminating app due to uncaught exception 'NSInvalidArgumentException' reason: 'http' is a URL scheme that WKWebView handles natively
意思是说WKWebview默认支持http的请求,所以处理这个崩溃的就是让系统认为webview是不支持http和https的请求,具体实现可以使用runtime方法替换,给WKWebview创建一个分类
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method originalMethod1 = class_getClassMethod(self, @selector(handlesURLScheme:));
Method swizzledMethod1 = class_getClassMethod(self, @selector(yyhandlesURLScheme:));
method_exchangeImplementations(originalMethod1, swizzledMethod1);
});
}
+ (BOOL)yyhandlesURLScheme:(NSString *)urlScheme {
if ([urlScheme isEqualToString:@"http"] || [urlScheme isEqualToString:@"https"]) {
return NO; //这里让返回NO,应该是默认不走系统断言或者其他判断啥的
} else {
return [self yyhandlesURLScheme:urlScheme];
}
}