本文是通过WKURLSchemeHandler
的方式实现的请求拦截,WKWebView
的WKURLSchemeHandler
是不支持拦截http/https/file
等原始协议的,如果通过[config setURLSchemeHandler:handler forURLScheme:@"http"];
就会闪退,但是支持自定义协议,但是有时候项目就是需要拦截这些请求,该怎么处理呢?
一、自定义一个HFURLSchemeHandler
类,并实现WKURLSchemeHandler
代理
1、HFURLSchemeHandler.h文件实现,遵循<WKURLSchemeHandler>
代理
#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
@interface HFURLSchemeHandler : NSObject <WKURLSchemeHandler>
@end
2、HFURLSchemeHandler.m文件实现两个代理方法- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
和- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id<WKURLSchemeTask>)urlSchemeTask
#import "HFURLSchemeHandler.h"
@implementation HFURLSchemeHandler
- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask{
NSURLRequest *request = urlSchemeTask.request;
NSString *urlStr = request.URL.absoluteString;
if ([urlStr hasPrefix:@"file://"]) {
// scheme切换回本地文件协议file://
NSURLRequest *fileUrlRequest = [[NSURLRequest alloc] initWithURL:request.URL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:0];
// 异步加载本地资源
NSURLSession *session = [NSURLSession sharedSession];
// 请求加载任务
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:fileUrlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
[urlSchemeTask didFailWithError:error];
} else {
NSDictionary *headerFields = @{
@"Content-Type":[NSString stringNullDealWith:response.MIMEType],
@"Content-Length":[NSString stringWithFormat:@"%ld", data.length]
};
response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:headerFields];
// 将数据回传给webView
[urlSchemeTask didReceiveResponse:response];
[urlSchemeTask didReceiveData:data];
[urlSchemeTask didFinish];
}
}];
[dataTask resume];
}
}
- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id<WKURLSchemeTask>)urlSchemeTask {
NSLog(@"stop = %@",urlSchemeTask);
[urlSchemeTask didFinish];
}
二、在WKWebView中配置需要拦截的协议名称
如果setURLSchemeHandler: forURLScheme:
中的URLScheme
设置的是http/https/file
,会出现崩溃,但是可设置自定义的URLScheme
,例如:@"Customer"
;如果要实现对http/https/file
的拦截,请查看第三步。
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
// 配置请求拦截(根据协议拦截)
HFURLSchemeHandler *handler = [HFURLSchemeHandler new];
[config setURLSchemeHandler:handler forURLScheme:@"file"];
三、配置允许拦截http/https/file
实现这个需求,则需要借助runtime
的知识,方法替换method_exchangeImplementations
,将WKWebView
中的handlesURLScheme
方法替换成自定义的方法。
给WKWebView增加一个分类,取名为WKWebView+SchemeHandle
。
1、WKWebView+SchemeHandle.h
#import <WebKit/WebKit.h>
@interface WKWebView (SchemeHandle)
@end
2、WKWebView+SchemeHandle.m 重写+ (void)load
方法进行方法替换
#import "WKWebView+SchemeHandle.h"
#import <objc/runtime.h>
@implementation WKWebView (SchemeHandle)
+ (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"] || [urlScheme isEqualToString:@"file"]) {
return NO; //这里让返回NO,应该是默认不走系统断言或者其他判断啥的
} else {
return [self yyhandlesURLScheme:urlScheme];
}
}
@end
至此,就可以实现WKWebView的请求拦截了。