利用NSURLProtocol拦截WKWebView的请求
我们知道 ,ios 8.0以后,apple给出了一个WKWebView来替换 UIWebView,前者比后者在加载速度方面优化了很多,但是也有不少坑点,比如在拦截wkwebView的请求上,apple始终没有给出明确的API供开发者使用,正常情况下,我们自定义一个NSURLProtocol类,然后在AppDelegate里面register一波,就可以拦截到app内部所有的网络请求,但是你会发现,wkwebView并不吃这一套,what the fuck!,这一点在网上有人说wkwebView的请求是在单独的进程里面,为了性能方面的考虑,所以不走NSURLProtocol,但是通过打断点会发现,它会走一下+ (BOOL)canInitWithRequest:(NSURLRequest *)request
,然而这就尴尬了,为啥他会走一下,然后就一直不走了呢?于是我开始去研究了一波技术讨论,请教了一些大牛,找到了解决方案:写一个单独的NSURLProtocol类的分类方法,这里要提醒一下:由于这是私有方法,可能导致上线被拒!!!
.h文件:
+ (void)wk_registerScheme:(NSString*)scheme;
+ (void)wk_unregisterScheme:(NSString*)scheme;
.m文件:
FOUNDATION_STATIC_INLINE Class ContextControllerClass() {
static Class cls;
if (!cls) {
cls = [[[WKWebView new] valueForKey:@"browsingContextController"] class];
}
return cls;
}
FOUNDATION_STATIC_INLINE SEL RegisterSchemeSelector() {
return NSSelectorFromString(@"registerSchemeForCustomProtocol:");
}
FOUNDATION_STATIC_INLINE SEL UnregisterSchemeSelector() {
return NSSelectorFromString(@"unregisterSchemeForCustomProtocol:");
}
@implementation NSURLProtocol (WebKitSupport)
+ (void)wk_registerScheme:(NSString *)scheme {
Class cls = ContextControllerClass();
SEL sel = RegisterSchemeSelector();
if ([(id)cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id)cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
}
}
+ (void)wk_unregisterScheme:(NSString *)scheme {
Class cls = ContextControllerClass();
SEL sel = UnregisterSchemeSelector();
if ([(id)cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id)cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
}
}
然后在AppDelegate里面去注册一波scheme,一般是注册http和https,然后打一波断点你就会发现,可以拦截了,可以为所欲为了,一般对wkwebView的拦截的原因一般是要加一些特定的请求头或者拦截广告(接触的项目里面是这样干的)
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
在这里进行过滤判断,
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
这里面可以拿到被拦截的请求,可以在这里面对这个request进行二次处理,然后在startLoading方法里面自己进行自定义的处理!
网友评论